diff --git a/src/pages/iou/request/step/IOURequestStepConfirmation.tsx b/src/pages/iou/request/step/IOURequestStepConfirmation.tsx
index 5537634e8c94..a90f12bdc649 100644
--- a/src/pages/iou/request/step/IOURequestStepConfirmation.tsx
+++ b/src/pages/iou/request/step/IOURequestStepConfirmation.tsx
@@ -1,5 +1,3 @@
-import {delegateEmailSelector} from '@selectors/Account';
-import {hasSeenTourSelector} from '@selectors/Onboarding';
 import {validTransactionDraftIDsSelector} from '@selectors/TransactionDraft';
 import React, {useCallback, useEffect, useMemo, useRef, useState} from 'react';
 import {View} from 'react-native';
@@ -21,97 +19,47 @@ import useFilesValidation from '@hooks/useFilesValidation';
 import {useMemoizedLazyExpensifyIcons} from '@hooks/useLazyAsset';
 import useLocalize from '@hooks/useLocalize';
 import useNetwork from '@hooks/useNetwork';
-import useOnboardingTaskInformation from '@hooks/useOnboardingTaskInformation';
 import useOnyx from '@hooks/useOnyx';
 import useOptimisticDraftTransactions from '@hooks/useOptimisticDraftTransactions';
-import useParentReportAction from '@hooks/useParentReportAction';
-import useParticipantsInvoiceReport from '@hooks/useParticipantsInvoiceReport';
-import useParticipantsPolicyTags from '@hooks/useParticipantsPolicyTags';
-import usePermissions from '@hooks/usePermissions';
 import usePolicyForTransaction from '@hooks/usePolicyForTransaction';
 import usePrivateIsArchivedMap from '@hooks/usePrivateIsArchivedMap';
 import useReportAttributes from '@hooks/useReportAttributes';
-import useReportTransactions from '@hooks/useReportTransactions';
 import useTheme from '@hooks/useTheme';
 import useThemeStyles from '@hooks/useThemeStyles';
-import {completeTestDriveTask} from '@libs/actions/Task';
 import {isMobileSafari} from '@libs/Browser';
-import {getCurrencySymbol} from '@libs/CurrencyUtils';
 import {canUseTouchScreen} from '@libs/DeviceCapabilities';
-import DistanceRequestUtils from '@libs/DistanceRequestUtils';
-import getCurrentPosition from '@libs/getCurrentPosition';
 import getIsNarrowLayout from '@libs/getIsNarrowLayout';
 import getNonEmptyStringOnyxID from '@libs/getNonEmptyStringOnyxID';
-import {getGPSCoordinates} from '@libs/GPSDraftDetailsUtils';
 import {
-    getExistingTransactionID,
     isMovingTransactionFromTrackExpense as isMovingTransactionFromTrackExpenseIOUUtils,
     navigateToStartMoneyRequestStep,
-    resolveOptimisticChatReportID,
     shouldShowReceiptEmptyState,
     shouldUseTransactionDraft,
 } from '@libs/IOUUtils';
-import Log from '@libs/Log';
-import dismissModalAndOpenReportInInboxTabHelper from '@libs/Navigation/helpers/dismissModalAndOpenReportInInboxTab';
 import isReportTopmostSplitNavigator from '@libs/Navigation/helpers/isReportTopmostSplitNavigator';
 import isSearchTopmostFullScreenRoute from '@libs/Navigation/helpers/isSearchTopmostFullScreenRoute';
-import navigateAfterExpenseCreate from '@libs/Navigation/helpers/navigateAfterExpenseCreate';
 import Navigation from '@libs/Navigation/Navigation';
-import {rand64, roundToTwoDecimalPlaces} from '@libs/NumberUtils';
 import {getParticipantsOption, getReportOption} from '@libs/OptionsListUtils';
-import {
-    findSelfDMReportID,
-    generateReportID,
-    getReportOrDraftReport,
-    hasViolations as hasViolationsReportUtils,
-    isMoneyRequestReport,
-    isProcessingReport,
-    isReportOutstanding,
-    isSelectedManagerMcTest,
-} from '@libs/ReportUtils';
+import {getReportOrDraftReport, isMoneyRequestReport, isProcessingReport, isReportOutstanding, isSelectedManagerMcTest} from '@libs/ReportUtils';
 import {buildCannedSearchQuery} from '@libs/SearchQueryUtils';
-import {endSpan, getSpan, startSpan} from '@libs/telemetry/activeSpans';
-import markSubmitExpenseEnd from '@libs/telemetry/markSubmitExpenseEnd';
 import type {SkeletonSpanReasonAttributes} from '@libs/telemetry/useSkeletonSpan';
 import {
-    getDefaultTaxCode,
-    getRateID,
     getRequestType,
-    getTaxValue,
-    getValidWaypoints,
     hasReceipt,
     isDistanceRequest as isDistanceRequestTransactionUtils,
-    isGPSDistanceRequest as isGPSDistanceRequestTransactionUtils,
     isManualDistanceRequest as isManualDistanceRequestTransactionUtils,
     isOdometerDistanceRequest as isOdometerDistanceRequestTransactionUtils,
     isScanRequest,
 } from '@libs/TransactionUtils';
-import type {GpsPoint} from '@userActions/IOU';
-import {
-    createDistanceRequest as createDistanceRequestIOUActions,
-    getIOURequestPolicyID,
-    setMoneyRequestBillable,
-    setMoneyRequestParticipantsFromReport,
-    setMoneyRequestReimbursable,
-} from '@userActions/IOU';
-import {submitPerDiemExpenseForSelfDM, submitPerDiemExpense as submitPerDiemExpenseIOUActions} from '@userActions/IOU/PerDiem';
+import {getIOURequestPolicyID, setMoneyRequestBillable, setMoneyRequestParticipantsFromReport, setMoneyRequestReimbursable} from '@userActions/IOU';
 import {setMoneyRequestReceipt} from '@userActions/IOU/Receipt';
-import {getReceiverType, sendInvoice} from '@userActions/IOU/SendInvoice';
-import {sendMoneyElsewhere, sendMoneyWithWallet} from '@userActions/IOU/SendMoney';
-import {splitBill, splitBillAndOpenReport, startSplitBill} from '@userActions/IOU/Split';
-import {requestMoney as requestMoneyIOUActions, trackExpense as trackExpenseIOUActions} from '@userActions/IOU/TrackExpense';
 import {removeDraftTransaction, replaceDefaultDraftTransaction} from '@userActions/TransactionEdit';
 import CONST from '@src/CONST';
 import ONYXKEYS from '@src/ONYXKEYS';
 import ROUTES from '@src/ROUTES';
 import type SCREENS from '@src/SCREENS';
-import type {RecentlyUsedCategories, Report} from '@src/types/onyx';
-import type {Participant} from '@src/types/onyx/IOU';
-import type {PaymentMethodType} from '@src/types/onyx/OriginalMessage';
-import type {InvoiceReceiver} from '@src/types/onyx/Report';
 import type {Receipt} from '@src/types/onyx/Transaction';
 import type {FileObject} from '@src/types/utils/Attachment';
-import {isEmptyObject} from '@src/types/utils/EmptyObject';
 import isLoadingOnyxValue from '@src/types/utils/isLoadingOnyxValue';
 import CategoryDefaultsSetter from './confirmation/CategoryDefaultsSetter';
 import DraftWorkspaceOpener from './confirmation/DraftWorkspaceOpener';
@@ -121,6 +69,7 @@ import OdometerReceiptStitcher from './confirmation/OdometerReceiptStitcher';
 import ReceiptFileValidator from './confirmation/ReceiptFileValidator';
 import SubmitExpenseOrchestrator from './confirmation/SubmitExpenseOrchestrator';
 import TelemetrySpanManager from './confirmation/TelemetrySpanManager';
+import useExpenseSubmission from './confirmation/useExpenseSubmission';
 import type {WithFullTransactionOrNotFoundProps} from './withFullTransactionOrNotFound';
 import withFullTransactionOrNotFound from './withFullTransactionOrNotFound';
 import type {WithWritableReportOrNotFoundProps} from './withWritableReportOrNotFound';
@@ -129,32 +78,6 @@ import withWritableReportOrNotFound from './withWritableReportOrNotFound';
 type IOURequestStepConfirmationProps = WithWritableReportOrNotFoundProps<typeof SCREENS.MONEY_REQUEST.STEP_CONFIRMATION> &
     WithFullTransactionOrNotFoundProps<typeof SCREENS.MONEY_REQUEST.STEP_CONFIRMATION>;
 
