diff --git a/__mocks__/reportData/violations.ts b/__mocks__/reportData/violations.ts index f1fce6ed8021..b7982210591a 100644 --- a/__mocks__/reportData/violations.ts +++ b/__mocks__/reportData/violations.ts @@ -31,6 +31,7 @@ const receiptErrorsR14932: ReceiptErrors = { retryParams: { transactionID: RECEIPT_ERRORS_TRANSACTION_ID_R14932, source: CONST.POLICY.ID_FAKE, + transactionPolicy: undefined, }, }, }; diff --git a/src/components/MoneyReportHeader.tsx b/src/components/MoneyReportHeader.tsx index 3d0cb8c07911..495581196e20 100644 --- a/src/components/MoneyReportHeader.tsx +++ b/src/components/MoneyReportHeader.tsx @@ -1,6 +1,6 @@ import {useRoute} from '@react-navigation/native'; import {isUserValidatedSelector} from '@selectors/Account'; -import getArchiveReason from '@selectors/Report'; +import {getArchiveReason} from '@selectors/Report'; import React, {useCallback, useContext, useEffect, useMemo, useRef, useState} from 'react'; import {InteractionManager, View} from 'react-native'; import type {OnyxEntry} from 'react-native-onyx'; diff --git a/src/components/TestDrive/Modal/EmployeeTestDriveModal.tsx b/src/components/TestDrive/Modal/EmployeeTestDriveModal.tsx index 91990a5dd2f1..261a3e35dbe0 100644 --- a/src/components/TestDrive/Modal/EmployeeTestDriveModal.tsx +++ b/src/components/TestDrive/Modal/EmployeeTestDriveModal.tsx @@ -1,7 +1,7 @@ import {useRoute} from '@react-navigation/native'; import {format} from 'date-fns'; import {Str} from 'expensify-common'; -import React, {useCallback, useState} from 'react'; +import React, {useCallback, useMemo, useState} from 'react'; import {InteractionManager} from 'react-native'; import TestReceipt from '@assets/images/fake-test-drive-employee-receipt.jpg'; import TextInput from '@components/TextInput'; @@ -25,6 +25,7 @@ import Log from '@libs/Log'; import Navigation from '@libs/Navigation/Navigation'; import type {PlatformStackRouteProp} from '@libs/Navigation/PlatformStackNavigation/types'; import type {TestDriveModalNavigatorParamList} from '@libs/Navigation/types'; +import {hasOnlyPersonalPolicies as hasOnlyPersonalPoliciesUtil} from '@libs/PolicyUtils'; import {generateReportID} from '@libs/ReportUtils'; import {generateAccountID} from '@libs/UserUtils'; import CONST from '@src/CONST'; @@ -45,6 +46,8 @@ function EmployeeTestDriveModal() { const [isLoading, setIsLoading] = useState(false); const {testDrive} = useOnboardingMessages(); const currentUserPersonalDetails = useCurrentUserPersonalDetails(); + const [allPolicies] = useOnyx(ONYXKEYS.COLLECTION.POLICY, {canBeMissing: true}); + const hasOnlyPersonalPolicies = useMemo(() => hasOnlyPersonalPoliciesUtil(allPolicies), [allPolicies]); const onBossEmailChange = useCallback((value: string) => { setBossEmail(value); @@ -78,6 +81,7 @@ function EmployeeTestDriveModal() { parentReport, currentDate, currentUserPersonalDetails, + hasOnlyPersonalPolicies, }); setMoneyRequestReceipt(transactionID, source, filename, true, CONST.TEST_RECEIPT.FILE_TYPE, false, true); diff --git a/src/libs/actions/IOU.ts b/src/libs/actions/IOU.ts index 04dd4622f003..5fb0c553de3b 100644 --- a/src/libs/actions/IOU.ts +++ b/src/libs/actions/IOU.ts @@ -90,7 +90,6 @@ import { getPolicy, getSubmitToAccountID, hasDependentTags, - hasOnlyPersonalPolicies, isControlPolicy, isDelayedSubmissionEnabled, isPaidGroupPolicy, @@ -299,6 +298,7 @@ type InitMoneyRequestParams = { currentDate: string | undefined; lastSelectedDistanceRates?: OnyxEntry; currentUserPersonalDetails: CurrentUserPersonalDetails; + hasOnlyPersonalPolicies: boolean; }; type MoneyRequestInformation = { @@ -354,6 +354,7 @@ type TrackedExpenseTransactionParams = Omit; policyID: string | undefined; isDraftPolicy?: boolean; }; @@ -787,6 +788,7 @@ type ReplaceReceipt = { file?: File; source: string; transactionPolicyCategories?: OnyxEntry; + transactionPolicy: OnyxEntry; }; type GetSearchOnyxUpdateParams = { @@ -874,22 +876,6 @@ Onyx.connect({ }, }); -const allPolicies: OnyxCollection = {}; -Onyx.connect({ - key: ONYXKEYS.COLLECTION.POLICY, - callback: (val, key) => { - if (!key) { - return; - } - if (val === null || val === undefined) { - delete allPolicies[key]; - return; - } - - allPolicies[key] = val; - }, -}); - // TODO: remove `allRecentlyUsedTags` from this file (https://github.com/Expensify/App/issues/71491) // `allRecentlyUsedTags` was moved here temporarily from `src/libs/actions/Policy/Tag.ts` during the `Deprecate Onyx.connect` refactor. // All uses of this variable should be replaced with `useOnyx`. @@ -1054,6 +1040,7 @@ function initMoneyRequest({ currentDate = '', lastSelectedDistanceRates, currentUserPersonalDetails, + hasOnlyPersonalPolicies, }: InitMoneyRequestParams) { // Generate a brand new transactionID // This will be fixed as part of https://github.com/Expensify/Expensify/issues/507850 @@ -1094,7 +1081,7 @@ function initMoneyRequest({ const isPolicyExpenseChat = isPolicyExpenseChatReportUtil(report) || isPolicyExpenseChatReportUtil(parentReport); const customUnitRateID = DistanceRequestUtils.getCustomUnitRateID({reportID, isPolicyExpenseChat, policy, lastSelectedDistanceRates}); comment.customUnit = {customUnitRateID}; - } else if (hasOnlyPersonalPolicies(allPolicies)) { + } else if (hasOnlyPersonalPolicies) { comment.customUnit = {customUnitRateID: CONST.CUSTOM_UNITS.FAKE_P2P_ID}; } if (comment.customUnit) { @@ -6066,7 +6053,7 @@ function shareTrackedExpense(trackedExpenseParams: TrackedExpenseParams) { successData?.push(...shareTrackedExpenseSuccessData); failureData?.push(...shareTrackedExpenseFailureData); - const policyEmployeeList = allPolicies?.[`${ONYXKEYS.COLLECTION.POLICY}${policyParams?.policyID}`]?.employeeList; + const policyEmployeeList = policyParams?.policy?.employeeList; if (!policyEmployeeList?.[accountantEmail]) { const policyMemberAccountIDs = Object.values(getMemberAccountIDsForWorkspace(policyEmployeeList, false, false)); const { @@ -6754,6 +6741,7 @@ function trackExpense(params: CreateTrackExpenseParams) { }; const policyParams: TrackedExpensePolicyParams = { policyID: chatReport?.policyID, + policy, isDraftPolicy, }; const reportInformation: TrackedExpenseReportInformation = { @@ -6804,6 +6792,7 @@ function trackExpense(params: CreateTrackExpenseParams) { }; const policyParams: TrackedExpensePolicyParams = { policyID: chatReport?.policyID, + policy, }; const reportInformation: TrackedExpenseReportInformation = { moneyRequestPreviewReportActionID: iouAction?.reportActionID, @@ -11898,13 +11887,12 @@ function payInvoice( API.write(WRITE_COMMANDS.PAY_INVOICE, params, {optimisticData, successData, failureData}); } -function detachReceipt(transactionID: string | undefined, transactionPolicyCategories?: OnyxEntry) { +function detachReceipt(transactionID: string | undefined, transactionPolicy: OnyxEntry, transactionPolicyCategories?: OnyxEntry) { if (!transactionID) { return; } const transaction = allTransactions[`${ONYXKEYS.COLLECTION.TRANSACTION}${transactionID}`]; const expenseReport = allReports?.[`${ONYXKEYS.COLLECTION.REPORT}${transaction?.reportID}`] ?? null; - const policy = allPolicies?.[`${ONYXKEYS.COLLECTION.POLICY}${expenseReport?.policyID}`]; const newTransaction = transaction ? { ...transaction, @@ -11950,16 +11938,16 @@ function detachReceipt(transactionID: string | undefined, transactionPolicyCateg }, ]; - if (policy && isPaidGroupPolicy(policy) && newTransaction) { - const policyTagList = getPolicyTagsData(policy.id); + if (transactionPolicy && isPaidGroupPolicy(transactionPolicy) && newTransaction) { + const policyTagList = getPolicyTagsData(transactionPolicy.id); const currentTransactionViolations = allTransactionViolations[`${ONYXKEYS.COLLECTION.TRANSACTION_VIOLATIONS}${transactionID}`] ?? []; const violationsOnyxData = ViolationsUtils.getViolationsOnyxData( newTransaction, currentTransactionViolations, - policy, + transactionPolicy, policyTagList ?? {}, transactionPolicyCategories ?? {}, - hasDependentTags(policy, policyTagList ?? {}), + hasDependentTags(transactionPolicy, policyTagList ?? {}), isInvoiceReportReportUtils(expenseReport), ); optimisticData.push(violationsOnyxData); @@ -12018,14 +12006,13 @@ function detachReceipt(transactionID: string | undefined, transactionPolicyCateg API.write(WRITE_COMMANDS.DETACH_RECEIPT, parameters, {optimisticData, successData, failureData}); } -function replaceReceipt({transactionID, file, source, transactionPolicyCategories}: ReplaceReceipt) { +function replaceReceipt({transactionID, file, source, transactionPolicy, transactionPolicyCategories}: ReplaceReceipt) { if (!file) { return; } const transaction = allTransactions[`${ONYXKEYS.COLLECTION.TRANSACTION}${transactionID}`]; const expenseReport = allReports?.[`${ONYXKEYS.COLLECTION.REPORT}${transaction?.reportID}`] ?? null; - const policy = allPolicies?.[`${ONYXKEYS.COLLECTION.POLICY}${expenseReport?.policyID}`]; const oldReceipt = transaction?.receipt ?? {}; const receiptOptimistic = { source, @@ -12033,7 +12020,7 @@ function replaceReceipt({transactionID, file, source, transactionPolicyCategorie filename: file.name, }; const newTransaction = transaction && {...transaction, receipt: receiptOptimistic}; - const retryParams: ReplaceReceipt = {transactionID, file: undefined, source, transactionPolicyCategories}; + const retryParams: ReplaceReceipt = {transactionID, file: undefined, source, transactionPolicy, transactionPolicyCategories}; const currentSearchQueryJSON = getCurrentSearchQueryJSON(); const optimisticData: OnyxUpdate[] = [ @@ -12076,16 +12063,16 @@ function replaceReceipt({transactionID, file, source, transactionPolicyCategorie }, ]; - if (policy && isPaidGroupPolicy(policy) && newTransaction) { - const policyTagList = getPolicyTagsData(policy.id); + if (transactionPolicy && isPaidGroupPolicy(transactionPolicy) && newTransaction) { + const policyTagList = getPolicyTagsData(transactionPolicy.id); const currentTransactionViolations = allTransactionViolations[`${ONYXKEYS.COLLECTION.TRANSACTION_VIOLATIONS}${transactionID}`] ?? []; const violationsOnyxData = ViolationsUtils.getViolationsOnyxData( newTransaction, currentTransactionViolations, - policy, + transactionPolicy, policyTagList ?? {}, transactionPolicyCategories ?? {}, - hasDependentTags(policy, policyTagList ?? {}), + hasDependentTags(transactionPolicy, policyTagList ?? {}), isInvoiceReportReportUtils(expenseReport), ); optimisticData.push(violationsOnyxData); @@ -13307,6 +13294,7 @@ function prepareRejectMoneyRequestData( transactionID: string, reportID: string, comment: string, + policy: OnyxEntry, options?: {sharedRejectedToReportID?: string}, shouldUseBulkAction?: boolean, ): RejectMoneyRequestData | undefined { @@ -13314,7 +13302,6 @@ function prepareRejectMoneyRequestData( const transactionAmount = getAmount(transaction); const report = allReports?.[`${ONYXKEYS.COLLECTION.REPORT}${reportID}`]; const policyExpenseChat = allReports?.[`${ONYXKEYS.COLLECTION.REPORT}${report?.chatReportID}`]; - const policy = allPolicies?.[`${ONYXKEYS.COLLECTION.POLICY}${report?.policyID}`]; const isPolicyDelayedSubmissionEnabled = policy ? isDelayedSubmissionEnabled(policy) : false; const isIOU = isIOUReport(report); const searchFullScreenRoutes = navigationRef.getRootState()?.routes.findLast((route) => route.name === NAVIGATORS.SEARCH_FULLSCREEN_NAVIGATOR); @@ -14032,8 +14019,8 @@ function prepareRejectMoneyRequestData( return {optimisticData, successData, failureData, parameters, urlToNavigateBack: urlToNavigateBack as Route}; } -function rejectMoneyRequest(transactionID: string, reportID: string, comment: string, options?: {sharedRejectedToReportID?: string}): Route | undefined { - const data = prepareRejectMoneyRequestData(transactionID, reportID, comment, options); +function rejectMoneyRequest(transactionID: string, reportID: string, comment: string, policy: OnyxEntry, options?: {sharedRejectedToReportID?: string}): Route | undefined { + const data = prepareRejectMoneyRequestData(transactionID, reportID, comment, policy, options); if (!data) { return; } diff --git a/src/libs/actions/Search.ts b/src/libs/actions/Search.ts index c3d948364edc..d4dc3877d748 100644 --- a/src/libs/actions/Search.ts +++ b/src/libs/actions/Search.ts @@ -724,7 +724,7 @@ function deleteMoneyRequestOnSearch(hash: number, transactionIDList: string[]) { } } -function rejectMoneyRequestInBulk(hash: number, reportID: string, comment: string, transactionIDs: string[]) { +function rejectMoneyRequestInBulk(hash: number, reportID: string, comment: string, policy: OnyxEntry, transactionIDs: string[]) { const {optimisticData, finallyData} = getOnyxLoadingData(hash); const successData: OnyxUpdate[] = []; const failureData: OnyxUpdate[] = []; @@ -736,7 +736,7 @@ function rejectMoneyRequestInBulk(hash: number, reportID: string, comment: strin } > = {}; for (const transactionID of transactionIDs) { - const data = prepareRejectMoneyRequestData(transactionID, reportID, comment, undefined, true); + const data = prepareRejectMoneyRequestData(transactionID, reportID, comment, policy, undefined, true); if (data) { optimisticData.push(...data.optimisticData); successData.push(...data.successData); @@ -778,12 +778,12 @@ function rejectMoneyRequestsOnSearch(hash: number, selectedTransactions: Selecte const policy = allPolicies?.[`${ONYXKEYS.COLLECTION.POLICY}${report?.policyID}`]; const isPolicyDelayedSubmissionEnabled = policy ? isDelayedSubmissionEnabled(policy) : false; if (isPolicyDelayedSubmissionEnabled && areAllExpensesSelected) { - rejectMoneyRequestInBulk(hash, reportID, comment, allTransactionIDs); + rejectMoneyRequestInBulk(hash, reportID, comment, policy, allTransactionIDs); } else { // Share a single destination ID across all rejections from the same source report const sharedRejectedToReportID = generateReportID(); for (const transactionID of selectedTransactionIDs) { - rejectMoneyRequest(transactionID, reportID, comment, {sharedRejectedToReportID}); + rejectMoneyRequest(transactionID, reportID, comment, policy, {sharedRejectedToReportID}); } } } diff --git a/src/pages/Search/SearchPage.tsx b/src/pages/Search/SearchPage.tsx index 2816a83330b6..343ef2431121 100644 --- a/src/pages/Search/SearchPage.tsx +++ b/src/pages/Search/SearchPage.tsx @@ -58,7 +58,7 @@ import {navigateToParticipantPage} from '@libs/IOUUtils'; import Navigation from '@libs/Navigation/Navigation'; import type {PlatformStackScreenProps} from '@libs/Navigation/PlatformStackNavigation/types'; import type {SearchFullscreenNavigatorParamList} from '@libs/Navigation/types'; -import {getActiveAdminWorkspaces, hasDynamicExternalWorkflow, hasVBBA, isPaidGroupPolicy} from '@libs/PolicyUtils'; +import {getActiveAdminWorkspaces, hasDynamicExternalWorkflow, hasOnlyPersonalPolicies as hasOnlyPersonalPoliciesUtil, hasVBBA, isPaidGroupPolicy} from '@libs/PolicyUtils'; import { generateReportID, getPolicyExpenseChat, @@ -146,6 +146,7 @@ function SearchPage({route}: SearchPageProps) { const selectedTransactionReportIDs = useMemo(() => [...new Set(Object.values(selectedTransactions).map((transaction) => transaction.reportID))], [selectedTransactions]); const selectedReportIDs = Object.values(selectedReports).map((report) => report.reportID); const isCurrencySupportedBulkWallet = isCurrencySupportWalletBulkPay(selectedReports, selectedTransactions); + const hasOnlyPersonalPolicies = useMemo(() => hasOnlyPersonalPoliciesUtil(policies), [policies]); // Collate a list of policyIDs from the selected transactions const selectedPolicyIDs = useMemo( @@ -711,6 +712,7 @@ function SearchPage({route}: SearchPageProps) { parentReport: newParentReport, currentDate, currentUserPersonalDetails, + hasOnlyPersonalPolicies, }); const newReceiptFiles: ReceiptFile[] = []; diff --git a/src/pages/Share/SubmitDetailsPage.tsx b/src/pages/Share/SubmitDetailsPage.tsx index c0fdefff299d..ca885037a80a 100644 --- a/src/pages/Share/SubmitDetailsPage.tsx +++ b/src/pages/Share/SubmitDetailsPage.tsx @@ -24,6 +24,7 @@ import navigateAfterInteraction from '@libs/Navigation/navigateAfterInteraction' import Navigation from '@libs/Navigation/Navigation'; import type {ShareNavigatorParamList} from '@libs/Navigation/types'; import {getParticipantsOption, getReportOption} from '@libs/OptionsListUtils'; +import {hasOnlyPersonalPolicies as hasOnlyPersonalPoliciesUtil} from '@libs/PolicyUtils'; import {shouldValidateFile} from '@libs/ReceiptUtils'; import {getReportOrDraftReport, isSelfDM} from '@libs/ReportUtils'; import {getDefaultTaxCode} from '@libs/TransactionUtils'; @@ -73,6 +74,7 @@ function SubmitDetailsPage({ const fileUri = shouldUsePreValidatedFile ? (validFilesToUpload?.uri ?? '') : (currentAttachment?.content ?? ''); const fileName = shouldUsePreValidatedFile ? getFileName(validFilesToUpload?.uri ?? CONST.ATTACHMENT_IMAGE_DEFAULT_NAME) : getFileName(currentAttachment?.content ?? ''); const fileType = shouldUsePreValidatedFile ? (validFilesToUpload?.type ?? CONST.RECEIPT_ALLOWED_FILE_TYPES.JPEG) : (currentAttachment?.mimeType ?? ''); + const [hasOnlyPersonalPolicies = false] = useOnyx(ONYXKEYS.COLLECTION.POLICY, {canBeMissing: true, selector: hasOnlyPersonalPoliciesUtil}); useEffect(() => { if (!errorTitle || !errorMessage) { @@ -92,8 +94,9 @@ function SubmitDetailsPage({ parentReport, currentDate, currentUserPersonalDetails, + hasOnlyPersonalPolicies, }); - }, [reportOrAccountID, policy, report, parentReport, currentDate, currentUserPersonalDetails]); + }, [reportOrAccountID, policy, report, parentReport, currentDate, currentUserPersonalDetails, hasOnlyPersonalPolicies]); const selectedParticipants = unknownUserDetails ? [unknownUserDetails] : getMoneyRequestParticipantsFromReport(report, currentUserPersonalDetails.accountID); const participants = selectedParticipants.map((participant) => diff --git a/src/pages/home/report/ReportActionCompose/useAttachmentUploadValidation.ts b/src/pages/home/report/ReportActionCompose/useAttachmentUploadValidation.ts index 658ed0090781..f6355fe2eb07 100644 --- a/src/pages/home/report/ReportActionCompose/useAttachmentUploadValidation.ts +++ b/src/pages/home/report/ReportActionCompose/useAttachmentUploadValidation.ts @@ -1,9 +1,10 @@ -import {useCallback, useContext, useRef} from 'react'; +import {useCallback, useContext, useMemo, useRef} from 'react'; import type {OnyxEntry} from 'react-native-onyx'; import useFilesValidation from '@hooks/useFilesValidation'; import useLocalize from '@hooks/useLocalize'; import useOnyx from '@hooks/useOnyx'; import {cleanFileObject, cleanFileObjectName, getFilesFromClipboardEvent} from '@libs/fileDownload/FileUtils'; +import {hasOnlyPersonalPolicies as hasOnlyPersonalPoliciesUtil} from '@libs/PolicyUtils'; import {isSelfDM} from '@libs/ReportUtils'; import {shouldRestrictUserBillableActions} from '@libs/SubscriptionUtils'; import Navigation from '@navigation/Navigation'; @@ -51,6 +52,8 @@ function useAttachmentUploadValidation({ }: AttachmentUploadValidationProps) { const {translate} = useLocalize(); const [policyCategories] = useOnyx(`${ONYXKEYS.COLLECTION.POLICY_CATEGORIES}${policy?.id}`, {canBeMissing: true}); + const [allPolicies] = useOnyx(ONYXKEYS.COLLECTION.POLICY, {canBeMissing: true}); + const hasOnlyPersonalPolicies = useMemo(() => hasOnlyPersonalPoliciesUtil(allPolicies), [allPolicies]); const reportAttachmentsContext = useContext(AttachmentModalContext); const showAttachmentModalScreen = useCallback( @@ -83,7 +86,7 @@ function useAttachmentUploadValidation({ if (shouldAddOrReplaceReceipt && transactionID) { const source = URL.createObjectURL(files.at(0) as Blob); - replaceReceipt({transactionID, file: files.at(0) as File, source, transactionPolicyCategories: policyCategories}); + replaceReceipt({transactionID, file: files.at(0) as File, source, transactionPolicy: policy, transactionPolicyCategories: policyCategories}); return; } @@ -94,6 +97,7 @@ function useAttachmentUploadValidation({ parentReport: newParentReport, currentDate, currentUserPersonalDetails, + hasOnlyPersonalPolicies, }); for (const [index, file] of files.entries()) { diff --git a/src/pages/iou/RejectReasonPage.tsx b/src/pages/iou/RejectReasonPage.tsx index 86ee77363724..965d18018f3b 100644 --- a/src/pages/iou/RejectReasonPage.tsx +++ b/src/pages/iou/RejectReasonPage.tsx @@ -1,7 +1,11 @@ +import {getReportPolicyID} from '@selectors/Report'; import React, {useCallback, useEffect} from 'react'; import type {FormInputErrors, FormOnyxValues} from '@components/Form/types'; import {useSearchContext} from '@components/Search/SearchContext'; import useLocalize from '@hooks/useLocalize'; +import useOnyx from '@hooks/useOnyx'; +import usePolicy from '@hooks/usePolicy'; +import getNonEmptyStringOnyxID from '@libs/getNonEmptyStringOnyxID'; import Navigation from '@libs/Navigation/Navigation'; import type {PlatformStackScreenProps} from '@libs/Navigation/PlatformStackNavigation/types'; import type {MoneyRequestNavigatorParamList, SearchReportActionsParamList} from '@libs/Navigation/types'; @@ -22,9 +26,11 @@ function RejectReasonPage({route}: RejectReasonPageProps) { const {transactionID, reportID, backTo} = route.params; const {removeTransaction} = useSearchContext(); + const [reportPolicyID] = useOnyx(`${ONYXKEYS.COLLECTION.REPORT}${getNonEmptyStringOnyxID(reportID)}`, {canBeMissing: false, selector: getReportPolicyID}); + const policy = usePolicy(reportPolicyID); const onSubmit = (values: FormOnyxValues) => { - const urlToNavigateBack = rejectMoneyRequest(transactionID, reportID, values.comment); + const urlToNavigateBack = rejectMoneyRequest(transactionID, reportID, values.comment, policy); removeTransaction(transactionID); Navigation.dismissModal(); if (urlToNavigateBack) { diff --git a/src/pages/iou/request/DistanceRequestStartPage.tsx b/src/pages/iou/request/DistanceRequestStartPage.tsx index 8d8fbf39513b..7a1ce978b8b8 100644 --- a/src/pages/iou/request/DistanceRequestStartPage.tsx +++ b/src/pages/iou/request/DistanceRequestStartPage.tsx @@ -16,6 +16,7 @@ import getNonEmptyStringOnyxID from '@libs/getNonEmptyStringOnyxID'; import Navigation from '@libs/Navigation/Navigation'; import OnyxTabNavigator, {TabScreenWithFocusTrapWrapper, TopTab} from '@libs/Navigation/OnyxTabNavigator'; import Performance from '@libs/Performance'; +import {hasOnlyPersonalPolicies as hasOnlyPersonalPoliciesUtil} from '@libs/PolicyUtils'; import {getPayeeName} from '@libs/ReportUtils'; import {endSpan} from '@libs/telemetry/activeSpans'; import AccessOrNotFoundWrapper from '@pages/workspace/AccessOrNotFoundWrapper'; @@ -57,6 +58,7 @@ function DistanceRequestStartPage({ const [lastSelectedDistanceRates] = useOnyx(ONYXKEYS.NVP_LAST_SELECTED_DISTANCE_RATES, {canBeMissing: true}); const [currentDate] = useOnyx(ONYXKEYS.CURRENT_DATE, {canBeMissing: true}); + const hasOnlyPersonalPolicies = useMemo(() => hasOnlyPersonalPoliciesUtil(allPolicies), [allPolicies]); const currentUserPersonalDetails = useCurrentUserPersonalDetails(); const tabTitles = { @@ -108,6 +110,7 @@ function DistanceRequestStartPage({ currentDate, lastSelectedDistanceRates, currentUserPersonalDetails, + hasOnlyPersonalPolicies, }); // eslint-disable-next-line }, []); @@ -129,9 +132,21 @@ function DistanceRequestStartPage({ currentDate, lastSelectedDistanceRates, currentUserPersonalDetails, + hasOnlyPersonalPolicies, }); }, - [transaction?.iouRequestType, reportID, policy, isFromGlobalCreate, report, parentReport, currentDate, lastSelectedDistanceRates, currentUserPersonalDetails], + [ + transaction?.iouRequestType, + reportID, + policy, + isFromGlobalCreate, + report, + parentReport, + currentDate, + lastSelectedDistanceRates, + currentUserPersonalDetails, + hasOnlyPersonalPolicies, + ], ); // Clear out the temporary expense if the reportID in the URL has changed from the transaction's reportID. diff --git a/src/pages/iou/request/IOURequestStartPage.tsx b/src/pages/iou/request/IOURequestStartPage.tsx index 17592b879fc9..58c752bc91be 100644 --- a/src/pages/iou/request/IOURequestStartPage.tsx +++ b/src/pages/iou/request/IOURequestStartPage.tsx @@ -27,7 +27,7 @@ import Navigation from '@libs/Navigation/Navigation'; import OnyxTabNavigator, {TabScreenWithFocusTrapWrapper, TopTab} from '@libs/Navigation/OnyxTabNavigator'; import {getIsUserSubmittedExpenseOrScannedReceipt} from '@libs/OptionsListUtils'; import Performance from '@libs/Performance'; -import {getActivePoliciesWithExpenseChatAndPerDiemEnabledAndHasRates, getPerDiemCustomUnit} from '@libs/PolicyUtils'; +import {getActivePoliciesWithExpenseChatAndPerDiemEnabledAndHasRates, getPerDiemCustomUnit, hasOnlyPersonalPolicies as hasOnlyPersonalPoliciesUtil} from '@libs/PolicyUtils'; import {getPayeeName} from '@libs/ReportUtils'; import {endSpan} from '@libs/telemetry/activeSpans'; import AccessOrNotFoundWrapper from '@pages/workspace/AccessOrNotFoundWrapper'; @@ -83,6 +83,7 @@ function IOURequestStartPage({ const [currentDate] = useOnyx(ONYXKEYS.CURRENT_DATE, {canBeMissing: true}); const {isOffline} = useNetwork(); const [nvpDismissedProductTraining] = useOnyx(ONYXKEYS.NVP_DISMISSED_PRODUCT_TRAINING, {canBeMissing: true}); + const hasOnlyPersonalPolicies = useMemo(() => hasOnlyPersonalPoliciesUtil(allPolicies), [allPolicies]); const tabTitles = { [CONST.IOU.TYPE.REQUEST]: translate('iou.createExpense'), @@ -154,6 +155,7 @@ function IOURequestStartPage({ currentDate, lastSelectedDistanceRates, currentUserPersonalDetails, + hasOnlyPersonalPolicies, }); // eslint-disable-next-line }, []); @@ -176,6 +178,7 @@ function IOURequestStartPage({ currentDate, lastSelectedDistanceRates, currentUserPersonalDetails, + hasOnlyPersonalPolicies, }); }, [ @@ -189,6 +192,7 @@ function IOURequestStartPage({ currentDate, lastSelectedDistanceRates, currentUserPersonalDetails, + hasOnlyPersonalPolicies, ], ); diff --git a/src/pages/iou/request/step/IOURequestStepScan/index.native.tsx b/src/pages/iou/request/step/IOURequestStepScan/index.native.tsx index 14efef5c6ca7..2dee79a45c10 100644 --- a/src/pages/iou/request/step/IOURequestStepScan/index.native.tsx +++ b/src/pages/iou/request/step/IOURequestStepScan/index.native.tsx @@ -564,9 +564,9 @@ function IOURequestStepScan({ } else { navigateBack(); } - replaceReceipt({transactionID: initialTransactionID, file: file as File, source, transactionPolicyCategories: policyCategories}); + replaceReceipt({transactionID: initialTransactionID, file: file as File, source, transactionPolicy: policy, transactionPolicyCategories: policyCategories}); }, - [initialTransactionID, policyCategories, backTo], + [initialTransactionID, policy, policyCategories, backTo], ); /** diff --git a/src/pages/iou/request/step/IOURequestStepScan/index.tsx b/src/pages/iou/request/step/IOURequestStepScan/index.tsx index 10992ed9ca1a..749f92171cf3 100644 --- a/src/pages/iou/request/step/IOURequestStepScan/index.tsx +++ b/src/pages/iou/request/step/IOURequestStepScan/index.tsx @@ -610,10 +610,10 @@ function IOURequestStepScan({ const updateScanAndNavigate = useCallback( (file: FileObject, source: string) => { - replaceReceipt({transactionID: initialTransactionID, file: file as File, source, transactionPolicyCategories: policyCategories}); + replaceReceipt({transactionID: initialTransactionID, file: file as File, source, transactionPolicy: policy, transactionPolicyCategories: policyCategories}); navigateBack(); }, - [initialTransactionID, navigateBack, policyCategories], + [initialTransactionID, navigateBack, policy, policyCategories], ); const setReceiptFilesAndNavigate = (files: FileObject[]) => { diff --git a/src/pages/media/AttachmentModalScreen/routes/TransactionReceiptModalContent.tsx b/src/pages/media/AttachmentModalScreen/routes/TransactionReceiptModalContent.tsx index 4a423782d224..44395b1027a7 100644 --- a/src/pages/media/AttachmentModalScreen/routes/TransactionReceiptModalContent.tsx +++ b/src/pages/media/AttachmentModalScreen/routes/TransactionReceiptModalContent.tsx @@ -7,6 +7,7 @@ import {useMemoizedLazyExpensifyIcons} from '@hooks/useLazyAsset'; import useLocalize from '@hooks/useLocalize'; import useNetwork from '@hooks/useNetwork'; import useOnyx from '@hooks/useOnyx'; +import usePolicy from '@hooks/usePolicy'; import {detachReceipt, navigateToStartStepIfScanFileCannotBeRead} from '@libs/actions/IOU'; import {openReport} from '@libs/actions/Report'; import Navigation from '@libs/Navigation/Navigation'; @@ -37,6 +38,7 @@ function TransactionReceiptModalContent({navigation, route}: AttachmentModalScre const [transactionDraft] = useOnyx(`${ONYXKEYS.COLLECTION.TRANSACTION_DRAFT}${transactionID}`, {canBeMissing: true}); const [reportMetadata = CONST.DEFAULT_REPORT_METADATA] = useOnyx(`${ONYXKEYS.COLLECTION.REPORT_METADATA}${reportID}`, {canBeMissing: true}); const [policyCategories] = useOnyx(`${ONYXKEYS.COLLECTION.POLICY_CATEGORIES}${report?.policyID}`, {canBeMissing: true}); + const policy = usePolicy(report?.policyID); // If we have a merge transaction, we need to use the receipt from the merge transaction const [mergeTransaction] = useOnyx(`${ONYXKEYS.COLLECTION.MERGE_TRANSACTION}${mergeTransactionID}`, {canBeMissing: true}); @@ -141,9 +143,9 @@ function TransactionReceiptModalContent({navigation, route}: AttachmentModalScre * Detach the receipt and close the modal. */ const deleteReceiptAndClose = useCallback(() => { - detachReceipt(transaction?.transactionID, policyCategories); + detachReceipt(transaction?.transactionID, policy, policyCategories); navigation.goBack(); - }, [navigation, transaction?.transactionID, policyCategories]); + }, [navigation, transaction?.transactionID, policy, policyCategories]); const onDownloadAttachment = useDownloadAttachment({ isAuthTokenRequired, diff --git a/src/selectors/Report.ts b/src/selectors/Report.ts index 0742f84144bc..a0c60472d6e0 100644 --- a/src/selectors/Report.ts +++ b/src/selectors/Report.ts @@ -2,7 +2,7 @@ import type {OnyxEntry} from 'react-native-onyx'; import type {ValueOf} from 'type-fest'; import {getOriginalMessage, isClosedAction} from '@libs/ReportActionsUtils'; import CONST from '@src/CONST'; -import type {ReportActions} from '@src/types/onyx'; +import type {Report, ReportActions} from '@src/types/onyx'; import {getLastClosedReportAction} from './ReportAction'; function getArchiveReason(reportActions: OnyxEntry): ValueOf | undefined { @@ -15,4 +15,8 @@ function getArchiveReason(reportActions: OnyxEntry): ValueOf) { + return report?.policyID; +} + +export {getArchiveReason, getReportPolicyID}; diff --git a/tests/actions/IOUTest.ts b/tests/actions/IOUTest.ts index 7f9550ff2947..16eb63836ca7 100644 --- a/tests/actions/IOUTest.ts +++ b/tests/actions/IOUTest.ts @@ -6977,6 +6977,7 @@ describe('actions/IOU', () => { parentReport: fakeParentReport, currentDate, currentUserPersonalDetails, + hasOnlyPersonalPolicies: false, }); }) .then(async () => { @@ -6997,6 +6998,7 @@ describe('actions/IOU', () => { parentReport: fakeParentReport, currentDate, currentUserPersonalDetails, + hasOnlyPersonalPolicies: false, }); }) .then(async () => { @@ -7017,6 +7019,7 @@ describe('actions/IOU', () => { parentReport: fakeParentReport, currentDate, currentUserPersonalDetails, + hasOnlyPersonalPolicies: false, }); }) .then(async () => { @@ -7988,7 +7991,7 @@ describe('actions/IOU', () => { await waitForBatchedUpdates(); // When the receipt is replaced - replaceReceipt({transactionID, file, source}); + replaceReceipt({transactionID, file, source, transactionPolicy: undefined}); await waitForBatchedUpdates(); // Then the transaction should have the new receipt source @@ -8045,7 +8048,7 @@ describe('actions/IOU', () => { await waitForBatchedUpdates(); // When the receipt is replaced - replaceReceipt({transactionID, file, source}); + replaceReceipt({transactionID, file, source, transactionPolicy: undefined}); await waitForBatchedUpdates(); // Then the transaction should have the new receipt source @@ -10037,7 +10040,7 @@ describe('actions/IOU', () => { if (!transaction?.transactionID || !iouReport?.reportID) { throw new Error('Required transaction or report data is missing'); } - const result = rejectMoneyRequest(transaction.transactionID, iouReport.reportID, comment); + const result = rejectMoneyRequest(transaction.transactionID, iouReport.reportID, comment, policy); // Then: Should return navigation route to chat report expect(result).toBe(ROUTES.REPORT_WITH_ID.getRoute(iouReport.reportID)); @@ -10053,7 +10056,7 @@ describe('actions/IOU', () => { if (!transaction?.transactionID || !iouReport?.reportID) { throw new Error('Required transaction or report data is missing'); } - rejectMoneyRequest(transaction.transactionID, iouReport.reportID, comment); + rejectMoneyRequest(transaction.transactionID, iouReport.reportID, comment, policy); await waitForBatchedUpdates(); // Then: Verify violation is added diff --git a/tests/unit/TransactionPreviewUtils.test.ts b/tests/unit/TransactionPreviewUtils.test.ts index b70010199b66..9daede4b6fa9 100644 --- a/tests/unit/TransactionPreviewUtils.test.ts +++ b/tests/unit/TransactionPreviewUtils.test.ts @@ -86,7 +86,7 @@ describe('TransactionPreviewUtils', () => { source: 'source.com', filename: 'file_name.png', action: 'replaceReceipt', - retryParams: {transactionID: basicProps.transaction.transactionID, source: 'source.com'}, + retryParams: {transactionID: basicProps.transaction.transactionID, source: 'source.com', transactionPolicy: undefined}, }, }, }, @@ -249,7 +249,7 @@ describe('TransactionPreviewUtils', () => { source: 'source.com', filename: 'file_name.png', action: 'replaceReceipt', - retryParams: {transactionID: basicProps.transaction.transactionID, source: 'source.com'}, + retryParams: {transactionID: basicProps.transaction.transactionID, source: 'source.com', transactionPolicy: undefined}, }, }, },