From aea224f92e4c9f58be9161f11964dd77fb38fc16 Mon Sep 17 00:00:00 2001 From: Agata Kosior Date: Wed, 5 Nov 2025 10:27:09 +0100 Subject: [PATCH 01/11] feat: enable tax field --- src/components/MoneyRequestConfirmationList.tsx | 2 +- .../ReportActionItem/MoneyRequestView.tsx | 2 +- src/libs/PolicyUtils.ts | 4 ++-- .../request/step/IOURequestStepTaxRatePage.tsx | 17 ++++++++++++----- 4 files changed, 16 insertions(+), 9 deletions(-) diff --git a/src/components/MoneyRequestConfirmationList.tsx b/src/components/MoneyRequestConfirmationList.tsx index 36e23403eac23..858fcb876c3ba 100755 --- a/src/components/MoneyRequestConfirmationList.tsx +++ b/src/components/MoneyRequestConfirmationList.tsx @@ -337,7 +337,7 @@ function MoneyRequestConfirmationList({ const policyTagLists = useMemo(() => getTagLists(policyTags), [policyTags]); - const shouldShowTax = isTaxTrackingEnabled(isPolicyExpenseChat, policy, isDistanceRequest, isPerDiemRequest); + const shouldShowTax = isTaxTrackingEnabled(isPolicyExpenseChat || isTrackExpense, policy, isDistanceRequest, isPerDiemRequest); // Update the tax code when the default changes (for example, because the transaction currency changed) const defaultTaxCode = getDefaultTaxCode(policy, transaction) ?? ''; diff --git a/src/components/ReportActionItem/MoneyRequestView.tsx b/src/components/ReportActionItem/MoneyRequestView.tsx index 781089d1bad17..986e6b8657f3a 100644 --- a/src/components/ReportActionItem/MoneyRequestView.tsx +++ b/src/components/ReportActionItem/MoneyRequestView.tsx @@ -286,7 +286,7 @@ function MoneyRequestView({ const canEditReimbursable = isEditable && canEditFieldOfMoneyRequest(parentReportAction, CONST.EDIT_REQUEST_FIELD.REIMBURSABLE, undefined, isChatReportArchived); const shouldShowAttendees = useMemo(() => shouldShowAttendeesTransactionUtils(iouType, policy), [iouType, policy]); - const shouldShowTax = isTaxTrackingEnabled(isPolicyExpenseChat, policy, isDistanceRequest, isPerDiemRequest); + const shouldShowTax = isTaxTrackingEnabled(isPolicyExpenseChat || isExpenseUnreported, policy, isDistanceRequest, isPerDiemRequest); const tripID = getTripIDFromTransactionParentReportID(parentReport?.parentReportID); const shouldShowViewTripDetails = hasReservationList(transaction) && !!tripID; diff --git a/src/libs/PolicyUtils.ts b/src/libs/PolicyUtils.ts index a7f4f98cccd47..985b798f6cfef 100644 --- a/src/libs/PolicyUtils.ts +++ b/src/libs/PolicyUtils.ts @@ -560,13 +560,13 @@ function isCollectPolicy(policy: OnyxEntry): boolean { return policy?.type === CONST.POLICY.TYPE.TEAM; } -function isTaxTrackingEnabled(isPolicyExpenseChat: boolean, policy: OnyxEntry, isDistanceRequest: boolean, isPerDiemRequest = false): boolean { +function isTaxTrackingEnabled(isPolicyExpenseChatOrUnreportedExpense: boolean, policy: OnyxEntry, isDistanceRequest: boolean, isPerDiemRequest = false): boolean { if (isPerDiemRequest) { return false; } const distanceUnit = getDistanceRateCustomUnit(policy); const customUnitID = distanceUnit?.customUnitID ?? CONST.DEFAULT_NUMBER_ID; - const isPolicyTaxTrackingEnabled = isPolicyExpenseChat && policy?.tax?.trackingEnabled; + const isPolicyTaxTrackingEnabled = isPolicyExpenseChatOrUnreportedExpense && policy?.tax?.trackingEnabled; const isTaxEnabledForDistance = isPolicyTaxTrackingEnabled && !!customUnitID && policy?.customUnits?.[customUnitID]?.attributes?.taxEnabled; return !!(isDistanceRequest ? isTaxEnabledForDistance : isPolicyTaxTrackingEnabled); diff --git a/src/pages/iou/request/step/IOURequestStepTaxRatePage.tsx b/src/pages/iou/request/step/IOURequestStepTaxRatePage.tsx index a4c8b570a8212..2883a0990afa4 100644 --- a/src/pages/iou/request/step/IOURequestStepTaxRatePage.tsx +++ b/src/pages/iou/request/step/IOURequestStepTaxRatePage.tsx @@ -3,11 +3,12 @@ import type {OnyxEntry} from 'react-native-onyx'; import TaxPicker from '@components/TaxPicker'; import useLocalize from '@hooks/useLocalize'; import useOnyx from '@hooks/useOnyx'; +import usePolicyForMovingExpenses from '@hooks/usePolicyForMovingExpenses'; import useRestartOnReceiptFailure from '@hooks/useRestartOnReceiptFailure'; import {convertToBackendAmount} from '@libs/CurrencyUtils'; import Navigation from '@libs/Navigation/Navigation'; import type {TaxRatesOption} from '@libs/TaxOptionsListUtils'; -import {calculateTaxAmount, getAmount, getCurrency, getTaxName, getTaxValue} from '@libs/TransactionUtils'; +import {calculateTaxAmount, getAmount, getCurrency, getTaxName, getTaxValue, isExpenseUnreported} from '@libs/TransactionUtils'; import {setDraftSplitTransaction, setMoneyRequestTaxAmount, setMoneyRequestTaxRate, updateMoneyRequestTaxRate} from '@userActions/IOU'; import CONST from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; @@ -38,10 +39,16 @@ function IOURequestStepTaxRatePage({ report, }: IOURequestStepTaxRatePageProps) { const {translate} = useLocalize(); + const {policyForMovingExpenses, policyForMovingExpensesID} = usePolicyForMovingExpenses(); + const isUnreportedExpense = isExpenseUnreported(transaction); + const isCreatingTrackExpense = action === CONST.IOU.ACTION.CREATE && iouType === CONST.IOU.TYPE.TRACK; - const [policy] = useOnyx(`${ONYXKEYS.COLLECTION.POLICY}${report?.policyID}`, {canBeMissing: true}); - const [policyCategories] = useOnyx(`${ONYXKEYS.COLLECTION.POLICY_CATEGORIES}${policy?.id}`, {canBeMissing: true}); - const [policyTags] = useOnyx(`${ONYXKEYS.COLLECTION.POLICY_TAGS}${policy?.id}`, {canBeMissing: true}); + const [reportPolicy] = useOnyx(`${ONYXKEYS.COLLECTION.POLICY}${report?.policyID}`, {canBeMissing: true}); + const policy = isUnreportedExpense || isCreatingTrackExpense ? policyForMovingExpenses : reportPolicy; + const policyID = isUnreportedExpense || isCreatingTrackExpense ? policyForMovingExpensesID : reportPolicy?.id; + + const [policyCategories] = useOnyx(`${ONYXKEYS.COLLECTION.POLICY_CATEGORIES}${policyID}`, {canBeMissing: true}); + const [policyTags] = useOnyx(`${ONYXKEYS.COLLECTION.POLICY_TAGS}${policyID}`, {canBeMissing: true}); const [splitDraftTransaction] = useOnyx(`${ONYXKEYS.COLLECTION.SPLIT_TRANSACTION_DRAFT}${transactionID}`, {canBeMissing: true}); useRestartOnReceiptFailure(transaction, reportIDFromRoute, iouType, action); @@ -108,7 +115,7 @@ function IOURequestStepTaxRatePage({ > Date: Thu, 6 Nov 2025 10:42:50 +0100 Subject: [PATCH 02/11] fix: create a hook to avoid code duplication --- src/hooks/usePolicyForTransaction.ts | 39 +++++++++++++++++++ .../step/IOURequestStepTaxAmountPage.tsx | 8 ++-- .../step/IOURequestStepTaxRatePage.tsx | 18 +++------ 3 files changed, 50 insertions(+), 15 deletions(-) create mode 100644 src/hooks/usePolicyForTransaction.ts diff --git a/src/hooks/usePolicyForTransaction.ts b/src/hooks/usePolicyForTransaction.ts new file mode 100644 index 0000000000000..93ea57a6148b1 --- /dev/null +++ b/src/hooks/usePolicyForTransaction.ts @@ -0,0 +1,39 @@ +import type {OnyxEntry} from 'react-native-onyx'; +import useOnyx from '@hooks/useOnyx'; +import usePolicyForMovingExpenses from '@hooks/usePolicyForMovingExpenses'; +import {isExpenseUnreported} from '@libs/TransactionUtils'; +import CONST from '@src/CONST'; +import ONYXKEYS from '@src/ONYXKEYS'; +import type {Policy, Report, Transaction} from '@src/types/onyx'; + +type UsePolicyForTransactionParams = { + /** The transaction to determine the policy for */ + transaction: OnyxEntry; + + /** The report associated with the transaction */ + report: OnyxEntry; + + /** The current action being performed */ + action: string; + + /** The type of IOU (split, track, submit, etc.) */ + iouType: string; +}; + +type UsePolicyForTransactionResult = { + /** The policy to use for the transaction */ + policy: OnyxEntry; +}; + +function usePolicyForTransaction({transaction, report, action, iouType}: UsePolicyForTransactionParams): UsePolicyForTransactionResult { + const {policyForMovingExpenses} = usePolicyForMovingExpenses(); + const isUnreportedExpense = isExpenseUnreported(transaction); + const isCreatingTrackExpense = action === CONST.IOU.ACTION.CREATE && iouType === CONST.IOU.TYPE.TRACK; + + const [reportPolicy] = useOnyx(`${ONYXKEYS.COLLECTION.POLICY}${report?.policyID}`, {canBeMissing: true}); + const policy = isUnreportedExpense || isCreatingTrackExpense ? policyForMovingExpenses : reportPolicy; + + return {policy}; +} + +export default usePolicyForTransaction; diff --git a/src/pages/iou/request/step/IOURequestStepTaxAmountPage.tsx b/src/pages/iou/request/step/IOURequestStepTaxAmountPage.tsx index a6d46ae3740b8..ba71b3722eafe 100644 --- a/src/pages/iou/request/step/IOURequestStepTaxAmountPage.tsx +++ b/src/pages/iou/request/step/IOURequestStepTaxAmountPage.tsx @@ -4,6 +4,7 @@ import type {OnyxEntry} from 'react-native-onyx'; import type {BaseTextInputRef} from '@components/TextInput/BaseTextInput/types'; import useLocalize from '@hooks/useLocalize'; import useOnyx from '@hooks/useOnyx'; +import usePolicyForTransaction from '@hooks/usePolicyForTransaction'; import useRestartOnReceiptFailure from '@hooks/useRestartOnReceiptFailure'; import {setDraftSplitTransaction, setMoneyRequestCurrency, setMoneyRequestParticipantsFromReport, setMoneyRequestTaxAmount, updateMoneyRequestTaxAmount} from '@libs/actions/IOU'; import {convertToBackendAmount, isValidCurrencyCode} from '@libs/CurrencyUtils'; @@ -49,9 +50,10 @@ function IOURequestStepTaxAmountPage({ transaction, report, }: IOURequestStepTaxAmountPageProps) { - const [policy] = useOnyx(`${ONYXKEYS.COLLECTION.POLICY}${report?.policyID}`, {canBeMissing: true}); - const [policyCategories] = useOnyx(`${ONYXKEYS.COLLECTION.POLICY_CATEGORIES}${report?.policyID}`, {canBeMissing: true}); - const [policyTags] = useOnyx(`${ONYXKEYS.COLLECTION.POLICY_TAGS}${report?.policyID}`, {canBeMissing: true}); + const {policy} = usePolicyForTransaction({transaction, report, action, iouType}); + + const [policyCategories] = useOnyx(`${ONYXKEYS.COLLECTION.POLICY_CATEGORIES}${policy?.id}`, {canBeMissing: true}); + const [policyTags] = useOnyx(`${ONYXKEYS.COLLECTION.POLICY_TAGS}${policy?.id}`, {canBeMissing: true}); const [splitDraftTransaction] = useOnyx(`${ONYXKEYS.COLLECTION.SPLIT_TRANSACTION_DRAFT}${transactionID}`, {canBeMissing: true}); const {translate} = useLocalize(); const textInput = useRef(null); diff --git a/src/pages/iou/request/step/IOURequestStepTaxRatePage.tsx b/src/pages/iou/request/step/IOURequestStepTaxRatePage.tsx index 2883a0990afa4..8ff36de59b5da 100644 --- a/src/pages/iou/request/step/IOURequestStepTaxRatePage.tsx +++ b/src/pages/iou/request/step/IOURequestStepTaxRatePage.tsx @@ -3,12 +3,12 @@ import type {OnyxEntry} from 'react-native-onyx'; import TaxPicker from '@components/TaxPicker'; import useLocalize from '@hooks/useLocalize'; import useOnyx from '@hooks/useOnyx'; -import usePolicyForMovingExpenses from '@hooks/usePolicyForMovingExpenses'; +import usePolicyForTransaction from '@hooks/usePolicyForTransaction'; import useRestartOnReceiptFailure from '@hooks/useRestartOnReceiptFailure'; import {convertToBackendAmount} from '@libs/CurrencyUtils'; import Navigation from '@libs/Navigation/Navigation'; import type {TaxRatesOption} from '@libs/TaxOptionsListUtils'; -import {calculateTaxAmount, getAmount, getCurrency, getTaxName, getTaxValue, isExpenseUnreported} from '@libs/TransactionUtils'; +import {calculateTaxAmount, getAmount, getCurrency, getTaxName, getTaxValue} from '@libs/TransactionUtils'; import {setDraftSplitTransaction, setMoneyRequestTaxAmount, setMoneyRequestTaxRate, updateMoneyRequestTaxRate} from '@userActions/IOU'; import CONST from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; @@ -39,16 +39,10 @@ function IOURequestStepTaxRatePage({ report, }: IOURequestStepTaxRatePageProps) { const {translate} = useLocalize(); - const {policyForMovingExpenses, policyForMovingExpensesID} = usePolicyForMovingExpenses(); - const isUnreportedExpense = isExpenseUnreported(transaction); - const isCreatingTrackExpense = action === CONST.IOU.ACTION.CREATE && iouType === CONST.IOU.TYPE.TRACK; + const {policy} = usePolicyForTransaction({transaction, report, action, iouType}); - const [reportPolicy] = useOnyx(`${ONYXKEYS.COLLECTION.POLICY}${report?.policyID}`, {canBeMissing: true}); - const policy = isUnreportedExpense || isCreatingTrackExpense ? policyForMovingExpenses : reportPolicy; - const policyID = isUnreportedExpense || isCreatingTrackExpense ? policyForMovingExpensesID : reportPolicy?.id; - - const [policyCategories] = useOnyx(`${ONYXKEYS.COLLECTION.POLICY_CATEGORIES}${policyID}`, {canBeMissing: true}); - const [policyTags] = useOnyx(`${ONYXKEYS.COLLECTION.POLICY_TAGS}${policyID}`, {canBeMissing: true}); + const [policyCategories] = useOnyx(`${ONYXKEYS.COLLECTION.POLICY_CATEGORIES}${policy?.id}`, {canBeMissing: true}); + const [policyTags] = useOnyx(`${ONYXKEYS.COLLECTION.POLICY_TAGS}${policy?.id}`, {canBeMissing: true}); const [splitDraftTransaction] = useOnyx(`${ONYXKEYS.COLLECTION.SPLIT_TRANSACTION_DRAFT}${transactionID}`, {canBeMissing: true}); useRestartOnReceiptFailure(transaction, reportIDFromRoute, iouType, action); @@ -115,7 +109,7 @@ function IOURequestStepTaxRatePage({ > Date: Thu, 6 Nov 2025 14:43:52 +0100 Subject: [PATCH 03/11] fix: preserve the value, show an error message --- .../MoneyRequestConfirmationList.tsx | 20 +++++++++++++------ .../MoneyRequestConfirmationListFooter.tsx | 14 +++++++++---- .../step/IOURequestStepParticipants.tsx | 6 ++++-- 3 files changed, 28 insertions(+), 12 deletions(-) diff --git a/src/components/MoneyRequestConfirmationList.tsx b/src/components/MoneyRequestConfirmationList.tsx index 858fcb876c3ba..416520b8d258e 100755 --- a/src/components/MoneyRequestConfirmationList.tsx +++ b/src/components/MoneyRequestConfirmationList.tsx @@ -251,6 +251,8 @@ function MoneyRequestConfirmationList({ selector: mileageRateSelector, canBeMissing: true, }); + const {policyForMovingExpenses} = usePolicyForMovingExpenses(); + const isMovingTransactionFromTrackExpense = isMovingTransactionFromTrackExpenseUtil(action); const [defaultMileageRateReal] = useOnyx(`${ONYXKEYS.COLLECTION.POLICY}${policyID}`, { selector: mileageRateSelector, canBeMissing: true, @@ -340,15 +342,14 @@ function MoneyRequestConfirmationList({ const shouldShowTax = isTaxTrackingEnabled(isPolicyExpenseChat || isTrackExpense, policy, isDistanceRequest, isPerDiemRequest); // Update the tax code when the default changes (for example, because the transaction currency changed) - const defaultTaxCode = getDefaultTaxCode(policy, transaction) ?? ''; + const defaultTaxCode = getDefaultTaxCode(policy, transaction) ?? (isMovingTransactionFromTrackExpense ? getDefaultTaxCode(policyForMovingExpenses, transaction) ?? '' : ''); + useEffect(() => { - if (!transactionID) { + if (!transactionID || isMovingTransactionFromTrackExpense) { return; } setMoneyRequestTaxRate(transactionID, defaultTaxCode); - }, [defaultTaxCode, transactionID]); - - const isMovingTransactionFromTrackExpense = isMovingTransactionFromTrackExpenseUtil(action); + }, [defaultTaxCode, isMovingTransactionFromTrackExpense, transactionID]); const distance = getDistanceInMeters(transaction, unit); const prevDistance = usePrevious(distance); @@ -488,7 +489,9 @@ function MoneyRequestConfirmationList({ // Calculate and set tax amount in transaction draft const taxableAmount = isDistanceRequest ? DistanceRequestUtils.getTaxableAmount(policy, customUnitRateID, distance) : (transaction?.amount ?? 0); - const taxPercentage = getTaxValue(policy, transaction, transaction?.taxCode ?? defaultTaxCode) ?? ''; + const taxPercentage = + getTaxValue(policy, transaction, transaction?.taxCode ?? defaultTaxCode) ?? + (isMovingTransactionFromTrackExpense ? getTaxValue(policyForMovingExpenses, transaction, transaction?.taxCode ?? defaultTaxCode) : ''); const taxAmount = calculateTaxAmount(taxPercentage, taxableAmount, transaction?.currency ?? CONST.CURRENCY.USD); const taxAmountInSmallestCurrencyUnits = convertToBackendAmount(Number.parseFloat(taxAmount.toString())); useEffect(() => { @@ -894,6 +897,11 @@ function MoneyRequestConfirmationList({ return; } + if (!Object.keys(policy?.taxRates?.taxes ?? {}).some((key) => key === transaction.taxCode)) { + setFormError('violations.taxOutOfPolicy'); + return; + } + if (isPerDiemRequest && (transaction.comment?.customUnit?.subRates ?? []).length === 0) { setFormError('iou.error.invalidSubrateLength'); return; diff --git a/src/components/MoneyRequestConfirmationListFooter.tsx b/src/components/MoneyRequestConfirmationListFooter.tsx index fac7f948ad84f..c8b3bc0c3cc8e 100644 --- a/src/components/MoneyRequestConfirmationListFooter.tsx +++ b/src/components/MoneyRequestConfirmationListFooter.tsx @@ -15,7 +15,7 @@ import useThemeStyles from '@hooks/useThemeStyles'; import {getDecodedCategoryName} from '@libs/CategoryUtils'; import {convertToDisplayString} from '@libs/CurrencyUtils'; import DistanceRequestUtils from '@libs/DistanceRequestUtils'; -import {shouldShowReceiptEmptyState} from '@libs/IOUUtils'; +import {isMovingTransactionFromTrackExpense, shouldShowReceiptEmptyState} from '@libs/IOUUtils'; import Navigation from '@libs/Navigation/Navigation'; import {getDestinationForDisplay, getSubratesFields, getSubratesForDisplay, getTimeDifferenceIntervals, getTimeForDisplay} from '@libs/PerDiemRequestUtils'; import {canSendInvoice, getPerDiemCustomUnit} from '@libs/PolicyUtils'; @@ -273,7 +273,7 @@ function MoneyRequestConfirmationListFooter({ const [outstandingReportsByPolicyID] = useOnyx(ONYXKEYS.DERIVED.OUTSTANDING_REPORTS_BY_POLICY_ID, { canBeMissing: true, }); - const {policyForMovingExpensesID, shouldSelectPolicy} = usePolicyForMovingExpenses(); + const {policyForMovingExpensesID, policyForMovingExpenses, shouldSelectPolicy} = usePolicyForMovingExpenses(); const [currentUserLogin] = useOnyx(ONYXKEYS.SESSION, {selector: emailSelector, canBeMissing: true}); @@ -341,11 +341,13 @@ function MoneyRequestConfirmationListFooter({ return name; }, [isUnreported, selectedReport, selectedPolicy, translate]); + const isMovingCurrentTransactionFromTrackExpense = isMovingTransactionFromTrackExpense(action); + // When creating an expense in an individual report, the report field becomes read-only // since the destination is already determined and there's no need to show a selectable list. const shouldReportBeEditable = (isFromGlobalCreate ? allOutstandingReports.length > 1 : availableOutstandingReports.length > 1) && !isMoneyRequestReport(reportID, allReports); - const taxRates = policy?.taxRates ?? null; + const taxRates = policy?.taxRates ?? (isMovingCurrentTransactionFromTrackExpense ? policyForMovingExpenses?.taxRates : null); // In Send Money and Split Bill with Scan flow, we don't allow the Merchant or Date to be edited. For distance requests, don't show the merchant as there's already another "Distance" menu item const shouldShowDate = shouldShowSmartScanFields || isDistanceRequest; // Determines whether the tax fields can be modified. @@ -359,10 +361,11 @@ function MoneyRequestConfirmationListFooter({ const taxAmount = getTaxAmount(transaction, false); const formattedTaxAmount = convertToDisplayString(taxAmount, iouCurrencyCode); // Get the tax rate title based on the policy and transaction - const taxRateTitle = getTaxName(policy, transaction); + const taxRateTitle = (getTaxName(policy, transaction) ?? isMovingCurrentTransactionFromTrackExpense) ? getTaxName(policyForMovingExpenses, transaction) : ''; // Determine if the merchant error should be displayed const shouldDisplayMerchantError = isMerchantRequired && (shouldDisplayFieldError || formError === 'iou.error.invalidMerchant') && isMerchantEmpty; const shouldDisplayDistanceRateError = formError === 'iou.error.invalidRate'; + const shouldDisplayTaxRateError = formError === 'violations.taxOutOfPolicy'; const showReceiptEmptyState = shouldShowReceiptEmptyState(iouType, action, policy, isPerDiemRequest); // The per diem custom unit const perDiemCustomUnit = getPerDiemCustomUnit(policy); @@ -675,6 +678,9 @@ function MoneyRequestConfirmationListFooter({ }} disabled={didConfirm} interactive={canModifyTaxFields} + brickRoadIndicator={shouldDisplayTaxRateError ? CONST.BRICK_ROAD_INDICATOR_STATUS.ERROR : undefined} + errorText={shouldDisplayTaxRateError ? translate(formError) : ''} + /> ), shouldShow: shouldShowTax, diff --git a/src/pages/iou/request/step/IOURequestStepParticipants.tsx b/src/pages/iou/request/step/IOURequestStepParticipants.tsx index cc503a03cedc3..c7fe94aa040eb 100644 --- a/src/pages/iou/request/step/IOURequestStepParticipants.tsx +++ b/src/pages/iou/request/step/IOURequestStepParticipants.tsx @@ -6,6 +6,7 @@ import type {OnyxCollection, OnyxEntry} from 'react-native-onyx'; import FormHelpMessage from '@components/FormHelpMessage'; import useLocalize from '@hooks/useLocalize'; import useOnyx from '@hooks/useOnyx'; +import usePolicyForMovingExpenses from '@hooks/usePolicyForMovingExpenses'; import useThemeStyles from '@hooks/useThemeStyles'; import {setTransactionReport} from '@libs/actions/Transaction'; import {READ_COMMANDS} from '@libs/API/types'; @@ -76,6 +77,7 @@ function IOURequestStepParticipants({ const {translate, localeCompare} = useLocalize(); const styles = useThemeStyles(); const isFocused = useIsFocused(); + const {policyForMovingExpensesID} = usePolicyForMovingExpenses(); const [skipConfirmation] = useOnyx(`${ONYXKEYS.COLLECTION.SKIP_CONFIRMATION}${initialTransactionID}`, {canBeMissing: true}); const [optimisticTransactions] = useOnyx(ONYXKEYS.COLLECTION.TRANSACTION_DRAFT, { selector: transactionDraftValuesSelector, @@ -300,7 +302,7 @@ function IOURequestStepParticipants({ transactions.forEach((transaction) => { setMoneyRequestTag(transaction.transactionID, ''); const category = isMovingTransactionFromTrackExpense && transaction?.category ? transaction?.category : ''; - setMoneyRequestCategory(transaction.transactionID, category); + setMoneyRequestCategory(transaction.transactionID, category, isMovingTransactionFromTrackExpense ? policyForMovingExpensesID : ''); if (shouldUpdateTransactionReportID) { setTransactionReport(transaction.transactionID, {reportID: transactionReportID}, true); } @@ -351,7 +353,7 @@ function IOURequestStepParticipants({ Navigation.navigate(route); } }); - }, [action, participants, iouType, initialTransaction, transactions, initialTransactionID, reportID, waitForKeyboardDismiss, isMovingTransactionFromTrackExpense, backTo, introSelected]); + }, [action, participants, iouType, initialTransaction, transactions, initialTransactionID, reportID, waitForKeyboardDismiss, isMovingTransactionFromTrackExpense, policyForMovingExpensesID, introSelected, backTo]); const navigateBack = useCallback(() => { if (backTo) { From ebf57af86f87015ff0e66e8e14da4d97382f563c Mon Sep 17 00:00:00 2001 From: Agata Kosior Date: Fri, 7 Nov 2025 15:12:44 +0100 Subject: [PATCH 04/11] fix: eslint, prettier --- src/components/MoneyRequestConfirmationList.tsx | 3 +-- .../MoneyRequestConfirmationListFooter.tsx | 1 - src/hooks/usePolicyForTransaction.ts | 4 ++-- .../request/step/IOURequestStepParticipants.tsx | 15 ++++++++++++++- 4 files changed, 17 insertions(+), 6 deletions(-) diff --git a/src/components/MoneyRequestConfirmationList.tsx b/src/components/MoneyRequestConfirmationList.tsx index 652d2a7cb469c..7ed6c9ca5f729 100755 --- a/src/components/MoneyRequestConfirmationList.tsx +++ b/src/components/MoneyRequestConfirmationList.tsx @@ -6,7 +6,7 @@ import type {OnyxEntry} from 'react-native-onyx'; import useCurrentUserPersonalDetails from '@hooks/useCurrentUserPersonalDetails'; import useDebouncedState from '@hooks/useDebouncedState'; import useLocalize from '@hooks/useLocalize'; -import {MouseProvider} from '@hooks/useMouseContext'; +import {MouseProvider} from '@hooks/useMouseContext' import useOnyx from '@hooks/useOnyx'; import usePermissions from '@hooks/usePermissions'; import usePolicyForMovingExpenses from '@hooks/usePolicyForMovingExpenses'; @@ -280,7 +280,6 @@ function MoneyRequestConfirmationList({ isTestDriveReceipt || isManagerMcTestReceipt, ); - const {policyForMovingExpenses} = usePolicyForMovingExpenses(); const isTrackExpense = iouType === CONST.IOU.TYPE.TRACK; const policy = isTrackExpense ? policyForMovingExpenses : (policyReal ?? policyDraft); const policyCategories = policyCategoriesReal ?? policyCategoriesDraft; diff --git a/src/components/MoneyRequestConfirmationListFooter.tsx b/src/components/MoneyRequestConfirmationListFooter.tsx index c8b3bc0c3cc8e..a3eaa587540f9 100644 --- a/src/components/MoneyRequestConfirmationListFooter.tsx +++ b/src/components/MoneyRequestConfirmationListFooter.tsx @@ -680,7 +680,6 @@ function MoneyRequestConfirmationListFooter({ interactive={canModifyTaxFields} brickRoadIndicator={shouldDisplayTaxRateError ? CONST.BRICK_ROAD_INDICATOR_STATUS.ERROR : undefined} errorText={shouldDisplayTaxRateError ? translate(formError) : ''} - /> ), shouldShow: shouldShowTax, diff --git a/src/hooks/usePolicyForTransaction.ts b/src/hooks/usePolicyForTransaction.ts index 93ea57a6148b1..31f33c9b5c811 100644 --- a/src/hooks/usePolicyForTransaction.ts +++ b/src/hooks/usePolicyForTransaction.ts @@ -1,10 +1,10 @@ import type {OnyxEntry} from 'react-native-onyx'; -import useOnyx from '@hooks/useOnyx'; -import usePolicyForMovingExpenses from '@hooks/usePolicyForMovingExpenses'; import {isExpenseUnreported} from '@libs/TransactionUtils'; import CONST from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; import type {Policy, Report, Transaction} from '@src/types/onyx'; +import useOnyx from './useOnyx'; +import usePolicyForMovingExpenses from './usePolicyForMovingExpenses'; type UsePolicyForTransactionParams = { /** The transaction to determine the policy for */ diff --git a/src/pages/iou/request/step/IOURequestStepParticipants.tsx b/src/pages/iou/request/step/IOURequestStepParticipants.tsx index c7fe94aa040eb..995f646d49138 100644 --- a/src/pages/iou/request/step/IOURequestStepParticipants.tsx +++ b/src/pages/iou/request/step/IOURequestStepParticipants.tsx @@ -353,7 +353,20 @@ function IOURequestStepParticipants({ Navigation.navigate(route); } }); - }, [action, participants, iouType, initialTransaction, transactions, initialTransactionID, reportID, waitForKeyboardDismiss, isMovingTransactionFromTrackExpense, policyForMovingExpensesID, introSelected, backTo]); + }, [ + action, + participants, + iouType, + initialTransaction, + transactions, + initialTransactionID, + reportID, + waitForKeyboardDismiss, + isMovingTransactionFromTrackExpense, + policyForMovingExpensesID, + introSelected, + backTo, + ]); const navigateBack = useCallback(() => { if (backTo) { From bb80896370d8c48bc2b255ca8c152df418611b06 Mon Sep 17 00:00:00 2001 From: Agata Kosior Date: Wed, 12 Nov 2025 09:55:31 +0100 Subject: [PATCH 05/11] fix: prettier, add a comment --- src/components/MoneyRequestConfirmationList.tsx | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/components/MoneyRequestConfirmationList.tsx b/src/components/MoneyRequestConfirmationList.tsx index caf91ca5be183..7c91fd88fb2d2 100755 --- a/src/components/MoneyRequestConfirmationList.tsx +++ b/src/components/MoneyRequestConfirmationList.tsx @@ -343,7 +343,7 @@ function MoneyRequestConfirmationList({ const shouldShowTax = isTaxTrackingEnabled(isPolicyExpenseChat || isTrackExpense, policy, isDistanceRequest, isPerDiemRequest); // Update the tax code when the default changes (for example, because the transaction currency changed) - const defaultTaxCode = getDefaultTaxCode(policy, transaction) ?? (isMovingTransactionFromTrackExpense ? getDefaultTaxCode(policyForMovingExpenses, transaction) ?? '' : ''); + const defaultTaxCode = getDefaultTaxCode(policy, transaction) ?? (isMovingTransactionFromTrackExpense ? (getDefaultTaxCode(policyForMovingExpenses, transaction) ?? '') : ''); useEffect(() => { if (!transactionID || isMovingTransactionFromTrackExpense) { @@ -490,6 +490,7 @@ function MoneyRequestConfirmationList({ // Calculate and set tax amount in transaction draft const taxableAmount = isDistanceRequest ? DistanceRequestUtils.getTaxableAmount(policy, customUnitRateID, distance) : (transaction?.amount ?? 0); + // First we'll try to get the tax value from the chosen policy and if not found, we'll try to get it from the policy for moving expenses (only if the transaction is moving from track expense) const taxPercentage = getTaxValue(policy, transaction, transaction?.taxCode ?? defaultTaxCode) ?? (isMovingTransactionFromTrackExpense ? getTaxValue(policyForMovingExpenses, transaction, transaction?.taxCode ?? defaultTaxCode) : ''); From 6c1d57bb513513c763905b3fcdbbc762a8d6c2eb Mon Sep 17 00:00:00 2001 From: Agata Kosior Date: Wed, 12 Nov 2025 16:45:52 +0100 Subject: [PATCH 06/11] fix: do not reset tax amount --- src/components/MoneyRequestConfirmationList.tsx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/components/MoneyRequestConfirmationList.tsx b/src/components/MoneyRequestConfirmationList.tsx index 7c91fd88fb2d2..669e33b9ac3d1 100755 --- a/src/components/MoneyRequestConfirmationList.tsx +++ b/src/components/MoneyRequestConfirmationList.tsx @@ -497,11 +497,11 @@ function MoneyRequestConfirmationList({ const taxAmount = calculateTaxAmount(taxPercentage, taxableAmount, transaction?.currency ?? CONST.CURRENCY.USD); const taxAmountInSmallestCurrencyUnits = convertToBackendAmount(Number.parseFloat(taxAmount.toString())); useEffect(() => { - if (!transactionID) { + if (!transactionID || isMovingTransactionFromTrackExpense) { return; } setMoneyRequestTaxAmount(transactionID, taxAmountInSmallestCurrencyUnits); - }, [transactionID, taxAmountInSmallestCurrencyUnits]); + }, [transactionID, taxAmountInSmallestCurrencyUnits, isMovingTransactionFromTrackExpense]); // If completing a split expense fails, set didConfirm to false to allow the user to edit the fields again if (isEditingSplitBill && didConfirm) { @@ -905,7 +905,7 @@ function MoneyRequestConfirmationList({ return; } - if (!Object.keys(policy?.taxRates?.taxes ?? {}).some((key) => key === transaction.taxCode)) { + if (shouldShowTax && !Object.keys(policy?.taxRates?.taxes ?? {}).some((key) => key === transaction.taxCode)) { setFormError('violations.taxOutOfPolicy'); return; } From a8859959b3547c942cffb84d1b69824925379d9e Mon Sep 17 00:00:00 2001 From: Agata Kosior Date: Thu, 13 Nov 2025 10:40:58 +0100 Subject: [PATCH 07/11] fix: show proper tax name --- src/components/MoneyRequestConfirmationListFooter.tsx | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/components/MoneyRequestConfirmationListFooter.tsx b/src/components/MoneyRequestConfirmationListFooter.tsx index 682124af552af..099f1d2f0c25c 100644 --- a/src/components/MoneyRequestConfirmationListFooter.tsx +++ b/src/components/MoneyRequestConfirmationListFooter.tsx @@ -365,7 +365,14 @@ function MoneyRequestConfirmationListFooter({ const taxAmount = getTaxAmount(transaction, false); const formattedTaxAmount = convertToDisplayString(taxAmount, iouCurrencyCode); // Get the tax rate title based on the policy and transaction - const taxRateTitle = (getTaxName(policy, transaction) ?? isMovingCurrentTransactionFromTrackExpense) ? getTaxName(policyForMovingExpenses, transaction) : ''; + let taxRateTitle; + if (getTaxName(policy, transaction)) { + taxRateTitle = getTaxName(policy, transaction); + } else if (isMovingCurrentTransactionFromTrackExpense) { + taxRateTitle = getTaxName(policyForMovingExpenses, transaction); + } else { + taxRateTitle = ''; + } // Determine if the merchant error should be displayed const shouldDisplayMerchantError = isMerchantRequired && (shouldDisplayFieldError || formError === 'iou.error.invalidMerchant') && isMerchantEmpty; const shouldDisplayDistanceRateError = formError === 'iou.error.invalidRate'; From 92db469c070c72256070e3fcc752c93194d4bbb3 Mon Sep 17 00:00:00 2001 From: Agata Kosior Date: Tue, 18 Nov 2025 11:41:16 +0100 Subject: [PATCH 08/11] fix: eslint, prettier --- .../MoneyRequestConfirmationList.tsx | 1 + .../MoneyRequestConfirmationListFooter.tsx | 9 +++++---- .../ReportActionItem/MoneyRequestView.tsx | 19 ++++++++++++++----- 3 files changed, 20 insertions(+), 9 deletions(-) diff --git a/src/components/MoneyRequestConfirmationList.tsx b/src/components/MoneyRequestConfirmationList.tsx index 707aeb1a62b75..3c374dce27ba5 100755 --- a/src/components/MoneyRequestConfirmationList.tsx +++ b/src/components/MoneyRequestConfirmationList.tsx @@ -960,6 +960,7 @@ function MoneyRequestConfirmationList({ isMerchantRequired, isMerchantEmpty, shouldDisplayFieldError, + shouldShowTax, transaction, iouCategory.length, policyTags, diff --git a/src/components/MoneyRequestConfirmationListFooter.tsx b/src/components/MoneyRequestConfirmationListFooter.tsx index 099f1d2f0c25c..fcf8e39408903 100644 --- a/src/components/MoneyRequestConfirmationListFooter.tsx +++ b/src/components/MoneyRequestConfirmationListFooter.tsx @@ -6,6 +6,7 @@ import React, {memo, useMemo} from 'react'; import {View} from 'react-native'; import type {OnyxEntry} from 'react-native-onyx'; import type {ValueOf} from 'type-fest'; +import {useMemoizedLazyExpensifyIcons} from '@hooks/useLazyAsset'; import useLocalize from '@hooks/useLocalize'; import useNetwork from '@hooks/useNetwork'; import useOnyx from '@hooks/useOnyx'; @@ -46,7 +47,6 @@ import {isEmptyObject} from '@src/types/utils/EmptyObject'; import Badge from './Badge'; import ConfirmedRoute from './ConfirmedRoute'; import MentionReportContext from './HTMLEngineProvider/HTMLRenderers/MentionReportRenderer/MentionReportContext'; -import * as Expensicons from './Icon/Expensicons'; import MenuItem from './MenuItem'; import MenuItemWithTopDescription from './MenuItemWithTopDescription'; import PDFThumbnail from './PDFThumbnail'; @@ -274,6 +274,7 @@ function MoneyRequestConfirmationListFooter({ canBeMissing: true, }); const {policyForMovingExpensesID, policyForMovingExpenses, shouldSelectPolicy} = usePolicyForMovingExpenses(); + const icons = useMemoizedLazyExpensifyIcons(['Stopwatch', 'CalendarSolid'] as const); const [currentUserLogin] = useOnyx(ONYXKEYS.SESSION, {selector: emailSelector, canBeMissing: true}); const isUnreported = transaction?.reportID === CONST.REPORT.UNREPORTED_REPORT_ID; @@ -838,7 +839,7 @@ function MoneyRequestConfirmationListFooter({ badges.push( , ); @@ -847,7 +848,7 @@ function MoneyRequestConfirmationListFooter({ badges.push( , ); @@ -856,7 +857,7 @@ function MoneyRequestConfirmationListFooter({ badges.push( , ); diff --git a/src/components/ReportActionItem/MoneyRequestView.tsx b/src/components/ReportActionItem/MoneyRequestView.tsx index 387cfa36f377d..58fddfe1ec9d6 100644 --- a/src/components/ReportActionItem/MoneyRequestView.tsx +++ b/src/components/ReportActionItem/MoneyRequestView.tsx @@ -3,7 +3,6 @@ import React, {useCallback, useContext, useEffect, useMemo, useState} from 'reac import {View} from 'react-native'; import type {OnyxCollection, OnyxEntry} from 'react-native-onyx'; import Icon from '@components/Icon'; -import * as Expensicons from '@components/Icon/Expensicons'; import MenuItem from '@components/MenuItem'; import MenuItemWithTopDescription from '@components/MenuItemWithTopDescription'; import OfflineWithFeedback from '@components/OfflineWithFeedback'; @@ -15,6 +14,7 @@ import ViolationMessages from '@components/ViolationMessages'; import {WideRHPContext} from '@components/WideRHPContextProvider'; import useActiveRoute from '@hooks/useActiveRoute'; import useEnvironment from '@hooks/useEnvironment'; +import {useMemoizedLazyExpensifyIcons} from '@hooks/useLazyAsset'; import useLocalize from '@hooks/useLocalize'; import useNetwork from '@hooks/useNetwork'; import useOnyx from '@hooks/useOnyx'; @@ -134,6 +134,7 @@ function MoneyRequestView({ const {translate, toLocaleDigit} = useLocalize(); const {getReportRHPActiveRoute} = useActiveRoute(); const [lastVisitedPath] = useOnyx(ONYXKEYS.LAST_VISITED_PATH, {canBeMissing: true}); + const icons = useMemoizedLazyExpensifyIcons(['DotIndicator', 'Checkmark', 'Suitcase'] as const); const [allTransactions] = useOnyx(ONYXKEYS.COLLECTION.TRANSACTION, {canBeMissing: false}); @@ -397,7 +398,15 @@ function MoneyRequestView({ (field: ViolationField, data?: OnyxTypes.TransactionViolation['data'], policyHasDependentTags = false, tagValue?: string) => { // Checks applied when creating a new expense // NOTE: receipt field can return multiple violations, so we need to handle it separately - const fieldChecks: Partial> = { + const fieldChecks: Partial< + Record< + ViolationField, + { + isError: boolean; + translationPath: TranslationPaths; + } + > + > = { merchant: { isError: !isSettled && !isCancelled && isPolicyExpenseChat && isEmptyMerchant, translationPath: canEditMerchant ? 'common.error.enterMerchant' : 'common.error.missingMerchantName', @@ -654,7 +663,7 @@ function MoneyRequestView({ {isCustomUnitOutOfPolicy && isPerDiemRequest && ( { const reservations = transaction?.receipt?.reservationList?.length ?? 0; if (reservations > 1) { From 61abb63c9d184f8e2fb625f72737d9591730206f Mon Sep 17 00:00:00 2001 From: Agata Kosior Date: Fri, 21 Nov 2025 16:35:18 +0200 Subject: [PATCH 09/11] fix: set proper tax rate --- src/components/MoneyRequestConfirmationList.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/MoneyRequestConfirmationList.tsx b/src/components/MoneyRequestConfirmationList.tsx index 960d0169e6e68..2e115bd5322c3 100755 --- a/src/components/MoneyRequestConfirmationList.tsx +++ b/src/components/MoneyRequestConfirmationList.tsx @@ -351,7 +351,7 @@ function MoneyRequestConfirmationList({ return; } setMoneyRequestTaxRate(transactionID, defaultTaxCode); - }, [defaultTaxCode, isMovingTransactionFromTrackExpense, isReadOnly, transactionID]); + }, [defaultTaxCode, isMovingTransactionFromTrackExpense, isReadOnly, transactionID, policyID]); const distance = getDistanceInMeters(transaction, unit); const prevDistance = usePrevious(distance); From dcca29f052983c116de54022451019d3d47539d0 Mon Sep 17 00:00:00 2001 From: Agata Kosior Date: Mon, 24 Nov 2025 15:59:59 +0200 Subject: [PATCH 10/11] fix: apply requested changes --- src/components/MoneyRequestConfirmationList.tsx | 1 + src/libs/actions/IOU.ts | 5 ++++- src/pages/iou/request/step/IOURequestStepParticipants.tsx | 2 +- 3 files changed, 6 insertions(+), 2 deletions(-) diff --git a/src/components/MoneyRequestConfirmationList.tsx b/src/components/MoneyRequestConfirmationList.tsx index 2e115bd5322c3..37c389007cfdd 100755 --- a/src/components/MoneyRequestConfirmationList.tsx +++ b/src/components/MoneyRequestConfirmationList.tsx @@ -351,6 +351,7 @@ function MoneyRequestConfirmationList({ return; } setMoneyRequestTaxRate(transactionID, defaultTaxCode); + // trigger this useEffect also when policyID changes - the defaultTaxCode may stay the same }, [defaultTaxCode, isMovingTransactionFromTrackExpense, isReadOnly, transactionID, policyID]); const distance = getDistanceInMeters(transaction, unit); diff --git a/src/libs/actions/IOU.ts b/src/libs/actions/IOU.ts index 2f8652abe41da..1c4f0cf7815fc 100644 --- a/src/libs/actions/IOU.ts +++ b/src/libs/actions/IOU.ts @@ -1221,13 +1221,16 @@ function setMoneyRequestPendingFields(transactionID: string, pendingFields: Onyx Onyx.merge(`${ONYXKEYS.COLLECTION.TRANSACTION_DRAFT}${transactionID}`, {pendingFields}); } -function setMoneyRequestCategory(transactionID: string, category: string, policyID?: string) { +function setMoneyRequestCategory(transactionID: string, category: string, policyID?: string, isMovingFromTrackExpense?: boolean) { Onyx.merge(`${ONYXKEYS.COLLECTION.TRANSACTION_DRAFT}${transactionID}`, {category}); if (!policyID) { setMoneyRequestTaxRate(transactionID, ''); setMoneyRequestTaxAmount(transactionID, null); return; } + if (!category && isMovingFromTrackExpense) { + return; + } const transaction = allTransactionDrafts[`${ONYXKEYS.COLLECTION.TRANSACTION_DRAFT}${transactionID}`]; // This will be fixed as part of https://github.com/Expensify/Expensify/issues/507850 // eslint-disable-next-line @typescript-eslint/no-deprecated diff --git a/src/pages/iou/request/step/IOURequestStepParticipants.tsx b/src/pages/iou/request/step/IOURequestStepParticipants.tsx index 60d824c9ace94..1601e91827177 100644 --- a/src/pages/iou/request/step/IOURequestStepParticipants.tsx +++ b/src/pages/iou/request/step/IOURequestStepParticipants.tsx @@ -309,7 +309,7 @@ function IOURequestStepParticipants({ const tag = isMovingTransactionFromTrackExpense && transaction?.tag ? transaction?.tag : ''; setMoneyRequestTag(transaction.transactionID, tag); const category = isMovingTransactionFromTrackExpense && transaction?.category ? transaction?.category : ''; - setMoneyRequestCategory(transaction.transactionID, category, isMovingTransactionFromTrackExpense ? policyForMovingExpensesID : ''); + setMoneyRequestCategory(transaction.transactionID, category, isMovingTransactionFromTrackExpense ? policyForMovingExpensesID : '', isMovingTransactionFromTrackExpense); if (shouldUpdateTransactionReportID) { setTransactionReport(transaction.transactionID, {reportID: transactionReportID}, true); } From 5cb7582a9a75fff27661e4434dc78302d945f22f Mon Sep 17 00:00:00 2001 From: Agata Kosior Date: Fri, 28 Nov 2025 14:06:45 +0100 Subject: [PATCH 11/11] fix: do not reset tax rate when moving transaction --- src/components/MoneyRequestConfirmationList.tsx | 2 +- src/libs/actions/IOU.ts | 7 ++++--- src/pages/iou/request/step/IOURequestStepConfirmation.tsx | 4 ++-- 3 files changed, 7 insertions(+), 6 deletions(-) diff --git a/src/components/MoneyRequestConfirmationList.tsx b/src/components/MoneyRequestConfirmationList.tsx index fffb2555ef365..fe616374347e5 100755 --- a/src/components/MoneyRequestConfirmationList.tsx +++ b/src/components/MoneyRequestConfirmationList.tsx @@ -840,7 +840,7 @@ function MoneyRequestConfirmationList({ if (!transactionID || iouCategory || !shouldShowCategories || enabledCategories.length !== 1 || !isCategoryRequired) { return; } - setMoneyRequestCategory(transactionID, enabledCategories.at(0)?.name ?? '', policy?.id); + setMoneyRequestCategory(transactionID, enabledCategories.at(0)?.name ?? '', policy?.id, isMovingTransactionFromTrackExpense); // Keep 'transaction' out to ensure that we auto select the option only once // eslint-disable-next-line react-compiler/react-compiler, react-hooks/exhaustive-deps }, [shouldShowCategories, policyCategories, isCategoryRequired, policy?.id]); diff --git a/src/libs/actions/IOU.ts b/src/libs/actions/IOU.ts index 87687ad5d7178..a9983cd7363d2 100644 --- a/src/libs/actions/IOU.ts +++ b/src/libs/actions/IOU.ts @@ -1231,14 +1231,14 @@ function setMoneyRequestPendingFields(transactionID: string, pendingFields: Onyx function setMoneyRequestCategory(transactionID: string, category: string, policyID?: string, isMovingFromTrackExpense?: boolean) { Onyx.merge(`${ONYXKEYS.COLLECTION.TRANSACTION_DRAFT}${transactionID}`, {category}); + if (isMovingFromTrackExpense) { + return; + } if (!policyID) { setMoneyRequestTaxRate(transactionID, ''); setMoneyRequestTaxAmount(transactionID, null); return; } - if (!category && isMovingFromTrackExpense) { - return; - } const transaction = allTransactionDrafts[`${ONYXKEYS.COLLECTION.TRANSACTION_DRAFT}${transactionID}`]; // This will be fixed as part of https://github.com/Expensify/Expensify/issues/507850 // eslint-disable-next-line @typescript-eslint/no-deprecated @@ -11527,6 +11527,7 @@ function completePaymentOnboarding( shouldSkipTestDriveModal: true, }); } + function payMoneyRequest( paymentType: PaymentMethodType, chatReport: OnyxTypes.Report, diff --git a/src/pages/iou/request/step/IOURequestStepConfirmation.tsx b/src/pages/iou/request/step/IOURequestStepConfirmation.tsx index 303d67e8ad5c4..74b38ffe625c6 100644 --- a/src/pages/iou/request/step/IOURequestStepConfirmation.tsx +++ b/src/pages/iou/request/step/IOURequestStepConfirmation.tsx @@ -385,7 +385,7 @@ function IOURequestStepConfirmation({ // Clear category field when the category doesn't exist for selected policy, or it's disabled if (!policyCategories?.[item.category] || !policyCategories[item.category]?.enabled) { - setMoneyRequestCategory(item.transactionID, '', policy?.id); + setMoneyRequestCategory(item.transactionID, '', policy?.id, isMovingTransactionFromTrackExpense); } } // We don't want to clear out category every time the transactions change @@ -400,7 +400,7 @@ function IOURequestStepConfirmation({ if (!isDistanceRequest || !!item?.category) { continue; } - setMoneyRequestCategory(item.transactionID, defaultCategory, policy?.id); + setMoneyRequestCategory(item.transactionID, defaultCategory, policy?.id, isMovingTransactionFromTrackExpense); } // Prevent resetting to default when unselect category // eslint-disable-next-line react-compiler/react-compiler, react-hooks/exhaustive-deps