-// Ends the submit expense span, starts a geolocation child span, then calls getCurrentPosition.
-// The expense callback receives GPS coordinates on success or undefined on error.
-// Extracted to avoid duplicating this identical telemetry block across trackExpense and requestMoney paths.
-function getCurrentPositionWithGeolocationSpan(onPosition: (gpsCoords?: {lat: number; long: number}) => void) {
-    const parentSpan = getSpan(CONST.TELEMETRY.SPAN_SUBMIT_EXPENSE);
-    markSubmitExpenseEnd();
-
-    startSpan(CONST.TELEMETRY.SPAN_GEOLOCATION_WAIT, {
-        name: CONST.TELEMETRY.SPAN_GEOLOCATION_WAIT,
-        op: CONST.TELEMETRY.SPAN_GEOLOCATION_WAIT,
-        parentSpan,
-    });
-
-    getCurrentPosition(
-        (successData) => {
-            onPosition({lat: successData.coords.latitude, long: successData.coords.longitude});
-            endSpan(CONST.TELEMETRY.SPAN_GEOLOCATION_WAIT);
-        },
-        (errorData) => {
-            Log.info('[IOURequestStepConfirmation] getCurrentPosition failed', false, errorData);
-            onPosition();
-            endSpan(CONST.TELEMETRY.SPAN_GEOLOCATION_WAIT);
-        },
-    );
-}
-
 function IOURequestStepConfirmation({
     report: reportReal,
     reportDraft,
@@ -181,8 +104,6 @@ function IOURequestStepConfirmation({
     const [existingTransaction, existingTransactionResult] = useOnyx(`${ONYXKEYS.COLLECTION.TRANSACTION}${getNonEmptyStringOnyxID(currentTransactionID)}`);
     const [optimisticTransaction, optimisticTransactionResult] = useOnyx(`${ONYXKEYS.COLLECTION.TRANSACTION_DRAFT}${getNonEmptyStringOnyxID(currentTransactionID)}`);
     const isLoadingCurrentTransaction = isLoadingOnyxValue(existingTransactionResult, optimisticTransactionResult);
-    const [introSelected] = useOnyx(ONYXKEYS.NVP_INTRO_SELECTED);
-    const [activePolicyID] = useOnyx(ONYXKEYS.NVP_ACTIVE_POLICY_ID);
     const transaction = useMemo(
         () => (!isLoadingCurrentTransaction ? (optimisticTransaction ?? existingTransaction) : undefined),
         [existingTransaction, optimisticTransaction, isLoadingCurrentTransaction],
@@ -196,10 +117,7 @@ function IOURequestStepConfirmation({
     const draftPolicyID = getIOURequestPolicyID(initialTransaction, reportDraft);
     const [policyDraft] = useOnyx(`${ONYXKEYS.COLLECTION.POLICY_DRAFTS}${draftPolicyID}`);
     const [policyReal] = useOnyx(`${ONYXKEYS.COLLECTION.POLICY}${realPolicyID}`);
-    const [gpsDraftDetails] = useOnyx(ONYXKEYS.GPS_DRAFT_DETAILS);
-    const [betas] = useOnyx(ONYXKEYS.BETAS);
     const [conciergeReportID] = useOnyx(ONYXKEYS.CONCIERGE_REPORT_ID);
-    const [delegateEmail] = useOnyx(ONYXKEYS.ACCOUNT, {selector: delegateEmailSelector});
 
     const expensifyIcons = useMemoizedLazyExpensifyIcons(['ReplaceReceipt', 'SmartScan']);
 
@@ -243,25 +161,10 @@ function IOURequestStepConfirmation({
     const isDraftPolicy = policy === policyDraft;
 
     const [policyCategoriesDraft] = useOnyx(`${ONYXKEYS.COLLECTION.POLICY_CATEGORIES_DRAFT}${draftPolicyID}`);
-    const [policyRecentlyUsedCategories] = useOnyx(`${ONYXKEYS.COLLECTION.POLICY_RECENTLY_USED_CATEGORIES}${policyID}`);
-    const [policyTags] = useOnyx(`${ONYXKEYS.COLLECTION.POLICY_TAGS}${policyID}`);
-    const [policyRecentlyUsedTags] = useOnyx(`${ONYXKEYS.COLLECTION.POLICY_RECENTLY_USED_TAGS}${policyID}`);
-    const [policyRecentlyUsedCurrencies] = useOnyx(ONYXKEYS.RECENTLY_USED_CURRENCIES);
-
-    const [selfDMReport] = useOnyx(`${ONYXKEYS.COLLECTION.REPORT}${findSelfDMReportID()}`);
 
-    const [userLocation] = useOnyx(ONYXKEYS.USER_LOCATION);
-    const [quickAction] = useOnyx(ONYXKEYS.NVP_QUICK_ACTION_GLOBAL_CREATE);
-    const [isSelfTourViewed = false] = useOnyx(ONYXKEYS.NVP_ONBOARDING, {selector: hasSeenTourSelector});
     const [draftTransactionIDs] = useOnyx(ONYXKEYS.COLLECTION.TRANSACTION_DRAFT, {selector: validTransactionDraftIDsSelector});
 
     const reportAttributesDerived = useReportAttributes();
-    const reportTransactions = useReportTransactions(report?.reportID);
-    const [recentlyUsedDestinations] = useOnyx(`${ONYXKEYS.COLLECTION.POLICY_RECENTLY_USED_DESTINATIONS}${policyID}`);
-    const [transactionViolations] = useOnyx(ONYXKEYS.COLLECTION.TRANSACTION_VIOLATIONS);
-    const transactionViolationsRef = useRef(transactionViolations);
-    transactionViolationsRef.current = transactionViolations;
-    const hasViolations = hasViolationsReportUtils(report?.reportID, transactionViolations, currentUserPersonalDetails.accountID, currentUserPersonalDetails.login ?? '');
 
     const policyCategories = useMemo(() => {
         if (isDraftPolicy && draftPolicyID) {
@@ -275,18 +178,9 @@ function IOURequestStepConfirmation({
         return undefined;
     }, [isDraftPolicy, draftPolicyID, policyID, policyCategoriesDraft, allPolicyCategories]);
 
-    const receiverParticipant: Participant | InvoiceReceiver | undefined = transaction?.participants?.find((participant) => participant?.accountID) ?? report?.invoiceReceiver;
-    const receiverAccountID = receiverParticipant && 'accountID' in receiverParticipant && receiverParticipant.accountID ? receiverParticipant.accountID : CONST.DEFAULT_NUMBER_ID;
-    const receiverType = getReceiverType(receiverParticipant);
-    const senderWorkspaceID = transaction?.participants?.find((participant) => participant?.isSender)?.policyID;
-    const [senderWorkspacePolicyTags] = useOnyx(`${ONYXKEYS.COLLECTION.POLICY_TAGS}${senderWorkspaceID}`);
-
-    const existingInvoiceReport = useParticipantsInvoiceReport(receiverAccountID, receiverType, senderWorkspaceID);
-
     const styles = useThemeStyles();
     const theme = useTheme();
-    const {translate, toLocaleDigit} = useLocalize();
-    const {isBetaEnabled} = usePermissions();
+    const {translate} = useLocalize();
     const {isOffline} = useNetwork();
     const {showConfirmModal} = useConfirmModal();
     // isConfirming, selectedParticipantList, and startLocationPermissionFlow state
@@ -296,34 +190,19 @@ function IOURequestStepConfirmation({
     const isDistanceRequest = isDistanceRequestTransactionUtils(transaction);
     const isManualDistanceRequest = isManualDistanceRequestTransactionUtils(transaction);
     const isOdometerDistanceRequest = isOdometerDistanceRequestTransactionUtils(transaction);
-    const isGPSDistanceRequest = isGPSDistanceRequestTransactionUtils(transaction);
-    const transactionDistance = isManualDistanceRequest || isOdometerDistanceRequest || isGPSDistanceRequest ? (transaction?.comment?.customUnit?.quantity ?? undefined) : undefined;
     const isTimeRequest = requestType === CONST.IOU.REQUEST_TYPE.TIME;
     const [lastLocationPermissionPrompt] = useOnyx(ONYXKEYS.NVP_LAST_LOCATION_PERMISSION_PROMPT);
-    const {
-        taskReport: viewTourTaskReport,
-        taskParentReport: viewTourTaskParentReport,
-        isOnboardingTaskParentReportArchived: isViewTourTaskParentReportArchived,
-        hasOutstandingChildTask,
-    } = useOnboardingTaskInformation(CONST.ONBOARDING_TASK_TYPE.VIEW_TOUR);
     const privateIsArchivedMap = usePrivateIsArchivedMap();
-    const parentReportAction = useParentReportAction(viewTourTaskReport);
 
     const receiptFilename = transaction?.receipt?.filename;
     const receiptPath = transaction?.receipt?.source;
     const isEditingReceipt = hasReceipt(transaction);
-    const customUnitRateID = getRateID(transaction) ?? '';
-    const defaultTaxCode = getDefaultTaxCode(policy, transaction);
-    const transactionTaxCode = (transaction?.taxCode ? transaction?.taxCode : defaultTaxCode) ?? '';
-    const transactionTaxAmount = transaction?.taxAmount ?? 0;
-    const transactionTaxValue = transaction?.taxValue ?? getTaxValue(policy, transaction, transactionTaxCode) ?? '';
     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 [isConfirmed, setIsConfirmed] = useState(false);
     const [isStitchingReceipt, setIsStitchingReceipt] = useState(false);
     const [stitchError, setStitchError] = useState('');
     const headerTitle = useMemo(() => {
@@ -361,13 +240,9 @@ function IOURequestStepConfirmation({
         // connection, so we don't need to subscribe to COLLECTION.REPORT_DRAFT here.
         [transaction?.participants, iouType, personalDetails, reportAttributesDerived, privateIsArchivedMap, policy, conciergeReportID],
     );
-    const participantsPolicyTags = useParticipantsPolicyTags(participants ?? []);
     const isPolicyExpenseChat = useMemo(() => participants?.some((participant) => participant.isPolicyExpenseChat), [participants]);
-    const formHasBeenSubmitted = useRef(false);
     const isFromGlobalCreate = !!(transaction?.isFromGlobalCreate ?? transaction?.isFromFloatingActionButton);
 
-    const isASAPSubmitBetaEnabled = isBetaEnabled(CONST.BETAS.ASAP_SUBMIT);
-
     useFetchRoute(transaction, transaction?.comment?.waypoints, action, shouldUseTransactionDraft(action, iouType) ? CONST.TRANSACTION.STATE.DRAFT : CONST.TRANSACTION.STATE.CURRENT);
 
     const policyExpenseChatPolicyID = participants?.find((participant) => participant.isPolicyExpenseChat)?.policyID;
@@ -383,6 +258,35 @@ function IOURequestStepConfirmation({
     // so pre-inserting Search would leave a stale route in the stack.
     const canPreInsertSearch = iouType !== CONST.IOU.TYPE.PAY && iouType !== CONST.IOU.TYPE.SPLIT && !(isPerDiemRequest && iouType === CONST.IOU.TYPE.TRACK);
 
+    const {createTransaction, sendMoney, isConfirmed, formHasBeenSubmitted} = useExpenseSubmission({
+        transaction,
+        transactions,
+        receiptFiles,
+        report,
+        reportID,
+        policy,
+        policyCategories,
+        isDraftPolicy,
+        currentUserPersonalDetails,
+        personalDetails,
+        participants,
+        iouType,
+        action,
+        requestType,
+        isDistanceRequest,
+        isManualDistanceRequest,
+        isOdometerDistanceRequest,
+        isPerDiemRequest,
+        isTimeRequest,
+        isMovingTransactionFromTrackExpense,
+        isCategorizingTrackExpense,
+        isSharingTrackExpense,
+        isUnreported,
+        draftTransactionIDs,
+        privateIsArchivedMap,
+        backToReport,
+    });
+
     const hasPreInsertFired = useRef(false);
     const isTransactionReady = !!transaction;
     useEffect(() => {
@@ -412,6 +316,7 @@ function IOURequestStepConfirmation({
         return () => {
             clearTimeout(timer);
 
+            // eslint-disable-next-line react-hooks/exhaustive-deps -- formHasBeenSubmitted is a stable ref from useExpenseSubmission; reading .current in cleanup is intentional
             if (!Navigation.getIsFullscreenPreInsertedUnderRHP() || formHasBeenSubmitted.current) {
                 return;
             }
@@ -488,816 +393,6 @@ function IOURequestStepConfirmation({
         backToReport,
     ]);
 
-    const requestMoney = useCallback(
-        (selectedParticipants: Participant[], shouldHandleNav: boolean, gpsPoint?: GpsPoint) => {
-            if (!transactions.length) {
-                return;
-            }
-
-            const participant = selectedParticipants.at(0);
-            if (!participant) {
-                return;
-            }
-
-            const optimisticChatReportID = generateReportID();
-            const optimisticCreatedReportActionID = rand64();
-            const optimisticReportPreviewActionID = rand64();
-            let existingIOUReport: Report | undefined;
-
-            for (const [index, item] of transactions.entries()) {
-                const receipt = receiptFiles[item.transactionID];
-                const isTestReceipt = receipt?.isTestReceipt ?? false;
-                const isTestDriveReceipt = receipt?.isTestDriveReceipt ?? false;
-                const isLinkedTrackedExpenseReportArchived =
-                    !!item.linkedTrackedExpenseReportID && privateIsArchivedMap[`${ONYXKEYS.COLLECTION.REPORT_NAME_VALUE_PAIRS}${item.linkedTrackedExpenseReportID}`];
-
-                const itemAmount = isTestReceipt ? CONST.TEST_RECEIPT.AMOUNT : item.amount;
-                const itemCurrency = isTestReceipt ? CONST.TEST_RECEIPT.CURRENCY : item.currency;
-
-                if (isTestDriveReceipt) {
-                    completeTestDriveTask(
-                        viewTourTaskReport,
-                        viewTourTaskParentReport,
-                        isViewTourTaskParentReportArchived,
-                        currentUserPersonalDetails.accountID,
-                        hasOutstandingChildTask,
-                        parentReportAction,
-                        delegateEmail,
-                        false,
-                    );
-                }
-
-                const existingTransactionID = getExistingTransactionID(item.linkedTrackedExpenseReportAction);
-                const existingTransactionDraft = transactions.find((tx) => tx.transactionID === existingTransactionID);
-                let merchantToUse = isTestReceipt ? CONST.TEST_RECEIPT.MERCHANT : item.merchant;
-                if (!isTestReceipt && isManualDistanceRequestTransactionUtils(item)) {
-                    const distance = item.comment?.customUnit?.quantity;
-                    const unit = item.comment?.customUnit?.distanceUnit;
-                    const rate = item.comment?.customUnit?.defaultP2PRate;
-                    if (distance && unit && rate) {
-                        // Convert distance to meters
-                        const distanceInMeters = DistanceRequestUtils.convertToDistanceInMeters(distance, unit);
-                        merchantToUse = DistanceRequestUtils.getDistanceMerchant(
-                            true,
-                            distanceInMeters,
-                            unit,
-                            rate,
-                            item.currency ?? CONST.CURRENCY.USD,
-                            translate,
-                            toLocaleDigit,
-                            getCurrencySymbol,
-                        );
-                    }
-                }
-
-                const {iouReport} = requestMoneyIOUActions({
-                    report,
-                    existingIOUReport,
-                    optimisticChatReportID,
-                    optimisticCreatedReportActionID,
-                    optimisticReportPreviewActionID,
-                    participantParams: {
-                        payeeEmail: currentUserPersonalDetails.login,
-                        payeeAccountID: currentUserPersonalDetails.accountID,
-                        participant,
-                    },
-                    policyParams: {
-                        policy,
-                        policyTagList: policyTags,
-                        policyCategories,
-                        policyRecentlyUsedCategories,
-                        policyRecentlyUsedTags,
-                    },
-                    gpsPoint,
-                    action,
-                    transactionParams: {
-                        amount: itemAmount,
-                        distance: isManualDistanceRequest && typeof item.comment?.customUnit?.quantity === 'number' ? roundToTwoDecimalPlaces(item.comment.customUnit.quantity) : undefined,
-                        attendees: item.comment?.attendees,
-                        currency: itemCurrency,
-                        created: item.created,
-                        merchant: merchantToUse,
-                        comment: item?.comment?.comment?.trim() ?? '',
-                        receipt,
-                        category: item.category,
-                        tag: item.tag,
-                        taxCode: transactionTaxCode,
-                        taxAmount: transactionTaxAmount,
-                        taxValue: transactionTaxValue,
-                        billable: item.billable,
-                        reimbursable: item.reimbursable,
-                        actionableWhisperReportActionID: item.actionableWhisperReportActionID,
-                        linkedTrackedExpenseReportAction: item.linkedTrackedExpenseReportAction,
-                        linkedTrackedExpenseReportID: item.linkedTrackedExpenseReportID,
-                        waypoints: Object.keys(item.comment?.waypoints ?? {}).length ? getValidWaypoints(item.comment?.waypoints, true, isGPSDistanceRequest) : undefined,
-                        customUnitRateID,
-                        isTestDrive: item.receipt?.isTestDriveReceipt,
-                        originalTransactionID: item.comment?.originalTransactionID,
-                        source: item.comment?.source,
-                        isLinkedTrackedExpenseReportArchived,
-                        isFromGlobalCreate: item?.isFromFloatingActionButton ?? item?.isFromGlobalCreate,
-                        ...(isTimeRequest
-                            ? {type: CONST.TRANSACTION.TYPE.TIME, count: item.comment?.units?.count, rate: item.comment?.units?.rate, unit: CONST.TIME_TRACKING.UNIT.HOUR}
-                            : {}),
-                    },
-                    shouldHandleNavigation: shouldHandleNav && index === transactions.length - 1,
-                    shouldGenerateTransactionThreadReport: false,
-                    backToReport,
-                    isASAPSubmitBetaEnabled,
-                    currentUserAccountIDParam: currentUserPersonalDetails.accountID,
-                    currentUserEmailParam: currentUserPersonalDetails.email ?? '',
-                    transactionViolations: transactionViolationsRef.current,
-                    policyRecentlyUsedCurrencies: policyRecentlyUsedCurrencies ?? [],
-                    quickAction,
-                    existingTransactionDraft,
-                    draftTransactionIDs,
-                    isSelfTourViewed,
-                    betas,
-                    personalDetails,
-                });
-                existingIOUReport = iouReport;
-            }
-        },
-        [
-            transactions,
-            receiptFiles,
-            privateIsArchivedMap,
-            report,
-            currentUserPersonalDetails.login,
-            currentUserPersonalDetails.accountID,
-            currentUserPersonalDetails.email,
-            policy,
-            policyTags,
-            policyCategories,
-            policyRecentlyUsedCategories,
-            policyRecentlyUsedTags,
-            action,
-            isManualDistanceRequest,
-            transactionTaxCode,
-            transactionTaxAmount,
-            transactionTaxValue,
-            customUnitRateID,
-            isTimeRequest,
-            backToReport,
-            isASAPSubmitBetaEnabled,
-            policyRecentlyUsedCurrencies,
-            quickAction,
-            isSelfTourViewed,
-            viewTourTaskReport,
-            viewTourTaskParentReport,
-            isViewTourTaskParentReportArchived,
-            hasOutstandingChildTask,
-            parentReportAction,
-            delegateEmail,
-            translate,
-            toLocaleDigit,
-            betas,
-            personalDetails,
-            isGPSDistanceRequest,
-            draftTransactionIDs,
-        ],
-    );
-
-    const submitPerDiemExpense = useCallback(
-        (selectedParticipants: Participant[], trimmedComment: string, shouldHandleNav: boolean, policyRecentlyUsedCategoriesParam?: RecentlyUsedCategories) => {
-            if (!transaction) {
-                return;
-            }
-
-            const participant = selectedParticipants.at(0);
-            if (!participant || isEmptyObject(transaction.comment) || isEmptyObject(transaction.comment.customUnit)) {
-                return;
-            }
-            if (iouType === CONST.IOU.TYPE.TRACK) {
-                submitPerDiemExpenseForSelfDM({
-                    selfDMReport,
-                    policy,
-                    transactionParams: {
-                        currency: transaction.currency,
-                        created: transaction.created,
-                        comment: trimmedComment,
-                        category: transaction.category,
-                        tag: transaction.tag,
-                        customUnit: transaction.comment?.customUnit,
-                        billable: transaction.billable,
-                        reimbursable: transaction.reimbursable,
-                        attendees: transaction.comment?.attendees,
-                        isFromGlobalCreate: transaction.isFromFloatingActionButton ?? transaction.isFromGlobalCreate,
-                    },
-                    currentUserAccountIDParam: currentUserPersonalDetails.accountID,
-                    currentUserEmailParam: currentUserPersonalDetails.login ?? '',
-                    quickAction,
-                });
-            } else {
-                const isExpenseReport = isMoneyRequestReport(report);
-                let existingChatReport = report;
-                if (isExpenseReport) {
-                    existingChatReport = getReportOrDraftReport(report?.chatReportID);
-                } else if (!report?.reportID && participant.isPolicyExpenseChat && participant.reportID) {
-                    existingChatReport = getReportOrDraftReport(participant.reportID);
-                }
-                const {optimisticChatReportID, chatReportID} = resolveOptimisticChatReportID(
-                    [participant.accountID ?? CONST.DEFAULT_NUMBER_ID, currentUserPersonalDetails.accountID],
-                    existingChatReport,
-                );
-                const activeReportID = isExpenseReport && Navigation.getTopmostReportId() === report?.reportID ? report?.reportID : chatReportID;
-
-                const result = submitPerDiemExpenseIOUActions({
-                    report,
-                    participantParams: {
-                        payeeEmail: currentUserPersonalDetails.login,
-                        payeeAccountID: currentUserPersonalDetails.accountID,
-                        participant,
-                    },
-                    policyParams: {
-                        policy,
-                        policyTagList: policyTags,
-                        policyRecentlyUsedTags,
-                        policyCategories,
-                        policyRecentlyUsedCategories: policyRecentlyUsedCategoriesParam,
-                    },
-                    recentlyUsedParams: {
-                        destinations: recentlyUsedDestinations,
-                    },
-                    transactionParams: {
-                        currency: transaction.currency,
-                        created: transaction.created,
-                        comment: trimmedComment,
-                        category: transaction.category,
-                        tag: transaction.tag,
-                        customUnit: transaction.comment?.customUnit,
-                        billable: transaction.billable,
-                        reimbursable: transaction.reimbursable,
-                        attendees: transaction.comment?.attendees,
-                        isFromGlobalCreate: transaction.isFromFloatingActionButton ?? transaction.isFromGlobalCreate,
-                    },
-                    isASAPSubmitBetaEnabled,
-                    currentUserAccountIDParam: currentUserPersonalDetails.accountID,
-                    currentUserEmailParam: currentUserPersonalDetails.login ?? '',
-                    hasViolations,
-                    policyRecentlyUsedCurrencies: policyRecentlyUsedCurrencies ?? [],
-                    quickAction,
-                    betas,
-                    personalDetails,
-                    optimisticChatReportID,
-                });
-                if (shouldHandleNav && result && activeReportID) {
-                    navigateAfterExpenseCreate({
-                        activeReportID,
-                        transactionID: transaction.transactionID,
-                        isFromGlobalCreate: transaction.isFromFloatingActionButton ?? transaction.isFromGlobalCreate,
-                        hasMultipleTransactions: reportTransactions.length > 0,
-                    });
-                }
-            }
-        },
-        [
-            transaction,
-            iouType,
-            selfDMReport,
-            policy,
-            currentUserPersonalDetails.accountID,
-            currentUserPersonalDetails.login,
-            report,
-            policyTags,
-            policyRecentlyUsedTags,
-            policyCategories,
-            recentlyUsedDestinations,
-            isASAPSubmitBetaEnabled,
-            hasViolations,
-            policyRecentlyUsedCurrencies,
-            quickAction,
-            betas,
-            personalDetails,
-            reportTransactions.length,
-        ],
-    );
-
-    const [recentWaypoints] = useOnyx(ONYXKEYS.NVP_RECENT_WAYPOINTS);
-
-    const trackExpense = useCallback(
-        (selectedParticipants: Participant[], shouldHandleNav: boolean, gpsPoint?: GpsPoint) => {
-            if (!transactions.length) {
-                return;
-            }
-            const participant = selectedParticipants.at(0);
-            if (!participant) {
-                return;
-            }
-            for (const [index, item] of transactions.entries()) {
-                const isLinkedTrackedExpenseReportArchived =
-                    !!item.linkedTrackedExpenseReportID && privateIsArchivedMap[`${ONYXKEYS.COLLECTION.REPORT_NAME_VALUE_PAIRS}${item.linkedTrackedExpenseReportID}`];
-                const itemDistance = isManualDistanceRequest || isOdometerDistanceRequest || isGPSDistanceRequest ? (item.comment?.customUnit?.quantity ?? undefined) : undefined;
-
-                trackExpenseIOUActions({
-                    report,
-                    isDraftPolicy,
-                    action,
-                    participantParams: {
-                        payeeEmail: currentUserPersonalDetails.login,
-                        payeeAccountID: currentUserPersonalDetails.accountID,
-                        participant,
-                    },
-                    policyParams: {
-                        policy,
-                        policyCategories,
-                        policyTagList: policyTags,
-                    },
-                    transactionParams: {
-                        amount: item.amount,
-                        distance: itemDistance,
-                        currency: item.currency,
-                        created: item.created,
-                        merchant: item.merchant,
-                        comment: item?.comment?.comment?.trim() ?? '',
-                        receipt: receiptFiles[item.transactionID],
-                        category: item.category,
-                        tag: item.tag,
-                        taxCode: transactionTaxCode,
-                        taxAmount: transactionTaxAmount,
-                        taxValue: transactionTaxValue,
-                        billable: item.billable,
-                        reimbursable: item.reimbursable,
-                        gpsPoint,
-                        validWaypoints: Object.keys(item?.comment?.waypoints ?? {}).length ? getValidWaypoints(item.comment?.waypoints, true, isGPSDistanceRequest) : undefined,
-                        actionableWhisperReportActionID: item.actionableWhisperReportActionID,
-                        linkedTrackedExpenseReportAction: item.linkedTrackedExpenseReportAction,
-                        linkedTrackedExpenseReportID: item.linkedTrackedExpenseReportID,
-                        customUnitRateID,
-                        attendees: item.comment?.attendees,
-                        isLinkedTrackedExpenseReportArchived,
-                        odometerStart: isOdometerDistanceRequest ? item.comment?.odometerStart : undefined,
-                        odometerEnd: isOdometerDistanceRequest ? item.comment?.odometerEnd : undefined,
-                        isFromGlobalCreate: item?.isFromFloatingActionButton ?? item?.isFromGlobalCreate,
-                        gpsCoordinates: isGPSDistanceRequest ? getGPSCoordinates(gpsDraftDetails) : undefined,
-                    },
-                    accountantParams: {
-                        accountant: item.accountant,
-                    },
-                    shouldHandleNavigation: shouldHandleNav && index === transactions.length - 1,
-                    isASAPSubmitBetaEnabled,
-                    currentUserAccountIDParam: currentUserPersonalDetails.accountID,
-                    currentUserEmailParam: currentUserPersonalDetails.login ?? '',
-                    introSelected,
-                    activePolicyID,
-                    quickAction,
-                    recentWaypoints,
-                    betas,
-                    draftTransactionIDs,
-                    isSelfTourViewed,
-                });
-            }
-        },
-        [
-            transactions,
-            privateIsArchivedMap,
-            isManualDistanceRequest,
-            isOdometerDistanceRequest,
-            isGPSDistanceRequest,
-            report,
-            isDraftPolicy,
-            action,
-            currentUserPersonalDetails.login,
-            currentUserPersonalDetails.accountID,
-            policy,
-            policyCategories,
-            policyTags,
-            receiptFiles,
-            transactionTaxCode,
-            transactionTaxAmount,
-            transactionTaxValue,
-            customUnitRateID,
-            gpsDraftDetails,
-            isASAPSubmitBetaEnabled,
-            introSelected,
-            activePolicyID,
-            quickAction,
-            recentWaypoints,
-            betas,
-            draftTransactionIDs,
-            isSelfTourViewed,
-        ],
-    );
-
-    const createDistanceRequest = useCallback(
-        (selectedParticipants: Participant[], trimmedComment: string, shouldHandleNav = true) => {
-            if (!transaction) {
-                return;
-            }
-
-            createDistanceRequestIOUActions({
-                report,
-                participants: selectedParticipants,
-                currentUserLogin: currentUserPersonalDetails.login,
-                currentUserAccountID: currentUserPersonalDetails.accountID,
-                iouType,
-                existingTransaction: transaction,
-                policyParams: {
-                    policy,
-                    policyCategories,
-                    policyTagList: policyTags,
-                    policyRecentlyUsedCategories,
-                    policyRecentlyUsedTags,
-                },
-                transactionParams: {
-                    amount: transaction.amount,
-                    comment: trimmedComment,
-                    distance: transactionDistance,
-                    created: transaction.created,
-                    currency: transaction.currency,
-                    merchant: transaction.merchant,
-                    category: transaction.category,
-                    tag: transaction.tag,
-                    taxCode: transactionTaxCode,
-                    taxAmount: transactionTaxAmount,
-                    taxValue: transactionTaxValue,
-                    customUnitRateID,
-                    splitShares: transaction.splitShares,
-                    validWaypoints: getValidWaypoints(transaction.comment?.waypoints, true, isGPSDistanceRequest),
-                    billable: transaction.billable,
-                    reimbursable: transaction.reimbursable,
-                    attendees: transaction.comment?.attendees,
-                    receipt: isManualDistanceRequest || isOdometerDistanceRequest ? receiptFiles[transaction.transactionID] : undefined,
-                    odometerStart: isOdometerDistanceRequest ? transaction.comment?.odometerStart : undefined,
-                    odometerEnd: isOdometerDistanceRequest ? transaction.comment?.odometerEnd : undefined,
-                    isFromGlobalCreate: transaction.isFromFloatingActionButton ?? transaction.isFromGlobalCreate,
-                    gpsCoordinates: isGPSDistanceRequest ? getGPSCoordinates(gpsDraftDetails) : undefined,
-                },
-                backToReport,
-                isASAPSubmitBetaEnabled,
-                transactionViolations: transactionViolationsRef.current,
-                quickAction,
-                policyRecentlyUsedCurrencies: policyRecentlyUsedCurrencies ?? [],
-                personalDetails,
-                recentWaypoints,
-                betas,
-                shouldHandleNavigation: shouldHandleNav,
-            });
-        },
-        [
-            transaction,
-            report,
-            currentUserPersonalDetails.login,
-            currentUserPersonalDetails.accountID,
-            iouType,
-            policy,
-            policyCategories,
-            policyTags,
-            policyRecentlyUsedCategories,
-            policyRecentlyUsedTags,
-            transactionDistance,
-            transactionTaxCode,
-            transactionTaxAmount,
-            transactionTaxValue,
-            customUnitRateID,
-            isManualDistanceRequest,
-            isOdometerDistanceRequest,
-            receiptFiles,
-            isGPSDistanceRequest,
-            gpsDraftDetails,
-            backToReport,
-            isASAPSubmitBetaEnabled,
-            quickAction,
-            policyRecentlyUsedCurrencies,
-            personalDetails,
-            recentWaypoints,
-            betas,
-        ],
-    );
-
-    // shouldHandleNavigation is a function parameter, not a closure variable, so it does not
-    // need to appear in the dependency array. The handle* functions pass it at call time
-    // (e.g. createTransaction(participants, false, false) for fast paths).
-    const createTransaction = useCallback(
-        (selectedParticipants: Participant[], locationPermissionGranted = false, shouldHandleNavigation = true) => {
-            setIsConfirmed(true);
-            let splitParticipants = selectedParticipants;
-
-            // Filter out participants with an amount equal to 0
-            if (iouType === CONST.IOU.TYPE.SPLIT && transaction?.splitShares) {
-                const participantsWithAmount = new Set(
-                    Object.keys(transaction.splitShares ?? {})
-                        .filter((accountID: string): boolean => (transaction?.splitShares?.[Number(accountID)]?.amount ?? 0) > 0)
-                        .map((accountID) => Number(accountID)),
-                );
-                splitParticipants = selectedParticipants.filter((participant) =>
-                    participantsWithAmount.has(
-                        participant.isPolicyExpenseChat ? (participant?.ownerAccountID ?? CONST.DEFAULT_NUMBER_ID) : (participant.accountID ?? CONST.DEFAULT_NUMBER_ID),
-                    ),
-                );
-            }
-            const trimmedComment = transaction?.comment?.comment?.trim() ?? '';
-
-            // Don't let the form be submitted multiple times while the navigator is waiting to take the user to a different page
-            if (formHasBeenSubmitted.current) {
-                return;
-            }
-
-            formHasBeenSubmitted.current = true;
-
-            if (iouType !== CONST.IOU.TYPE.TRACK && isDistanceRequest && !isMovingTransactionFromTrackExpense && !isUnreported) {
-                createDistanceRequest(iouType === CONST.IOU.TYPE.SPLIT ? splitParticipants : selectedParticipants, trimmedComment, shouldHandleNavigation);
-                markSubmitExpenseEnd();
-                return;
-            }
-
-            const currentTransactionReceiptFile = transaction?.transactionID ? receiptFiles[transaction.transactionID] : undefined;
-
-            // Split (startSplitBill, splitBill, splitBillAndOpenReport) and invoice (sendInvoice)
-            // flows handle their own navigation internally and don't participate in the
-            // dismiss-modal fast path. shouldHandleNavigation is not threaded through to them.
-            if (iouType === CONST.IOU.TYPE.SPLIT && Object.values(receiptFiles).filter((receipt) => !!receipt).length) {
-                const currentUserLogin = currentUserPersonalDetails.login;
-                if (currentUserLogin) {
-                    for (const [index, item] of transactions.entries()) {
-                        const transactionReceiptFile = receiptFiles[item.transactionID];
-                        if (!transactionReceiptFile) {
-                            continue;
-                        }
-                        const itemTrimmedComment = item?.comment?.comment?.trim() ?? '';
-
-                        // If we have a receipt let's start the split expense by creating only the action, the transaction, and the group DM if needed
-                        startSplitBill({
-                            participants: selectedParticipants,
-                            currentUserLogin,
-                            currentUserAccountID: currentUserPersonalDetails.accountID,
-                            comment: itemTrimmedComment,
-                            receipt: transactionReceiptFile,
-                            existingSplitChatReportID: report?.reportID,
-                            billable: item.billable,
-                            reimbursable: item.reimbursable,
-                            category: item.category,
-                            tag: item.tag,
-                            currency: item.currency,
-                            taxCode: transactionTaxCode,
-                            taxAmount: transactionTaxAmount,
-                            taxValue: transactionTaxValue,
-                            shouldPlaySound: index === transactions.length - 1,
-                            policyRecentlyUsedCategories,
-                            policyRecentlyUsedTags,
-                            quickAction,
-                            policyRecentlyUsedCurrencies: policyRecentlyUsedCurrencies ?? [],
-                            participantsPolicyTags,
-                        });
-                    }
-                }
-                markSubmitExpenseEnd();
-                return;
-            }
-
-            // IOUs created from a group report will have a reportID param in the route.
-            // Since the user is already viewing the report, we don't need to navigate them to the report
-            if (iouType === CONST.IOU.TYPE.SPLIT && !transaction?.isFromGlobalCreate) {
-                if (currentUserPersonalDetails.login && !!transaction) {
-                    splitBill({
-                        participants: splitParticipants,
-                        currentUserLogin: currentUserPersonalDetails.login,
-                        currentUserAccountID: currentUserPersonalDetails.accountID,
-                        amount: transaction.amount,
-                        comment: trimmedComment,
-                        currency: transaction.currency,
-                        merchant: transaction.merchant,
-                        created: transaction.created,
-                        category: transaction.category,
-                        tag: transaction.tag,
-                        existingSplitChatReportID: report?.reportID,
-                        billable: transaction.billable,
-                        reimbursable: transaction.reimbursable,
-                        iouRequestType: transaction.iouRequestType,
-                        splitShares: transaction.splitShares,
-                        taxCode: transactionTaxCode,
-                        taxAmount: transactionTaxAmount,
-                        taxValue: transactionTaxValue,
-                        policyRecentlyUsedCategories,
-                        policyRecentlyUsedTags,
-                        isASAPSubmitBetaEnabled,
-                        transactionViolations: transactionViolationsRef.current,
-                        quickAction,
-                        policyRecentlyUsedCurrencies: policyRecentlyUsedCurrencies ?? [],
-                        betas,
-                        personalDetails,
-                    });
-                }
-                markSubmitExpenseEnd();
-                return;
-            }
-
-            // If the split expense is created from the global create menu, we also navigate the user to the group report
-            if (iouType === CONST.IOU.TYPE.SPLIT) {
-                if (currentUserPersonalDetails.login && !!transaction) {
-                    splitBillAndOpenReport({
-                        participants: splitParticipants,
-                        currentUserLogin: currentUserPersonalDetails.login,
-                        currentUserAccountID: currentUserPersonalDetails.accountID,
-                        amount: transaction.amount,
-                        comment: trimmedComment,
-                        currency: transaction.currency,
-                        merchant: transaction.merchant,
-                        created: transaction.created,
-                        category: transaction.category,
-                        tag: transaction.tag,
-                        billable: !!transaction.billable,
-                        reimbursable: !!transaction.reimbursable,
-                        iouRequestType: transaction.iouRequestType,
-                        splitShares: transaction.splitShares,
-                        taxCode: transactionTaxCode,
-                        taxAmount: transactionTaxAmount,
-                        taxValue: transactionTaxValue,
-                        policyRecentlyUsedCategories,
-                        policyRecentlyUsedTags,
-                        isASAPSubmitBetaEnabled,
-                        transactionViolations: transactionViolationsRef.current,
-                        quickAction,
-                        policyRecentlyUsedCurrencies: policyRecentlyUsedCurrencies ?? [],
-                        betas,
-                        personalDetails,
-                    });
-                }
-                markSubmitExpenseEnd();
-                return;
-            }
-
-            if (iouType === CONST.IOU.TYPE.INVOICE) {
-                const invoiceChatReport = !isEmptyObject(report) && report?.reportID ? report : existingInvoiceReport;
-                const invoiceChatReportID = invoiceChatReport ? undefined : reportID;
-
-                sendInvoice({
-                    currentUserAccountID: currentUserPersonalDetails.accountID,
-                    transaction,
-                    policyRecentlyUsedCurrencies: policyRecentlyUsedCurrencies ?? [],
-                    invoiceChatReport,
-                    invoiceChatReportID,
-                    receiptFile: currentTransactionReceiptFile,
-                    policy,
-                    policyTagList: policyTags,
-                    policyCategories,
-                    policyRecentlyUsedCategories,
-                    isFromGlobalCreate: transaction?.isFromFloatingActionButton ?? transaction?.isFromGlobalCreate,
-                    policyRecentlyUsedTags,
-                    senderPolicyTags: senderWorkspacePolicyTags ?? {},
-                });
-                markSubmitExpenseEnd();
-                return;
-            }
-
-            if (!isPerDiemRequest && (iouType === CONST.IOU.TYPE.TRACK || isCategorizingTrackExpense || isSharingTrackExpense)) {
-                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) {
-                        if (userLocation) {
-                            trackExpense(selectedParticipants, shouldHandleNavigation, {
-                                lat: userLocation.latitude,
-                                long: userLocation.longitude,
-                            });
-                            markSubmitExpenseEnd();
-                            return;
-                        }
-
-                        getCurrentPositionWithGeolocationSpan((gpsCoords) => trackExpense(selectedParticipants, shouldHandleNavigation, gpsCoords));
-                        return;
-                    }
-
-                    // Otherwise, the money is being requested through the "Manual" flow with an attached image and the GPS coordinates are not needed.
-                    trackExpense(selectedParticipants, shouldHandleNavigation);
-                    markSubmitExpenseEnd();
-                    return;
-                }
-                trackExpense(selectedParticipants, shouldHandleNavigation);
-                markSubmitExpenseEnd();
-                return;
-            }
-
-            if (isPerDiemRequest) {
-                submitPerDiemExpense(selectedParticipants, trimmedComment, shouldHandleNavigation, policyRecentlyUsedCategories);
-                markSubmitExpenseEnd();
-                return;
-            }
-
-            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 &&
-                    !selectedParticipants.some((participant) => isSelectedManagerMcTest(participant.login))
-                ) {
-                    if (userLocation) {
-                        requestMoney(selectedParticipants, shouldHandleNavigation, {
-                            lat: userLocation.latitude,
-                            long: userLocation.longitude,
-                        });
-                        markSubmitExpenseEnd();
-                        return;
-                    }
-
-                    getCurrentPositionWithGeolocationSpan((gpsCoords) => requestMoney(selectedParticipants, shouldHandleNavigation, gpsCoords));
-                    return;
-                }
-
-                // Otherwise, the money is being requested through the "Manual" flow with an attached image and the GPS coordinates are not needed.
-                requestMoney(selectedParticipants, shouldHandleNavigation);
-                markSubmitExpenseEnd();
-                return;
-            }
-
-            requestMoney(selectedParticipants, shouldHandleNavigation);
-            markSubmitExpenseEnd();
-        },
-        [
-            iouType,
-            transaction,
-            isDistanceRequest,
-            isMovingTransactionFromTrackExpense,
-            isUnreported,
-            receiptFiles,
-            isCategorizingTrackExpense,
-            isSharingTrackExpense,
-            isPerDiemRequest,
-            requestMoney,
-            createDistanceRequest,
-            currentUserPersonalDetails.login,
-            currentUserPersonalDetails.accountID,
-            transactions,
-            report,
-            transactionTaxCode,
-            transactionTaxAmount,
-            transactionTaxValue,
-            policyRecentlyUsedCategories,
-            policyRecentlyUsedTags,
-            quickAction,
-            isASAPSubmitBetaEnabled,
-            existingInvoiceReport,
-            policy,
-            policyTags,
-            senderWorkspacePolicyTags,
-            policyCategories,
-            trackExpense,
-            userLocation,
-            submitPerDiemExpense,
-            policyRecentlyUsedCurrencies,
-            reportID,
-            betas,
-            participantsPolicyTags,
-            personalDetails,
-        ],
-    );
-
-    /**
-     * Checks if user has a GOLD wallet then creates a paid IOU report on the fly
-     */
-    const sendMoney = useCallback(
-        (paymentMethod: PaymentMethodType | undefined) => {
-            const currency = transaction?.currency;
-            const trimmedComment = transaction?.comment?.comment?.trim() ?? '';
-            const participant = participants?.at(0);
-
-            if (!participant || !transaction?.amount || !currency) {
-                return;
-            }
-
-            const {optimisticChatReportID, chatReportID} = resolveOptimisticChatReportID([participant.accountID ?? CONST.DEFAULT_NUMBER_ID, currentUserPersonalDetails.accountID], report);
-            const sendMoneyParams = {
-                report,
-                quickAction,
-                amount: transaction.amount,
-                currency,
-                comment: trimmedComment,
-                currentUserAccountID: currentUserPersonalDetails.accountID,
-                recipient: participant,
-                created: transaction.created,
-                merchant: transaction.merchant,
-                receipt: receiptFiles[transaction.transactionID],
-                optimisticChatReportID,
-            };
-
-            if (paymentMethod === CONST.IOU.PAYMENT_TYPE.ELSEWHERE) {
-                setIsConfirmed(true);
-                sendMoneyElsewhere(sendMoneyParams);
-            } else if (paymentMethod === CONST.IOU.PAYMENT_TYPE.EXPENSIFY) {
-                setIsConfirmed(true);
-                sendMoneyWithWallet(sendMoneyParams);
-            } else {
-                return;
-            }
-            dismissModalAndOpenReportInInboxTabHelper(chatReportID, undefined, reportTransactions.length > 0);
-        },
-        [
-            transaction?.currency,
-            transaction?.comment?.comment,
-            transaction?.amount,
-            transaction?.created,
-            transaction?.merchant,
-            transaction?.transactionID,
-            participants,
-            report,
-            currentUserPersonalDetails.accountID,
-            receiptFiles,
-            quickAction,
-            reportTransactions.length,
-        ],
-    );
-
     const setBillable = useCallback(
         (billable: boolean) => {
             setMoneyRequestBillable(currentTransactionID, billable);
diff --git a/src/pages/iou/request/step/confirmation/useExpenseSubmission.ts b/src/pages/iou/request/step/confirmation/useExpenseSubmission.ts
new file mode 100644
index 000000000000..af62fd1c96ed
--- /dev/null
+++ b/src/pages/iou/request/step/confirmation/useExpenseSubmission.ts
@@ -0,0 +1,851 @@
+import {delegateEmailSelector} from '@selectors/Account';
+import {hasSeenTourSelector} from '@selectors/Onboarding';
+import {useEffect, useRef, useState} from 'react';
+import type {OnyxEntry} from 'react-native-onyx';
+import useLocalize from '@hooks/useLocalize';
+import useOnboardingTaskInformation from '@hooks/useOnboardingTaskInformation';
+import useOnyx from '@hooks/useOnyx';
+import useParentReportAction from '@hooks/useParentReportAction';
+import useParticipantsInvoiceReport from '@hooks/useParticipantsInvoiceReport';
+import useParticipantsPolicyTags from '@hooks/useParticipantsPolicyTags';
+import usePermissions from '@hooks/usePermissions';
+import useReportTransactions from '@hooks/useReportTransactions';
+import {completeTestDriveTask} from '@libs/actions/Task';
+import {getCurrencySymbol} from '@libs/CurrencyUtils';
+import DistanceRequestUtils from '@libs/DistanceRequestUtils';
+import getCurrentPosition from '@libs/getCurrentPosition';
+import {getGPSCoordinates} from '@libs/GPSDraftDetailsUtils';
+import {getExistingTransactionID, resolveOptimisticChatReportID} from '@libs/IOUUtils';
+import Log from '@libs/Log';
+import dismissModalAndOpenReportInInboxTabHelper from '@libs/Navigation/helpers/dismissModalAndOpenReportInInboxTab';
+import navigateAfterExpenseCreate from '@libs/Navigation/helpers/navigateAfterExpenseCreate';
+import Navigation from '@libs/Navigation/Navigation';
+import {rand64, roundToTwoDecimalPlaces} from '@libs/NumberUtils';
+import {findSelfDMReportID, generateReportID, getReportOrDraftReport, hasViolations as hasViolationsReportUtils, isMoneyRequestReport, isSelectedManagerMcTest} from '@libs/ReportUtils';
+import {endSpan, getSpan, startSpan} from '@libs/telemetry/activeSpans';
+import markSubmitExpenseEnd from '@libs/telemetry/markSubmitExpenseEnd';
+import {
+    getDefaultTaxCode,
+    getRateID,
+    getTaxValue,
+    getValidWaypoints,
+    isGPSDistanceRequest as isGPSDistanceRequestTransactionUtils,
+    isManualDistanceRequest as isManualDistanceRequestTransactionUtils,
+} from '@libs/TransactionUtils';
+import type {GpsPoint} from '@userActions/IOU';
+import {createDistanceRequest as createDistanceRequestIOUActions} from '@userActions/IOU';
+import {submitPerDiemExpenseForSelfDM, submitPerDiemExpense as submitPerDiemExpenseIOUActions} from '@userActions/IOU/PerDiem';
+import {getReceiverType, sendInvoice} from '@userActions/IOU/SendInvoice';
+import {sendMoneyElsewhere, sendMoneyWithWallet} from '@userActions/IOU/SendMoney';
+import {splitBill, splitBillAndOpenReport, startSplitBill} from '@userActions/IOU/Split';
+import {requestMoney as requestMoneyIOUActions, trackExpense as trackExpenseIOUActions} from '@userActions/IOU/TrackExpense';
+import CONST from '@src/CONST';
+import ONYXKEYS from '@src/ONYXKEYS';
+import type {PersonalDetailsList, PolicyCategories, RecentlyUsedCategories, Report} from '@src/types/onyx';
+import type {Participant} from '@src/types/onyx/IOU';
+import type {PaymentMethodType} from '@src/types/onyx/OriginalMessage';
+import type Policy from '@src/types/onyx/Policy';
+import type {Receipt} from '@src/types/onyx/Transaction';
+import type Transaction from '@src/types/onyx/Transaction';
+import type DeepValueOf from '@src/types/utils/DeepValueOf';
+import {isEmptyObject} from '@src/types/utils/EmptyObject';
+
+// Ends the submit expense span, starts a geolocation child span, then calls getCurrentPosition.
+// The expense callback receives GPS coordinates on success or undefined on error.
+// Extracted to avoid duplicating this identical telemetry block across trackExpense and requestMoney paths.
+function getCurrentPositionWithGeolocationSpan(onPosition: (gpsCoords?: {lat: number; long: number}) => void) {
+    const parentSpan = getSpan(CONST.TELEMETRY.SPAN_SUBMIT_EXPENSE);
+    markSubmitExpenseEnd();
+
+    startSpan(CONST.TELEMETRY.SPAN_GEOLOCATION_WAIT, {
+        name: CONST.TELEMETRY.SPAN_GEOLOCATION_WAIT,
+        op: CONST.TELEMETRY.SPAN_GEOLOCATION_WAIT,
+        parentSpan,
+    });
+
+    getCurrentPosition(
+        (successData) => {
+            onPosition({lat: successData.coords.latitude, long: successData.coords.longitude});
+            endSpan(CONST.TELEMETRY.SPAN_GEOLOCATION_WAIT);
+        },
+        (errorData) => {
+            Log.info('[useExpenseSubmission] getCurrentPosition failed', false, errorData);
+            onPosition();
+            endSpan(CONST.TELEMETRY.SPAN_GEOLOCATION_WAIT);
+        },
+    );
+}
+
+type UseExpenseSubmissionParams = {
+    // Transaction data
+    transaction: OnyxEntry<Transaction>;
+    transactions: Transaction[];
+    receiptFiles: Record<string, Receipt>;
+
+    // Report data
+    report: OnyxEntry<Report>;
+    reportID: string;
+
+    // Policy data
+    policy: OnyxEntry<Policy>;
+    policyCategories: OnyxEntry<PolicyCategories>;
+    isDraftPolicy: boolean;
+
+    // User data
+    currentUserPersonalDetails: {accountID: number; login?: string; email?: string};
+    personalDetails: OnyxEntry<PersonalDetailsList>;
+    participants: Participant[];
+
+    // Request type flags
+    iouType: DeepValueOf<typeof CONST.IOU.TYPE>;
+    action: DeepValueOf<typeof CONST.IOU.ACTION>;
+    requestType: DeepValueOf<typeof CONST.IOU.REQUEST_TYPE> | undefined;
+    isDistanceRequest: boolean;
+    isManualDistanceRequest: boolean;
+    isOdometerDistanceRequest: boolean;
+    isPerDiemRequest: boolean;
+    isTimeRequest: boolean;
+    isMovingTransactionFromTrackExpense: boolean;
+    isCategorizingTrackExpense: boolean;
+    isSharingTrackExpense: boolean;
+    isUnreported: boolean;
+
+    // Onyx values
+    draftTransactionIDs: string[] | undefined;
+    privateIsArchivedMap: Record<string, boolean | undefined>;
+
+    // Navigation
+    backToReport?: string;
+};
+
+function useExpenseSubmission(params: UseExpenseSubmissionParams) {
+    const {
+        transaction,
+        transactions,
+        receiptFiles,
+        report,
+        reportID,
+        policy,
+        policyCategories,
+        isDraftPolicy,
+        currentUserPersonalDetails,
+        personalDetails,
+        participants,
+        iouType,
+        action,
+        isDistanceRequest,
+        isManualDistanceRequest,
+        isOdometerDistanceRequest,
+        isPerDiemRequest,
+        isTimeRequest,
+        isMovingTransactionFromTrackExpense,
+        isCategorizingTrackExpense,
+        isSharingTrackExpense,
+        isUnreported,
+        draftTransactionIDs,
+        privateIsArchivedMap,
+        backToReport,
+    } = params;
+
+    // Localization
+    const {translate, toLocaleDigit} = useLocalize();
+
+    // Permissions
+    const {isBetaEnabled} = usePermissions();
+    const isASAPSubmitBetaEnabled = isBetaEnabled(CONST.BETAS.ASAP_SUBMIT);
+    const shouldGenerateTransactionThreadReport = false;
+
+    // UI state
+    const [isConfirmed, setIsConfirmed] = useState(false);
+    const formHasBeenSubmitted = useRef(false);
+
+    // Transaction violations – ref keeps callbacks always reading the latest value without re-creating them.
+    const [transactionViolations] = useOnyx(ONYXKEYS.COLLECTION.TRANSACTION_VIOLATIONS);
+    const transactionViolationsRef = useRef(transactionViolations);
+    useEffect(() => {
+        transactionViolationsRef.current = transactionViolations;
+    }, [transactionViolations]);
+    const hasViolations = hasViolationsReportUtils(report?.reportID, transactionViolations, currentUserPersonalDetails.accountID, currentUserPersonalDetails.login ?? '');
+
+    // Policy-scoped Onyx data
+    const policyID = policy?.id;
+    const [policyTags] = useOnyx(`${ONYXKEYS.COLLECTION.POLICY_TAGS}${policyID}`);
+    const [policyRecentlyUsedCategories] = useOnyx(`${ONYXKEYS.COLLECTION.POLICY_RECENTLY_USED_CATEGORIES}${policyID}`);
+    const [policyRecentlyUsedTags] = useOnyx(`${ONYXKEYS.COLLECTION.POLICY_RECENTLY_USED_TAGS}${policyID}`);
+    const [policyRecentlyUsedCurrenciesOnyx] = useOnyx(ONYXKEYS.RECENTLY_USED_CURRENCIES);
+    const policyRecentlyUsedCurrencies = policyRecentlyUsedCurrenciesOnyx ?? [];
+    const [recentlyUsedDestinations] = useOnyx(`${ONYXKEYS.COLLECTION.POLICY_RECENTLY_USED_DESTINATIONS}${policyID}`);
+
+    // Reports
+    const [selfDMReport] = useOnyx(`${ONYXKEYS.COLLECTION.REPORT}${findSelfDMReportID()}`);
+    const reportTransactions = useReportTransactions(report?.reportID);
+
+    // Invoice data
+    const receiverParticipant = transaction?.participants?.find((p) => p?.accountID) ?? report?.invoiceReceiver;
+    const receiverAccountID = receiverParticipant && 'accountID' in receiverParticipant && receiverParticipant.accountID ? receiverParticipant.accountID : CONST.DEFAULT_NUMBER_ID;
+    const receiverType = getReceiverType(receiverParticipant);
+    const senderWorkspaceID = transaction?.participants?.find((p) => p?.isSender)?.policyID;
+    const [senderWorkspacePolicyTags] = useOnyx(`${ONYXKEYS.COLLECTION.POLICY_TAGS}${senderWorkspaceID}`);
+    const existingInvoiceReport = useParticipantsInvoiceReport(receiverAccountID, receiverType, senderWorkspaceID);
+
+    // Policy tags from participants
+    const participantsPolicyTags = useParticipantsPolicyTags(participants ?? []);
+
+    // Global Onyx values
+    const [userLocation] = useOnyx(ONYXKEYS.USER_LOCATION);
+    const [quickAction] = useOnyx(ONYXKEYS.NVP_QUICK_ACTION_GLOBAL_CREATE);
+    const [isSelfTourViewed = false] = useOnyx(ONYXKEYS.NVP_ONBOARDING, {selector: hasSeenTourSelector});
+    const [introSelected] = useOnyx(ONYXKEYS.NVP_INTRO_SELECTED);
+    const [activePolicyID] = useOnyx(ONYXKEYS.NVP_ACTIVE_POLICY_ID);
+    const [betas] = useOnyx(ONYXKEYS.BETAS);
+    const [gpsDraftDetails] = useOnyx(ONYXKEYS.GPS_DRAFT_DETAILS);
+    const [recentWaypoints] = useOnyx(ONYXKEYS.NVP_RECENT_WAYPOINTS);
+    const [delegateEmail] = useOnyx(ONYXKEYS.ACCOUNT, {selector: delegateEmailSelector});
+
+    // Onboarding task data
+    const {
+        taskReport: viewTourTaskReport,
+        taskParentReport: viewTourTaskParentReport,
+        isOnboardingTaskParentReportArchived: isViewTourTaskParentReportArchived,
+        hasOutstandingChildTask,
+    } = useOnboardingTaskInformation(CONST.ONBOARDING_TASK_TYPE.VIEW_TOUR);
+    const parentReportAction = useParentReportAction(viewTourTaskReport);
+
+    // Derived values from transaction
+    const isGPSDistanceRequest = isGPSDistanceRequestTransactionUtils(transaction);
+    const customUnitRateID = getRateID(transaction) ?? '';
+    const transactionDistance = isManualDistanceRequest || isOdometerDistanceRequest || isGPSDistanceRequest ? (transaction?.comment?.customUnit?.quantity ?? undefined) : undefined;
+    const defaultTaxCode = getDefaultTaxCode(policy, transaction);
+    const transactionTaxCode = (transaction?.taxCode ? transaction?.taxCode : defaultTaxCode) ?? '';
+    const transactionTaxAmount = transaction?.taxAmount ?? 0;
+    const transactionTaxValue = transaction?.taxValue ?? getTaxValue(policy, transaction, transactionTaxCode) ?? '';
+
+    function requestMoney(selectedParticipantsArg: Participant[], shouldHandleNav: boolean, gpsPoint?: GpsPoint) {
+        if (!transactions.length) {
+            return;
+        }
+
+        const participant = selectedParticipantsArg.at(0);
+        if (!participant) {
+            return;
+        }
+
+        const optimisticChatReportID = generateReportID();
+        const optimisticCreatedReportActionID = rand64();
+        const optimisticReportPreviewActionID = rand64();
+        let existingIOUReport: Report | undefined;
+
+        for (const [index, item] of transactions.entries()) {
+            const receipt = receiptFiles[item.transactionID];
+            const isTestReceipt = receipt?.isTestReceipt ?? false;
+            const isTestDriveReceipt = receipt?.isTestDriveReceipt ?? false;
+            const isLinkedTrackedExpenseReportArchived =
+                !!item.linkedTrackedExpenseReportID && privateIsArchivedMap[`${ONYXKEYS.COLLECTION.REPORT_NAME_VALUE_PAIRS}${item.linkedTrackedExpenseReportID}`];
+
+            const itemAmount = isTestReceipt ? CONST.TEST_RECEIPT.AMOUNT : item.amount;
+            const itemCurrency = isTestReceipt ? CONST.TEST_RECEIPT.CURRENCY : item.currency;
+
+            if (isTestDriveReceipt) {
+                completeTestDriveTask(
+                    viewTourTaskReport,
+                    viewTourTaskParentReport,
+                    isViewTourTaskParentReportArchived,
+                    currentUserPersonalDetails.accountID,
+                    hasOutstandingChildTask,
+                    parentReportAction,
+                    delegateEmail,
+                    false,
+                );
+            }
+
+            const existingTransactionID = getExistingTransactionID(item.linkedTrackedExpenseReportAction);
+            const existingTransactionDraft = transactions.find((tx) => tx.transactionID === existingTransactionID);
+            let merchantToUse = isTestReceipt ? CONST.TEST_RECEIPT.MERCHANT : item.merchant;
+            if (!isTestReceipt && isManualDistanceRequestTransactionUtils(item)) {
+                const distance = item.comment?.customUnit?.quantity;
+                const unit = item.comment?.customUnit?.distanceUnit;
+                const rate = item.comment?.customUnit?.defaultP2PRate;
+                if (distance && unit && rate) {
+                    // Convert distance to meters
+                    const distanceInMeters = DistanceRequestUtils.convertToDistanceInMeters(distance, unit);
+                    merchantToUse = DistanceRequestUtils.getDistanceMerchant(
+                        true,
+                        distanceInMeters,
+                        unit,
+                        rate,
+                        item.currency ?? CONST.CURRENCY.USD,
+                        translate,
+                        toLocaleDigit,
+                        getCurrencySymbol,
+                    );
+                }
+            }
+
+            const {iouReport} = requestMoneyIOUActions({
+                report,
+                existingIOUReport,
+                optimisticChatReportID,
+                optimisticCreatedReportActionID,
+                optimisticReportPreviewActionID,
+                participantParams: {
+                    payeeEmail: currentUserPersonalDetails.login,
+                    payeeAccountID: currentUserPersonalDetails.accountID,
+                    participant,
+                },
+                policyParams: {
+                    policy,
+                    policyTagList: policyTags,
+                    policyCategories,
+                    policyRecentlyUsedCategories,
+                    policyRecentlyUsedTags,
+                },
+                gpsPoint,
+                action,
+                transactionParams: {
+                    amount: itemAmount,
+                    distance: isManualDistanceRequest && typeof item.comment?.customUnit?.quantity === 'number' ? roundToTwoDecimalPlaces(item.comment.customUnit.quantity) : undefined,
+                    attendees: item.comment?.attendees,
+                    currency: itemCurrency,
+                    created: item.created,
+                    merchant: merchantToUse,
+                    comment: item?.comment?.comment?.trim() ?? '',
+                    receipt,
+                    category: item.category,
+                    tag: item.tag,
+                    taxCode: transactionTaxCode,
+                    taxAmount: transactionTaxAmount,
+                    taxValue: transactionTaxValue,
+                    billable: item.billable,
+                    reimbursable: item.reimbursable,
+                    actionableWhisperReportActionID: item.actionableWhisperReportActionID,
+                    linkedTrackedExpenseReportAction: item.linkedTrackedExpenseReportAction,
+                    linkedTrackedExpenseReportID: item.linkedTrackedExpenseReportID,
+                    waypoints: Object.keys(item.comment?.waypoints ?? {}).length ? getValidWaypoints(item.comment?.waypoints, true, isGPSDistanceRequest) : undefined,
+                    customUnitRateID,
+                    isTestDrive: item.receipt?.isTestDriveReceipt,
+                    originalTransactionID: item.comment?.originalTransactionID,
+                    source: item.comment?.source,
+                    isLinkedTrackedExpenseReportArchived,
+                    isFromGlobalCreate: item?.isFromFloatingActionButton ?? item?.isFromGlobalCreate,
+                    ...(isTimeRequest ? {type: CONST.TRANSACTION.TYPE.TIME, count: item.comment?.units?.count, rate: item.comment?.units?.rate, unit: CONST.TIME_TRACKING.UNIT.HOUR} : {}),
+                },
+                shouldHandleNavigation: shouldHandleNav && index === transactions.length - 1,
+                shouldGenerateTransactionThreadReport,
+                backToReport,
+                isASAPSubmitBetaEnabled,
+                currentUserAccountIDParam: currentUserPersonalDetails.accountID,
+                currentUserEmailParam: currentUserPersonalDetails.email ?? '',
+                transactionViolations: transactionViolationsRef.current,
+                policyRecentlyUsedCurrencies,
+                quickAction,
+                existingTransactionDraft,
+                draftTransactionIDs,
+                isSelfTourViewed,
+                betas,
+                personalDetails,
+            });
+            existingIOUReport = iouReport;
+        }
+    }
+
+    function submitPerDiemExpense(selectedParticipantsArg: Participant[], trimmedComment: string, shouldHandleNav: boolean, policyRecentlyUsedCategoriesParam?: RecentlyUsedCategories) {
+        if (!transaction) {
+            return;
+        }
+
+        const participant = selectedParticipantsArg.at(0);
+        if (!participant || isEmptyObject(transaction.comment) || isEmptyObject(transaction.comment.customUnit)) {
+            return;
+        }
+        if (iouType === CONST.IOU.TYPE.TRACK) {
+            submitPerDiemExpenseForSelfDM({
+                selfDMReport,
+                policy,
+                transactionParams: {
+                    currency: transaction.currency,
+                    created: transaction.created,
+                    comment: trimmedComment,
+                    category: transaction.category,
+                    tag: transaction.tag,
+                    customUnit: transaction.comment?.customUnit,
+                    billable: transaction.billable,
+                    reimbursable: transaction.reimbursable,
+                    attendees: transaction.comment?.attendees,
+                    isFromGlobalCreate: transaction.isFromFloatingActionButton ?? transaction.isFromGlobalCreate,
+                },
+                currentUserAccountIDParam: currentUserPersonalDetails.accountID,
+                currentUserEmailParam: currentUserPersonalDetails.login ?? '',
+                quickAction,
+            });
+        } else {
+            const isExpenseReport = isMoneyRequestReport(report);
+            let existingChatReport = report;
+            if (isExpenseReport) {
+                existingChatReport = getReportOrDraftReport(report?.chatReportID);
+            } else if (!report?.reportID && participant.isPolicyExpenseChat && participant.reportID) {
+                existingChatReport = getReportOrDraftReport(participant.reportID);
+            }
+            const {optimisticChatReportID, chatReportID} = resolveOptimisticChatReportID(
+                [participant.accountID ?? CONST.DEFAULT_NUMBER_ID, currentUserPersonalDetails.accountID],
+                existingChatReport,
+            );
+            const activeReportID = isExpenseReport && Navigation.getTopmostReportId() === report?.reportID ? report?.reportID : chatReportID;
+
+            const result = submitPerDiemExpenseIOUActions({
+                report,
+                participantParams: {
+                    payeeEmail: currentUserPersonalDetails.login,
+                    payeeAccountID: currentUserPersonalDetails.accountID,
+                    participant,
+                },
+                policyParams: {
+                    policy,
+                    policyTagList: policyTags,
+                    policyRecentlyUsedTags,
+                    policyCategories,
+                    policyRecentlyUsedCategories: policyRecentlyUsedCategoriesParam,
+                },
+                recentlyUsedParams: {
+                    destinations: recentlyUsedDestinations,
+                },
+                transactionParams: {
+                    currency: transaction.currency,
+                    created: transaction.created,
+                    comment: trimmedComment,
+                    category: transaction.category,
+                    tag: transaction.tag,
+                    customUnit: transaction.comment?.customUnit,
+                    billable: transaction.billable,
+                    reimbursable: transaction.reimbursable,
+                    attendees: transaction.comment?.attendees,
+                    isFromGlobalCreate: transaction.isFromFloatingActionButton ?? transaction.isFromGlobalCreate,
+                },
+                isASAPSubmitBetaEnabled,
+                currentUserAccountIDParam: currentUserPersonalDetails.accountID,
+                currentUserEmailParam: currentUserPersonalDetails.login ?? '',
+                hasViolations,
+                policyRecentlyUsedCurrencies,
+                quickAction,
+                betas,
+                personalDetails,
+                optimisticChatReportID,
+            });
+            if (shouldHandleNav && result && activeReportID) {
+                navigateAfterExpenseCreate({
+                    activeReportID,
+                    transactionID: transaction.transactionID,
+                    isFromGlobalCreate: transaction.isFromFloatingActionButton ?? transaction.isFromGlobalCreate,
+                    hasMultipleTransactions: reportTransactions.length > 0,
+                });
+            }
+        }
+    }
+
+    function trackExpense(selectedParticipantsArg: Participant[], shouldHandleNav: boolean, gpsPoint?: GpsPoint) {
+        if (!transactions.length) {
+            return;
+        }
+        const participant = selectedParticipantsArg.at(0);
+        if (!participant) {
+            return;
+        }
+        for (const [index, item] of transactions.entries()) {
+            const isLinkedTrackedExpenseReportArchived =
+                !!item.linkedTrackedExpenseReportID && privateIsArchivedMap[`${ONYXKEYS.COLLECTION.REPORT_NAME_VALUE_PAIRS}${item.linkedTrackedExpenseReportID}`];
+            const itemDistance = isManualDistanceRequest || isOdometerDistanceRequest || isGPSDistanceRequest ? (item.comment?.customUnit?.quantity ?? undefined) : undefined;
+
+            trackExpenseIOUActions({
+                report,
+                isDraftPolicy,
+                action,
+                participantParams: {
+                    payeeEmail: currentUserPersonalDetails.login,
+                    payeeAccountID: currentUserPersonalDetails.accountID,
+                    participant,
+                },
+                policyParams: {
+                    policy,
+                    policyCategories,
+                    policyTagList: policyTags,
+                },
+                transactionParams: {
+                    amount: item.amount,
+                    distance: itemDistance,
+                    currency: item.currency,
+                    created: item.created,
+                    merchant: item.merchant,
+                    comment: item?.comment?.comment?.trim() ?? '',
+                    receipt: receiptFiles[item.transactionID],
+                    category: item.category,
+                    tag: item.tag,
+                    taxCode: transactionTaxCode,
+                    taxAmount: transactionTaxAmount,
+                    taxValue: transactionTaxValue,
+                    billable: item.billable,
+                    reimbursable: item.reimbursable,
+                    gpsPoint,
+                    validWaypoints: Object.keys(item?.comment?.waypoints ?? {}).length ? getValidWaypoints(item.comment?.waypoints, true, isGPSDistanceRequest) : undefined,
+                    actionableWhisperReportActionID: item.actionableWhisperReportActionID,
+                    linkedTrackedExpenseReportAction: item.linkedTrackedExpenseReportAction,
+                    linkedTrackedExpenseReportID: item.linkedTrackedExpenseReportID,
+                    customUnitRateID,
+                    attendees: item.comment?.attendees,
+                    isLinkedTrackedExpenseReportArchived,
+                    odometerStart: isOdometerDistanceRequest ? item.comment?.odometerStart : undefined,
+                    odometerEnd: isOdometerDistanceRequest ? item.comment?.odometerEnd : undefined,
+                    isFromGlobalCreate: item?.isFromFloatingActionButton ?? item?.isFromGlobalCreate,
+                    gpsCoordinates: isGPSDistanceRequest ? getGPSCoordinates(gpsDraftDetails) : undefined,
+                },
+                accountantParams: {
+                    accountant: item.accountant,
+                },
+                shouldHandleNavigation: shouldHandleNav && index === transactions.length - 1,
+                isASAPSubmitBetaEnabled,
+                currentUserAccountIDParam: currentUserPersonalDetails.accountID,
+                currentUserEmailParam: currentUserPersonalDetails.login ?? '',
+                introSelected,
+                activePolicyID,
+                quickAction,
+                recentWaypoints,
+                betas,
+                draftTransactionIDs,
+                isSelfTourViewed,
+            });
+        }
+    }
+
+    function createDistanceRequest(selectedParticipantsArg: Participant[], trimmedComment: string, shouldHandleNav = true) {
+        if (!transaction) {
+            return;
+        }
+
+        createDistanceRequestIOUActions({
+            report,
+            participants: selectedParticipantsArg,
+            currentUserLogin: currentUserPersonalDetails.login,
+            currentUserAccountID: currentUserPersonalDetails.accountID,
+            iouType,
+            existingTransaction: transaction,
+            policyParams: {
+                policy,
+                policyCategories,
+                policyTagList: policyTags,
+                policyRecentlyUsedCategories,
+                policyRecentlyUsedTags,
+            },
+            transactionParams: {
+                amount: transaction.amount,
+                comment: trimmedComment,
+                distance: transactionDistance,
+                created: transaction.created,
+                currency: transaction.currency,
+                merchant: transaction.merchant,
+                category: transaction.category,
+                tag: transaction.tag,
+                taxCode: transactionTaxCode,
+                taxAmount: transactionTaxAmount,
+                taxValue: transactionTaxValue,
+                customUnitRateID,
+                splitShares: transaction.splitShares,
+                validWaypoints: getValidWaypoints(transaction.comment?.waypoints, true, isGPSDistanceRequest),
+                billable: transaction.billable,
+                reimbursable: transaction.reimbursable,
+                attendees: transaction.comment?.attendees,
+                receipt: isManualDistanceRequest || isOdometerDistanceRequest ? receiptFiles[transaction.transactionID] : undefined,
+                odometerStart: isOdometerDistanceRequest ? transaction.comment?.odometerStart : undefined,
+                odometerEnd: isOdometerDistanceRequest ? transaction.comment?.odometerEnd : undefined,
+                isFromGlobalCreate: transaction.isFromFloatingActionButton ?? transaction.isFromGlobalCreate,
+                gpsCoordinates: isGPSDistanceRequest ? getGPSCoordinates(gpsDraftDetails) : undefined,
+            },
+            backToReport,
+            isASAPSubmitBetaEnabled,
+            transactionViolations: transactionViolationsRef.current,
+            quickAction,
+            policyRecentlyUsedCurrencies,
+            personalDetails,
+            recentWaypoints,
+            betas,
+            shouldHandleNavigation: shouldHandleNav,
+        });
+    }
+
+    // shouldHandleNavigation is a function parameter, not a closure variable, so it does not
+    // need to appear in any dependency array. The handle* functions pass it at call time
+    // (e.g. createTransaction(participants, false, false) for fast paths).
+    function createTransaction(selectedParticipantsArg: Participant[], locationPermissionGranted = false, shouldHandleNavigation = true) {
+        setIsConfirmed(true);
+        let splitParticipants = selectedParticipantsArg;
+
+        // Filter out participants with an amount equal to O
+        if (iouType === CONST.IOU.TYPE.SPLIT && transaction?.splitShares) {
+            const participantsWithAmount = new Set(
+                Object.keys(transaction.splitShares ?? {})
+                    .filter((accountID: string): boolean => (transaction?.splitShares?.[Number(accountID)]?.amount ?? 0) > 0)
+                    .map((accountID) => Number(accountID)),
+            );
+            splitParticipants = selectedParticipantsArg.filter((participant) =>
+                participantsWithAmount.has(participant.isPolicyExpenseChat ? (participant?.ownerAccountID ?? CONST.DEFAULT_NUMBER_ID) : (participant.accountID ?? CONST.DEFAULT_NUMBER_ID)),
+            );
+        }
+        const trimmedComment = transaction?.comment?.comment?.trim() ?? '';
+
+        // Don't let the form be submitted multiple times while the navigator is waiting to take the user to a different page
+        if (formHasBeenSubmitted.current) {
+            return;
+        }
+
+        formHasBeenSubmitted.current = true;
+
+        // Telemetry spans (SPAN_SUBMIT_EXPENSE, SPAN_SUBMIT_TO_DESTINATION_VISIBLE)
+        // are started by SubmitExpenseOrchestrator before calling createTransaction.
+        if (iouType !== CONST.IOU.TYPE.TRACK && isDistanceRequest && !isMovingTransactionFromTrackExpense && !isUnreported) {
+            createDistanceRequest(iouType === CONST.IOU.TYPE.SPLIT ? splitParticipants : selectedParticipantsArg, trimmedComment, shouldHandleNavigation);
+            markSubmitExpenseEnd();
+            return;
+        }
+
+        const currentTransactionReceiptFile = transaction?.transactionID ? receiptFiles[transaction.transactionID] : undefined;
+
+        // Split (startSplitBill, splitBill, splitBillAndOpenReport) and invoice (sendInvoice)
+        // flows handle their own navigation internally and don't participate in the
+        // dismiss-modal fast path. shouldHandleNavigation is not threaded through to them.
+        if (iouType === CONST.IOU.TYPE.SPLIT && Object.values(receiptFiles).filter((receipt) => !!receipt).length) {
+            const currentUserLogin = currentUserPersonalDetails.login;
+            if (currentUserLogin) {
+                for (const [index, item] of transactions.entries()) {
+                    const transactionReceiptFile = receiptFiles[item.transactionID];
+                    if (!transactionReceiptFile) {
+                        continue;
+                    }
+                    const itemTrimmedComment = item?.comment?.comment?.trim() ?? '';
+
+                    // If we have a receipt let's start the split expense by creating only the action, the transaction, and the group DM if needed
+                    startSplitBill({
+                        participants: selectedParticipantsArg,
+                        currentUserLogin,
+                        currentUserAccountID: currentUserPersonalDetails.accountID,
+                        comment: itemTrimmedComment,
+                        receipt: transactionReceiptFile,
+                        existingSplitChatReportID: report?.reportID,
+                        billable: item.billable,
+                        reimbursable: item.reimbursable,
+                        category: item.category,
+                        tag: item.tag,
+                        currency: item.currency,
+                        taxCode: transactionTaxCode,
+                        taxAmount: transactionTaxAmount,
+                        taxValue: transactionTaxValue,
+                        shouldPlaySound: index === transactions.length - 1,
+                        policyRecentlyUsedCategories,
+                        policyRecentlyUsedTags,
+                        quickAction,
+                        policyRecentlyUsedCurrencies,
+                        participantsPolicyTags,
+                    });
+                }
+            }
+            markSubmitExpenseEnd();
+            return;
+        }
+
+        // IOUs created from a group report will have a reportID param in the route.
+        // Since the user is already viewing the report, we don't need to navigate them to the report
+        if (iouType === CONST.IOU.TYPE.SPLIT && !transaction?.isFromGlobalCreate) {
+            if (currentUserPersonalDetails.login && !!transaction) {
+                splitBill({
+                    participants: splitParticipants,
+                    currentUserLogin: currentUserPersonalDetails.login,
+                    currentUserAccountID: currentUserPersonalDetails.accountID,
+                    amount: transaction.amount,
+                    comment: trimmedComment,
+                    currency: transaction.currency,
+                    merchant: transaction.merchant,
+                    created: transaction.created,
+                    category: transaction.category,
+                    tag: transaction.tag,
+                    existingSplitChatReportID: report?.reportID,
+                    billable: transaction.billable,
+                    reimbursable: transaction.reimbursable,
+                    iouRequestType: transaction.iouRequestType,
+                    splitShares: transaction.splitShares,
+                    taxCode: transactionTaxCode,
+                    taxAmount: transactionTaxAmount,
+                    taxValue: transactionTaxValue,
+                    policyRecentlyUsedCategories,
+                    policyRecentlyUsedTags,
+                    isASAPSubmitBetaEnabled,
+                    transactionViolations: transactionViolationsRef.current,
+                    quickAction,
+                    policyRecentlyUsedCurrencies,
+                    betas,
+                    personalDetails,
+                });
+            }
+            markSubmitExpenseEnd();
+            return;
+        }
+
+        // If the split expense is created from the global create menu, we also navigate the user to the group report
+        if (iouType === CONST.IOU.TYPE.SPLIT) {
+            if (currentUserPersonalDetails.login && !!transaction) {
+                splitBillAndOpenReport({
+                    participants: splitParticipants,
+                    currentUserLogin: currentUserPersonalDetails.login,
+                    currentUserAccountID: currentUserPersonalDetails.accountID,
+                    amount: transaction.amount,
+                    comment: trimmedComment,
+                    currency: transaction.currency,
+                    merchant: transaction.merchant,
+                    created: transaction.created,
+                    category: transaction.category,
+                    tag: transaction.tag,
+                    billable: !!transaction.billable,
+                    reimbursable: !!transaction.reimbursable,
+                    iouRequestType: transaction.iouRequestType,
+                    splitShares: transaction.splitShares,
+                    taxCode: transactionTaxCode,
+                    taxAmount: transactionTaxAmount,
+                    taxValue: transactionTaxValue,
+                    policyRecentlyUsedCategories,
+                    policyRecentlyUsedTags,
+                    isASAPSubmitBetaEnabled,
+                    transactionViolations: transactionViolationsRef.current,
+                    quickAction,
+                    policyRecentlyUsedCurrencies,
+                    betas,
+                    personalDetails,
+                });
+            }
+            markSubmitExpenseEnd();
+            return;
+        }
+
+        if (iouType === CONST.IOU.TYPE.INVOICE) {
+            const invoiceChatReport = !isEmptyObject(report) && report?.reportID ? report : existingInvoiceReport;
+            const invoiceChatReportID = invoiceChatReport ? undefined : reportID;
+
+            sendInvoice({
+                currentUserAccountID: currentUserPersonalDetails.accountID,
+                transaction,
+                policyRecentlyUsedCurrencies,
+                invoiceChatReport,
+                invoiceChatReportID,
+                receiptFile: currentTransactionReceiptFile,
+                policy,
+                policyTagList: policyTags,
+                policyCategories,
+                policyRecentlyUsedCategories,
+                isFromGlobalCreate: transaction?.isFromFloatingActionButton ?? transaction?.isFromGlobalCreate,
+                policyRecentlyUsedTags,
+                senderPolicyTags: senderWorkspacePolicyTags ?? {},
+            });
+            markSubmitExpenseEnd();
+            return;
+        }
+
+        if (!isPerDiemRequest && (iouType === CONST.IOU.TYPE.TRACK || isCategorizingTrackExpense || isSharingTrackExpense)) {
+            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) {
+                    if (userLocation) {
+                        trackExpense(selectedParticipantsArg, shouldHandleNavigation, {
+                            lat: userLocation.latitude,
+                            long: userLocation.longitude,
+                        });
+                        markSubmitExpenseEnd();
+                        return;
+                    }
+
+                    getCurrentPositionWithGeolocationSpan((gpsCoords) => trackExpense(selectedParticipantsArg, shouldHandleNavigation, gpsCoords));
+                    return;
+                }
+
+                // Otherwise, the money is being requested through the "Manual" flow with an attached image and the GPS coordinates are not needed.
+                trackExpense(selectedParticipantsArg, shouldHandleNavigation);
+                markSubmitExpenseEnd();
+                return;
+            }
+            trackExpense(selectedParticipantsArg, shouldHandleNavigation);
+            markSubmitExpenseEnd();
+            return;
+        }
+
+        if (isPerDiemRequest) {
+            submitPerDiemExpense(selectedParticipantsArg, trimmedComment, shouldHandleNavigation, policyRecentlyUsedCategories);
+            markSubmitExpenseEnd();
+            return;
+        }
+
+        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 (userLocation) {
+                    requestMoney(selectedParticipantsArg, shouldHandleNavigation, {
+                        lat: userLocation.latitude,
+                        long: userLocation.longitude,
+                    });
+                    markSubmitExpenseEnd();
+                    return;
+                }
+
+                getCurrentPositionWithGeolocationSpan((gpsCoords) => requestMoney(selectedParticipantsArg, shouldHandleNavigation, gpsCoords));
+                return;
+            }
+
+            // Otherwise, the money is being requested through the "Manual" flow with an attached image and the GPS coordinates are not needed.
+            requestMoney(selectedParticipantsArg, shouldHandleNavigation);
+            markSubmitExpenseEnd();
+            return;
+        }
+
+        requestMoney(selectedParticipantsArg, shouldHandleNavigation);
+        markSubmitExpenseEnd();
+    }
+
+    function sendMoney(paymentMethod: PaymentMethodType | undefined) {
+        const currency = transaction?.currency;
+        const trimmedComment = transaction?.comment?.comment?.trim() ?? '';
+        const participant = participants?.at(0);
+
+        if (!participant || !transaction?.amount || !currency) {
+            return;
+        }
+
+        const {optimisticChatReportID, chatReportID} = resolveOptimisticChatReportID([participant.accountID ?? CONST.DEFAULT_NUMBER_ID, currentUserPersonalDetails.accountID], report);
+        const sendMoneyParams = {
+            report,
+            quickAction,
+            amount: transaction.amount,
+            currency,
+            comment: trimmedComment,
+            currentUserAccountID: currentUserPersonalDetails.accountID,
+            recipient: participant,
+            created: transaction.created,
+            merchant: transaction.merchant,
+            receipt: receiptFiles[transaction.transactionID],
+            optimisticChatReportID,
+        };
+
+        if (paymentMethod === CONST.IOU.PAYMENT_TYPE.ELSEWHERE) {
+            setIsConfirmed(true);
+            sendMoneyElsewhere(sendMoneyParams);
+        } else if (paymentMethod === CONST.IOU.PAYMENT_TYPE.EXPENSIFY) {
+            setIsConfirmed(true);
+            sendMoneyWithWallet(sendMoneyParams);
+        } else {
+            return;
+        }
+        dismissModalAndOpenReportInInboxTabHelper(chatReportID, undefined, reportTransactions.length > 0);
+    }
+
+    return {createTransaction, sendMoney, isConfirmed, formHasBeenSubmitted};
+}
+
+export default useExpenseSubmission;
+export type {UseExpenseSubmissionParams};
