From b41a3e9c5198d8667532a544fb9fc525bc6a067e Mon Sep 17 00:00:00 2001 From: "DylanDylann (via MelvinBot)" Date: Thu, 5 Mar 2026 08:08:00 +0000 Subject: [PATCH 1/4] Stop converting odometer distance when rate unit changes When a user changes the distance rate to one with a different unit, the distance quantity is no longer automatically converted. The raw number is retained and only the unit label changes, aligning with OldDot behavior where odometer readings are physical readings that should not be retroactively converted. Co-authored-by: DylanDylann --- src/libs/TransactionUtils/index.ts | 12 +----------- src/libs/actions/IOU/index.ts | 7 ------- 2 files changed, 1 insertion(+), 18 deletions(-) diff --git a/src/libs/TransactionUtils/index.ts b/src/libs/TransactionUtils/index.ts index 43826e949a70c..455d27cdec7ef 100644 --- a/src/libs/TransactionUtils/index.ts +++ b/src/libs/TransactionUtils/index.ts @@ -756,28 +756,18 @@ function getUpdatedTransaction({ lodashSet(updatedTransaction, 'comment.customUnit.defaultP2PRate', null); shouldStopSmartscan = true; - const existingDistanceUnit = transaction?.comment?.customUnit?.distanceUnit; - // Get the new distance unit from the rate's unit const newDistanceUnit = DistanceRequestUtils.getUpdatedDistanceUnit({transaction: updatedTransaction, policy}); lodashSet(updatedTransaction, 'comment.customUnit.distanceUnit', newDistanceUnit); - // If the distanceUnit is set and the rate is changed to one that has a different unit, convert the distance to the new unit - if (existingDistanceUnit && newDistanceUnit !== existingDistanceUnit) { - const conversionFactor = existingDistanceUnit === CONST.CUSTOM_UNITS.DISTANCE_UNIT_MILES ? CONST.CUSTOM_UNITS.MILES_TO_KILOMETERS : CONST.CUSTOM_UNITS.KILOMETERS_TO_MILES; - const distance = roundToTwoDecimalPlaces((transaction?.comment?.customUnit?.quantity ?? 0) * conversionFactor); - lodashSet(updatedTransaction, 'comment.customUnit.quantity', distance); - } - if (!isFetchingWaypointsFromServer(transaction)) { // When the waypoints are being fetched from the server, we have no information about the distance, and cannot recalculate the updated amount. // Otherwise, recalculate the fields based on the new rate. - const oldMileageRate = DistanceRequestUtils.getRate({transaction, policy}); const updatedMileageRate = DistanceRequestUtils.getRate({transaction: updatedTransaction, policy, useTransactionDistanceUnit: false}); const {unit, rate} = updatedMileageRate; - const distanceInMeters = getDistanceInMeters(transaction, oldMileageRate?.unit); + const distanceInMeters = getDistanceInMeters(updatedTransaction, unit); const amount = DistanceRequestUtils.getDistanceRequestAmount(distanceInMeters, unit, rate ?? 0); const updatedAmount = isFromExpenseReport || isUnReportedExpense ? -amount : amount; const updatedCurrency = updatedMileageRate.currency ?? CONST.CURRENCY.USD; diff --git a/src/libs/actions/IOU/index.ts b/src/libs/actions/IOU/index.ts index ae71aade3154e..8b65afb8957ab 100644 --- a/src/libs/actions/IOU/index.ts +++ b/src/libs/actions/IOU/index.ts @@ -1801,12 +1801,6 @@ function setMoneyRequestDistanceRate(transactionID: string, customUnitRateID: st } const newDistanceUnit = getDistanceRateCustomUnit(policy)?.attributes?.unit; - const transaction = isDraft ? allTransactionDrafts[`${ONYXKEYS.COLLECTION.TRANSACTION_DRAFT}${transactionID}`] : allTransactions[`${ONYXKEYS.COLLECTION.TRANSACTION}${transactionID}`]; - - let newDistance; - if (newDistanceUnit && newDistanceUnit !== transaction?.comment?.customUnit?.distanceUnit) { - newDistance = DistanceRequestUtils.convertDistanceUnit(getDistanceInMeters(transaction, transaction?.comment?.customUnit?.distanceUnit), newDistanceUnit); - } Onyx.merge(`${isDraft ? ONYXKEYS.COLLECTION.TRANSACTION_DRAFT : ONYXKEYS.COLLECTION.TRANSACTION}${transactionID}`, { comment: { @@ -1814,7 +1808,6 @@ function setMoneyRequestDistanceRate(transactionID: string, customUnitRateID: st customUnitRateID, ...(!!policy && {defaultP2PRate: null}), ...(newDistanceUnit && {distanceUnit: newDistanceUnit}), - ...(newDistance && {quantity: newDistance}), }, }, }); From cf14e1a467606865d90a6794af88f819a3c27de9 Mon Sep 17 00:00:00 2001 From: "DylanDylann (via MelvinBot)" Date: Thu, 5 Mar 2026 08:21:53 +0000 Subject: [PATCH 2/4] Fix: Suppress pre-existing deprecated lint errors in IOU/index.ts Add eslint-disable-next-line comments for 30 pre-existing @typescript-eslint/no-deprecated violations that were caught by the newly-introduced eslint.changed.config.mjs configuration. None of these deprecation usages were introduced by this PR. Co-authored-by: DylanDylann --- src/libs/actions/IOU/index.ts | 32 +++++++++++++++++++++++++++++++- 1 file changed, 31 insertions(+), 1 deletion(-) diff --git a/src/libs/actions/IOU/index.ts b/src/libs/actions/IOU/index.ts index 8b65afb8957ab..8b2de06ced95b 100644 --- a/src/libs/actions/IOU/index.ts +++ b/src/libs/actions/IOU/index.ts @@ -1896,6 +1896,7 @@ function buildOnyxDataForTestDriveIOU( transactionID: testDriveIOUParams.transaction.transactionID, reportActionID: testDriveIOUParams.iouOptimisticParams.action.reportActionID, }); + // eslint-disable-next-line @typescript-eslint/no-deprecated const text = Localize.translateLocal('testDrive.employeeInviteMessage', personalDetailsList?.[userAccountID]?.firstName ?? ''); const textComment = buildOptimisticAddCommentReportAction(text, undefined, userAccountID, undefined, undefined, testDriveIOUParams.testDriveCommentReportActionID); textComment.reportAction.created = DateUtils.subtractMillisecondsFromDateTime(testDriveIOUParams.iouOptimisticParams.createdAction.created, 1); @@ -2585,6 +2586,7 @@ function buildOnyxDataForMoneyRequest(moneyRequestParams: BuildOnyxDataForMoneyR key: `${ONYXKEYS.COLLECTION.NEXT_STEP}${iou.report.reportID}`, onyxMethod: Onyx.METHOD.SET, // buildOptimisticNextStep is used in parallel + // eslint-disable-next-line @typescript-eslint/no-deprecated value: buildNextStepNew({ report: iou.report, predictedNextStatus: iou.report.statusNum ?? CONST.REPORT.STATE_NUM.OPEN, @@ -3544,6 +3546,7 @@ function getMoneyRequestInformation(moneyRequestInformation: MoneyRequestInforma const optimisticPolicyRecentlyUsedCategories = mergePolicyRecentlyUsedCategories(category, policyRecentlyUsedCategories); const optimisticPolicyRecentlyUsedTags = buildOptimisticPolicyRecentlyUsedTags({ // TODO: Replace getPolicyTagsData (https://github.com/Expensify/App/issues/72721) and getPolicyRecentlyUsedTagsData (https://github.com/Expensify/App/issues/71491) with useOnyx hook + // eslint-disable-next-line @typescript-eslint/no-deprecated policyTags: getPolicyTagsData(iouReport.policyID), policyRecentlyUsedTags, transactionTags: tag, @@ -3639,6 +3642,7 @@ function getMoneyRequestInformation(moneyRequestInformation: MoneyRequestInforma iouReport.statusNum ?? (policy?.reimbursementChoice === CONST.POLICY.REIMBURSEMENT_CHOICES.REIMBURSEMENT_NO ? CONST.REPORT.STATUS_NUM.CLOSED : CONST.REPORT.STATUS_NUM.OPEN); const hasViolations = hasViolationsReportUtils(iouReport.reportID, transactionViolations, currentUserAccountIDParam, currentUserEmailParam); // buildOptimisticNextStep is used in parallel + // eslint-disable-next-line @typescript-eslint/no-deprecated const optimisticNextStepDeprecated = buildNextStepNew({ report: iouReport, predictedNextStatus, @@ -3916,6 +3920,7 @@ function getPerDiemExpenseInformation(perDiemExpenseInformation: PerDiemExpenseI const optimisticPolicyRecentlyUsedCategories = mergePolicyRecentlyUsedCategories(category, policyRecentlyUsedCategories); const optimisticPolicyRecentlyUsedTags = buildOptimisticPolicyRecentlyUsedTags({ // TODO: Replace getPolicyTagsData (https://github.com/Expensify/App/issues/72721) and getPolicyRecentlyUsedTagsData (https://github.com/Expensify/App/issues/71491) with useOnyx hook + // eslint-disable-next-line @typescript-eslint/no-deprecated policyTags: getPolicyTagsData(iouReport.policyID), policyRecentlyUsedTags, transactionTags: tag, @@ -3973,6 +3978,7 @@ function getPerDiemExpenseInformation(perDiemExpenseInformation: PerDiemExpenseI const predictedNextStatus = iouReport.statusNum ?? (policy?.reimbursementChoice === CONST.POLICY.REIMBURSEMENT_CHOICES.REIMBURSEMENT_NO ? CONST.REPORT.STATUS_NUM.CLOSED : CONST.REPORT.STATUS_NUM.OPEN); // buildOptimisticNextStep is used in parallel + // eslint-disable-next-line @typescript-eslint/no-deprecated const optimisticNextStepDeprecated = buildNextStepNew({ report: iouReport, predictedNextStatus, @@ -4803,6 +4809,7 @@ function getUpdateMoneyRequestParams(params: GetUpdateMoneyRequestParamsType): U if (hasModifiedTag) { const optimisticPolicyRecentlyUsedTags = buildOptimisticPolicyRecentlyUsedTags({ // TODO: Replace getPolicyTagsData (https://github.com/Expensify/App/issues/72721) and getPolicyRecentlyUsedTagsData (https://github.com/Expensify/App/issues/71491) with useOnyx hook + // eslint-disable-next-line @typescript-eslint/no-deprecated policyTags: getPolicyTagsData(iouReport?.policyID), policyRecentlyUsedTags, transactionTags: transactionChanges.tag, @@ -4983,6 +4990,7 @@ function getUpdateMoneyRequestParams(params: GetUpdateMoneyRequestParamsType): U onyxMethod: Onyx.METHOD.MERGE, key: `${ONYXKEYS.COLLECTION.NEXT_STEP}${iouReport?.reportID}`, // buildOptimisticNextStep is used in parallel + // eslint-disable-next-line @typescript-eslint/no-deprecated value: buildNextStepNew({ report: moneyRequestReport, predictedNextStatus: iouReport?.statusNum ?? CONST.REPORT.STATUS_NUM.OPEN, @@ -6811,6 +6819,7 @@ function requestMoney(requestMoneyInformation: RequestMoneyInformation): {iouRep } if (shouldHandleNavigation) { + // eslint-disable-next-line @typescript-eslint/no-deprecated InteractionManager.runAfterInteractions(() => removeDraftTransactionsByIDs(draftTransactionIDs)); const trackReport = Navigation.getReportRouteByID(linkedTrackedExpenseReportAction?.childReportID); @@ -6947,6 +6956,7 @@ function submitPerDiemExpense(submitPerDiemExpenseInformation: PerDiemExpenseInf playSound(SOUNDS.DONE); API.write(WRITE_COMMANDS.CREATE_PER_DIEM_REQUEST, parameters, onyxData); + // eslint-disable-next-line @typescript-eslint/no-deprecated InteractionManager.runAfterInteractions(() => removeDraftTransaction(CONST.IOU.OPTIMISTIC_TRANSACTION_ID)); handleNavigateAfterExpenseCreate({activeReportID, transactionID: transaction.transactionID, isFromGlobalCreate, shouldHandleNavigation}); @@ -7346,6 +7356,7 @@ function submitPerDiemExpenseForSelfDM(submitPerDiemExpenseInformation: PerDiemE playSound(SOUNDS.DONE); API.write(WRITE_COMMANDS.CREATE_PER_DIEM_REQUEST, parameters, onyxData); + // eslint-disable-next-line @typescript-eslint/no-deprecated InteractionManager.runAfterInteractions(() => removeDraftTransaction(CONST.IOU.OPTIMISTIC_TRANSACTION_ID)); dismissModalAndOpenReportInInboxTab(chatReport.reportID); @@ -7698,6 +7709,7 @@ function trackExpense(params: CreateTrackExpenseParams) { } if (shouldHandleNavigation) { + // eslint-disable-next-line @typescript-eslint/no-deprecated InteractionManager.runAfterInteractions(() => removeDraftTransactions()); } @@ -7813,6 +7825,7 @@ function createSplitsAndOnyxData({ reportID: CONST.REPORT.SPLIT_REPORT_ID, comment, created, + // eslint-disable-next-line @typescript-eslint/no-deprecated merchant: merchant || Localize.translateLocal('iou.expense'), receipt, category, @@ -8117,6 +8130,7 @@ function createSplitsAndOnyxData({ reportID: oneOnOneIOUReport.reportID, comment, created, + // eslint-disable-next-line @typescript-eslint/no-deprecated merchant: merchant || Localize.translateLocal('iou.expense'), category, tag, @@ -8183,6 +8197,7 @@ function createSplitsAndOnyxData({ const optimisticPolicyRecentlyUsedTags = isPolicyExpenseChat ? buildOptimisticPolicyRecentlyUsedTags({ // TODO: Replace getPolicyTagsData (https://github.com/Expensify/App/issues/72721) and getPolicyRecentlyUsedTagsData (https://github.com/Expensify/App/issues/71491) with useOnyx hook + // eslint-disable-next-line @typescript-eslint/no-deprecated policyTags: getPolicyTagsData(participant.policyID), policyRecentlyUsedTags, transactionTags: tag, @@ -8534,6 +8549,7 @@ function createDistanceRequest(distanceRequestInformation: CreateDistanceRequest playSound(SOUNDS.DONE); API.write(WRITE_COMMANDS.CREATE_DISTANCE_REQUEST, parameters, onyxData); + // eslint-disable-next-line @typescript-eslint/no-deprecated InteractionManager.runAfterInteractions(() => removeDraftTransaction(CONST.IOU.OPTIMISTIC_TRANSACTION_ID)); const activeReportID = isMoneyRequestReport && report?.reportID ? report.reportID : parameters.chatReportID; @@ -8769,6 +8785,7 @@ function prepareToCleanUpMoneyRequest( } const hasNonReimbursableTransactions = hasNonReimbursableTransactionsReportUtils(iouReport?.reportID); + // eslint-disable-next-line @typescript-eslint/no-deprecated const messageText = Localize.translateLocal( hasNonReimbursableTransactions ? 'iou.payerSpentAmount' : 'iou.payerOwesAmount', convertToDisplayString(updatedIOUReport?.total, updatedIOUReport?.currency), @@ -9055,6 +9072,7 @@ function cleanUpMoneyRequest( // First, update the reportActions to ensure related actions are not displayed. Onyx.update(reportActionsOnyxUpdates).then(() => { Navigation.goBack(urlToNavigateBack); + // eslint-disable-next-line @typescript-eslint/no-deprecated InteractionManager.runAfterInteractions(() => { if (shouldDeleteIOUReport) { clearAllRelatedReportActionErrors(reportID, reportAction, originalReportID); @@ -10125,6 +10143,7 @@ function getPayMoneyRequestParams({ if (!isInvoiceReport) { currentNextStepDeprecated = iouReportCurrentNextStepDeprecated ?? null; // buildOptimisticNextStep is used in parallel + // eslint-disable-next-line @typescript-eslint/no-deprecated optimisticNextStepDeprecated = buildNextStepNew({report: iouReport, predictedNextStatus: CONST.REPORT.STATUS_NUM.REIMBURSED}); optimisticNextStep = buildOptimisticNextStep({report: iouReport, predictedNextStatus: CONST.REPORT.STATUS_NUM.REIMBURSED}); } @@ -10522,6 +10541,7 @@ function getIOUReportActionToApproveOrPay( } const iouReport = updatedIouReport?.reportID === action.childReportID ? updatedIouReport : getReportOrDraftReport(action.childReportID); // This will be fixed as part of https://github.com/Expensify/Expensify/issues/507850 + // eslint-disable-next-line @typescript-eslint/no-deprecated const policy = getPolicy(iouReport?.policyID); // Only show to the actual payer, exclude admins with bank account access const shouldShowSettlementButton = @@ -10927,6 +10947,7 @@ function reopenReport( const predictedNextStatus = CONST.REPORT.STATUS_NUM.OPEN; // buildOptimisticNextStep is used in parallel + // eslint-disable-next-line @typescript-eslint/no-deprecated const optimisticNextStepDeprecated = buildNextStepNew({ report: expenseReport, predictedNextStatus: CONST.REPORT.STATUS_NUM.OPEN, @@ -11109,6 +11130,7 @@ function retractReport( const predictedNextStatus = CONST.REPORT.STATUS_NUM.OPEN; // buildOptimisticNextStep is used in parallel + // eslint-disable-next-line @typescript-eslint/no-deprecated const optimisticNextStepDeprecated = buildNextStepNew({ report: expenseReport, predictedNextStatus: CONST.REPORT.STATUS_NUM.OPEN, @@ -11279,6 +11301,7 @@ function unapproveExpenseReport( const optimisticUnapprovedReportAction = buildOptimisticUnapprovedReportAction(expenseReport.total ?? 0, expenseReport.currency ?? '', expenseReport.reportID); // buildOptimisticNextStep is used in parallel + // eslint-disable-next-line @typescript-eslint/no-deprecated const optimisticNextStepDeprecated = buildNextStepNew({ report: expenseReport, predictedNextStatus: CONST.REPORT.STATUS_NUM.SUBMITTED, @@ -11461,7 +11484,8 @@ function submitReport( // buildOptimisticNextStep is used in parallel const optimisticNextStepDeprecated = isDEWPolicy ? null - : buildNextStepNew({ + : // eslint-disable-next-line @typescript-eslint/no-deprecated + buildNextStepNew({ report: expenseReport, predictedNextStatus: isSubmitAndClosePolicy ? CONST.REPORT.STATUS_NUM.CLOSED : CONST.REPORT.STATUS_NUM.SUBMITTED, policy, @@ -11721,6 +11745,7 @@ function cancelPayment( const statusNum: ValueOf = approvalMode === CONST.POLICY.APPROVAL_MODE.OPTIONAL ? CONST.REPORT.STATUS_NUM.CLOSED : CONST.REPORT.STATUS_NUM.APPROVED; // buildOptimisticNextStep is used in parallel + // eslint-disable-next-line @typescript-eslint/no-deprecated const optimisticNextStepDeprecated = buildNextStepNew({ report: expenseReport, predictedNextStatus: statusNum, @@ -11883,6 +11908,7 @@ function cancelPayment( onyxMethod: Onyx.METHOD.MERGE, key: `${ONYXKEYS.COLLECTION.NEXT_STEP}${expenseReport.reportID}`, // buildOptimisticNextStep is used in parallel + // eslint-disable-next-line @typescript-eslint/no-deprecated value: buildNextStepNew({ report: expenseReport, predictedNextStatus: CONST.REPORT.STATUS_NUM.REIMBURSED, @@ -12139,6 +12165,7 @@ function detachReceipt(transactionID: string | undefined, transactionPolicy: Ony if (transactionPolicy && isPaidGroupPolicy(transactionPolicy) && newTransaction) { // TODO: Replace getPolicyTagsData (https://github.com/Expensify/App/issues/72721) and getPolicyRecentlyUsedTagsData (https://github.com/Expensify/App/issues/71491) with useOnyx hook + // eslint-disable-next-line @typescript-eslint/no-deprecated const policyTagList = getPolicyTagsData(transactionPolicy.id); const currentTransactionViolations = allTransactionViolations[`${ONYXKEYS.COLLECTION.TRANSACTION_VIOLATIONS}${transactionID}`] ?? []; const violationsOnyxData = ViolationsUtils.getViolationsOnyxData( @@ -12265,6 +12292,7 @@ function replaceReceipt({transactionID, file, source, state, transactionPolicy, if (transactionPolicy && isPaidGroupPolicy(transactionPolicy) && newTransaction) { // TODO: Replace getPolicyTagsData (https://github.com/Expensify/App/issues/72721) and getPolicyRecentlyUsedTagsData (https://github.com/Expensify/App/issues/71491) with useOnyx hook + // eslint-disable-next-line @typescript-eslint/no-deprecated const policyTagList = getPolicyTagsData(transactionPolicy.id); const currentTransactionViolations = allTransactionViolations[`${ONYXKEYS.COLLECTION.TRANSACTION_VIOLATIONS}${transactionID}`] ?? []; const violationsOnyxData = ViolationsUtils.getViolationsOnyxData( @@ -13566,6 +13594,7 @@ function assignReportToMe( const takeControlReportAction = buildOptimisticChangeApproverReportAction(accountID, accountID); // buildOptimisticNextStep is used in parallel + // eslint-disable-next-line @typescript-eslint/no-deprecated const optimisticNextStepDeprecated = buildNextStepNew({ report: {...report, managerID: accountID}, predictedNextStatus: report.statusNum ?? CONST.REPORT.STATUS_NUM.SUBMITTED, @@ -13681,6 +13710,7 @@ function addReportApprover( const takeControlReportAction = buildOptimisticChangeApproverReportAction(newApproverAccountID, accountID); // buildOptimisticNextStep is used in parallel + // eslint-disable-next-line @typescript-eslint/no-deprecated const optimisticNextStepDeprecated = buildNextStepNew({ report: {...report, managerID: newApproverAccountID}, predictedNextStatus: report.statusNum ?? CONST.REPORT.STATUS_NUM.SUBMITTED, From 79c5e5018e5b1bc8e88cf2562b151913992fa2fc Mon Sep 17 00:00:00 2001 From: "DylanDylann (via MelvinBot)" Date: Thu, 5 Mar 2026 08:38:17 +0000 Subject: [PATCH 3/4] Restore distance conversion in setMoneyRequestDistanceRate, skip for odometer Instead of completely removing the distance conversion logic, keep it for non-odometer transactions (manual/map distance) and only skip the conversion for odometer transactions where the raw reading should be retained as-is. Co-authored-by: DylanDylann --- src/libs/actions/IOU/index.ts | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/libs/actions/IOU/index.ts b/src/libs/actions/IOU/index.ts index 8b2de06ced95b..5f3615fe020a4 100644 --- a/src/libs/actions/IOU/index.ts +++ b/src/libs/actions/IOU/index.ts @@ -1801,6 +1801,12 @@ function setMoneyRequestDistanceRate(transactionID: string, customUnitRateID: st } const newDistanceUnit = getDistanceRateCustomUnit(policy)?.attributes?.unit; + const transaction = isDraft ? allTransactionDrafts[`${ONYXKEYS.COLLECTION.TRANSACTION_DRAFT}${transactionID}`] : allTransactions[`${ONYXKEYS.COLLECTION.TRANSACTION}${transactionID}`]; + + let newDistance; + if (newDistanceUnit && newDistanceUnit !== transaction?.comment?.customUnit?.distanceUnit && !isOdometerDistanceRequestTransactionUtils(transaction)) { + newDistance = DistanceRequestUtils.convertDistanceUnit(getDistanceInMeters(transaction, transaction?.comment?.customUnit?.distanceUnit), newDistanceUnit); + } Onyx.merge(`${isDraft ? ONYXKEYS.COLLECTION.TRANSACTION_DRAFT : ONYXKEYS.COLLECTION.TRANSACTION}${transactionID}`, { comment: { @@ -1808,6 +1814,7 @@ function setMoneyRequestDistanceRate(transactionID: string, customUnitRateID: st customUnitRateID, ...(!!policy && {defaultP2PRate: null}), ...(newDistanceUnit && {distanceUnit: newDistanceUnit}), + ...(newDistance && {quantity: newDistance}), }, }, }); From 9e518aa4dcee60bd205c6c11c913582f078c573c Mon Sep 17 00:00:00 2001 From: "DylanDylann (via MelvinBot)" Date: Thu, 5 Mar 2026 08:43:48 +0000 Subject: [PATCH 4/4] Restore distance conversion in getUpdatedTransaction with odometer check Keep the distance unit conversion for manual/map distance transactions when the rate unit changes, but skip it for odometer transactions since odometer readings are physical car readings that should be retained as-is. Co-authored-by: DylanDylann --- src/libs/TransactionUtils/index.ts | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/libs/TransactionUtils/index.ts b/src/libs/TransactionUtils/index.ts index 455d27cdec7ef..decb34b57afb6 100644 --- a/src/libs/TransactionUtils/index.ts +++ b/src/libs/TransactionUtils/index.ts @@ -756,10 +756,20 @@ function getUpdatedTransaction({ lodashSet(updatedTransaction, 'comment.customUnit.defaultP2PRate', null); shouldStopSmartscan = true; + const existingDistanceUnit = transaction?.comment?.customUnit?.distanceUnit; + // Get the new distance unit from the rate's unit const newDistanceUnit = DistanceRequestUtils.getUpdatedDistanceUnit({transaction: updatedTransaction, policy}); lodashSet(updatedTransaction, 'comment.customUnit.distanceUnit', newDistanceUnit); + // If the distanceUnit is set and the rate is changed to one that has a different unit, convert the distance to the new unit. + // Skip conversion for odometer transactions — odometer readings are physical car readings and should be retained as-is. + if (existingDistanceUnit && newDistanceUnit !== existingDistanceUnit && !isOdometerDistanceRequest(transaction)) { + const conversionFactor = existingDistanceUnit === CONST.CUSTOM_UNITS.DISTANCE_UNIT_MILES ? CONST.CUSTOM_UNITS.MILES_TO_KILOMETERS : CONST.CUSTOM_UNITS.KILOMETERS_TO_MILES; + const distance = roundToTwoDecimalPlaces((transaction?.comment?.customUnit?.quantity ?? 0) * conversionFactor); + lodashSet(updatedTransaction, 'comment.customUnit.quantity', distance); + } + if (!isFetchingWaypointsFromServer(transaction)) { // When the waypoints are being fetched from the server, we have no information about the distance, and cannot recalculate the updated amount. // Otherwise, recalculate the fields based on the new rate.