Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion src/hooks/useTransactionInlineEdit.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ import {useOnyx as originalUseOnyx} from 'react-native-onyx';
import useDistanceRateOriginalPolicy from './useDistanceRateOriginalPolicy';
import useNetwork from './useNetwork';
import useOnyx from './useOnyx';
import usePersonalPolicy from './usePersonalPolicy';
import usePolicyForMovingExpenses from './usePolicyForMovingExpenses';
import usePolicyForTransaction from './usePolicyForTransaction';
import useSelfDMReport from './useSelfDMReport';
Expand Down Expand Up @@ -146,6 +147,7 @@ function useTransactionInlineEdit({transactionID, hash, linkedReportAction}: Use
const distanceOriginalPolicy = useDistanceRateOriginalPolicy(customUnitRateID, shouldLookupDistancePolicy);

const {isOffline} = useNetwork();
const personalPolicy = usePersonalPolicy();

const permissions = getTransactionEditPermissions({
transaction,
Expand Down Expand Up @@ -186,7 +188,7 @@ function useTransactionInlineEdit({transactionID, hash, linkedReportAction}: Use
};

const onEditDate = (newDate: string) => {
editTransactionDateInline(getEditParams(), newDate);
editTransactionDateInline(getEditParams(), newDate, personalPolicy?.outputCurrency);
};

const onEditMerchant = (newMerchant: string) => {
Expand Down
16 changes: 4 additions & 12 deletions src/libs/DistanceRequestUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -598,18 +598,10 @@ function getRate({
* For example, if an expense is '10 mi @ $1.00 / mi' and the rate is updated to '$1.00 / km',
* then the updated distance unit should be 'km' from the updated rate, not 'mi' from the currently stored transaction distance unit.
*/
function getUpdatedDistanceUnit({
transaction,
policy,
policyDraft,
personalPolicyOutputCurrency,
}: {
transaction: OnyxEntry<Transaction>;
policy: OnyxEntry<Policy>;
policyDraft?: OnyxEntry<Policy>;
personalPolicyOutputCurrency?: string;
}) {
return getRate({transaction, policy, policyDraft, useTransactionDistanceUnit: false, personalPolicyOutputCurrency}).unit;
function getUpdatedDistanceUnit({transaction, policy, policyDraft}: {transaction: OnyxEntry<Transaction>; policy: OnyxEntry<Policy>; policyDraft?: OnyxEntry<Policy>}) {
// The distance unit doesn't depend on the currency (the rate is selected by ID/P2P, not currency), so
// personalPolicyOutputCurrency isn't accepted here and is passed as undefined to getRate.
return getRate({transaction, policy, policyDraft, useTransactionDistanceUnit: false, personalPolicyOutputCurrency: undefined}).unit;
}

/**
Expand Down
16 changes: 12 additions & 4 deletions src/libs/TransactionUtils/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -609,13 +609,15 @@ function getUpdatedTransaction({
shouldUpdateReceiptState = true,
policy = undefined,
isSplitTransaction = false,
personalPolicyOutputCurrency,
}: {
transaction: Transaction;
transactionChanges: TransactionChanges;
isFromExpenseReport: boolean;
shouldUpdateReceiptState?: boolean;
policy?: OnyxEntry<Policy>;
isSplitTransaction?: boolean;
personalPolicyOutputCurrency: string | undefined;
}): Transaction {
const isUnReportedExpense = transaction?.reportID === CONST.REPORT.UNREPORTED_REPORT_ID;

Expand Down Expand Up @@ -666,20 +668,23 @@ function getUpdatedTransaction({
updatedTransaction.modifiedAmount = CONST.IOU.DEFAULT_AMOUNT;
updatedTransaction.modifiedMerchant = translateLocal('iou.fieldPending');
} else if (transactionChanges.routes?.route0?.geometry?.coordinates) {
const mileageRate = DistanceRequestUtils.getRate({transaction: updatedTransaction, policy});
const mileageRate = DistanceRequestUtils.getRate({transaction: updatedTransaction, policy, personalPolicyOutputCurrency});
const {unit, rate} = mileageRate;

// Use route distance directly since waypoints changed and the route was recalculated.
// getDistanceInMeters prefers quantity which may hold a stale manually-edited value.
const distanceInMeters = transactionChanges.routes?.route0?.distance ?? getDistanceInMeters(transaction, unit);
const amount = DistanceRequestUtils.getDistanceRequestAmount(distanceInMeters, unit, rate ?? 0);
const updatedAmount = isFromExpenseReport || isUnReportedExpense ? -amount : amount;
// Use the rate's resolved currency (which may come from personalPolicyOutputCurrency for a P2P expense),
// not transaction.currency, so the merchant symbol/rate and the recalculated amount stay in the same currency.
const updatedCurrency = mileageRate.currency ?? transaction.currency ?? CONST.CURRENCY.USD;
const updatedMerchant = DistanceRequestUtils.getDistanceMerchant(
true,
distanceInMeters,
unit,
rate,
transaction.currency,
updatedCurrency,
translateLocal,
(digit) => toLocaleDigit(IntlStore.getCurrentLocale(), digit),
getCurrencySymbol,
Expand All @@ -689,6 +694,9 @@ function getUpdatedTransaction({
updatedTransaction.amount = updatedAmount;
updatedTransaction.modifiedAmount = updatedAmount;
updatedTransaction.modifiedMerchant = updatedMerchant;
if (getCurrency(updatedTransaction) !== updatedCurrency) {
updatedTransaction.modifiedCurrency = updatedCurrency;
}

// Sync `customUnit.quantity` to the new route distance. Without this the prior manual
// quantity (set when the user edited distance manually before changing waypoints) would
Expand Down Expand Up @@ -730,7 +738,7 @@ function getUpdatedTransaction({
// 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 updatedMileageRate = DistanceRequestUtils.getRate({transaction: updatedTransaction, policy, useTransactionDistanceUnit: false});
const updatedMileageRate = DistanceRequestUtils.getRate({transaction: updatedTransaction, policy, useTransactionDistanceUnit: false, personalPolicyOutputCurrency});
const {unit, rate} = updatedMileageRate;

const distanceInMeters = getDistanceInMeters(updatedTransaction, unit);
Expand Down Expand Up @@ -818,7 +826,7 @@ function getUpdatedTransaction({
lodashSet(updatedTransaction, 'routes.route0.distance', null);
shouldStopSmartscan = true;

const updatedMileageRate = DistanceRequestUtils.getRate({transaction: updatedTransaction, policy, useTransactionDistanceUnit: false});
const updatedMileageRate = DistanceRequestUtils.getRate({transaction: updatedTransaction, policy, useTransactionDistanceUnit: false, personalPolicyOutputCurrency});
const {unit, rate} = updatedMileageRate;

// Sync the stored distanceUnit to the policy's current unit. The user's input on the Manual
Expand Down
3 changes: 3 additions & 0 deletions src/libs/actions/IOU/BulkEdit.ts
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,7 @@ type UpdateMultipleMoneyRequestsParams = {
allPolicies?: OnyxCollection<OnyxTypes.Policy>;
currentUserAccountID: number;
delegateAccountID: number | undefined;
personalPolicyOutputCurrency?: string;
};

function updateMultipleMoneyRequests({
Expand All @@ -112,6 +113,7 @@ function updateMultipleMoneyRequests({
allPolicies,
currentUserAccountID,
delegateAccountID,
personalPolicyOutputCurrency,
}: UpdateMultipleMoneyRequestsParams) {
// Track running totals per report so multiple edits in the same report compound correctly.
const optimisticReportsByID: Record<string, OnyxTypes.Report> = {};
Expand Down Expand Up @@ -347,6 +349,7 @@ function updateMultipleMoneyRequests({
transactionChanges,
isFromExpenseReport,
policy: transactionPolicy,
personalPolicyOutputCurrency,
});
const isTransactionOnHold = isOnHold(transaction);

Expand Down
2 changes: 2 additions & 0 deletions src/libs/actions/IOU/Split.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1247,6 +1247,7 @@ function setDraftSplitTransaction(
splitTransactionDraft: OnyxEntry<OnyxTypes.Transaction>,
transactionChanges: TransactionChanges = {},
policy?: OnyxEntry<OnyxTypes.Policy>,
personalPolicyOutputCurrency?: string,
) {
if (!transactionID) {
return undefined;
Expand All @@ -1265,6 +1266,7 @@ function setDraftSplitTransaction(
shouldUpdateReceiptState: false,
policy,
isSplitTransaction: true,
personalPolicyOutputCurrency,
})
: null;

Expand Down
17 changes: 17 additions & 0 deletions src/libs/actions/IOU/UpdateMoneyRequest.ts
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,7 @@ type UpdateMoneyRequestDateParams = {
delegateAccountID: number | undefined;
policyForTrackExpense?: OnyxEntry<OnyxTypes.Policy>;
distanceOriginalPolicy?: OnyxEntry<OnyxTypes.Policy>;
personalPolicyOutputCurrency: string | undefined;
};

type SearchSnapshotOnyxData = {
Expand Down Expand Up @@ -228,6 +229,7 @@ function updateMoneyRequestDate({
delegateAccountID,
policyForTrackExpense,
distanceOriginalPolicy,
personalPolicyOutputCurrency,
}: UpdateMoneyRequestDateParams) {
const transaction = getAllTransactions()[`${ONYXKEYS.COLLECTION.TRANSACTION}${transactionID}`];
const isTrackExpense = isTrackExpenseReport(transactionThreadReport) && isSelfDM(parentReport);
Expand Down Expand Up @@ -270,6 +272,7 @@ function updateMoneyRequestDate({
updatedTaxValue: distanceRateTaxUpdates?.taxValue,
distanceOriginalPolicy,
currentTransactionViolations,
personalPolicyOutputCurrency,
});
return;
}
Expand Down Expand Up @@ -913,6 +916,7 @@ type UpdateMoneyRequestDistanceParams = {
parentReportNextStep: OnyxEntry<OnyxTypes.ReportNextStepDeprecated>;
distanceOriginalPolicy?: OnyxEntry<OnyxTypes.Policy>;
delegateAccountID: number | undefined;
personalPolicyOutputCurrency: string | undefined;
};

/** Updates the waypoints of a distance expense */
Expand All @@ -936,6 +940,7 @@ function updateMoneyRequestDistance({
parentReportNextStep,
distanceOriginalPolicy,
delegateAccountID,
personalPolicyOutputCurrency,
}: UpdateMoneyRequestDistanceParams) {
const transactionChanges: TransactionChanges = {
// Don't sanitize waypoints here - keep all fields for Onyx optimistic data (e.g., keyForList)
Expand All @@ -961,6 +966,8 @@ function updateMoneyRequestDistance({
undefined,
undefined,
distanceOriginalPolicy,
undefined,
personalPolicyOutputCurrency,
);
} else {
data = getUpdateMoneyRequestParams({
Expand All @@ -978,6 +985,7 @@ function updateMoneyRequestDistance({
isASAPSubmitBetaEnabled,
iouReportNextStep: parentReportNextStep,
delegateAccountID,
personalPolicyOutputCurrency,
});
}
const {params, onyxData} = data;
Expand Down Expand Up @@ -1176,6 +1184,7 @@ function updateMoneyRequestDistanceRate({
shouldBuildOptimisticModifiedExpenseReportAction = true,
distanceOriginalPolicy,
currentTransactionViolations: currentTransactionViolationsParam,
personalPolicyOutputCurrency,
}: {
transaction: OnyxEntry<OnyxTypes.Transaction>;
transactionThreadReport: OnyxEntry<OnyxTypes.Report>;
Expand All @@ -1200,6 +1209,7 @@ function updateMoneyRequestDistanceRate({
shouldBuildOptimisticModifiedExpenseReportAction?: boolean;
distanceOriginalPolicy?: OnyxEntry<OnyxTypes.Policy>;
currentTransactionViolations?: OnyxEntry<OnyxTypes.TransactionViolations>;
personalPolicyOutputCurrency: string | undefined;
}) {
const transactionChanges: TransactionChanges = {
customUnitRateID: rateID,
Expand Down Expand Up @@ -1238,6 +1248,7 @@ function updateMoneyRequestDistanceRate({
shouldBuildOptimisticModifiedExpenseReportAction,
distanceOriginalPolicy,
currentTransactionViolations,
personalPolicyOutputCurrency,
);
} else {
data = getUpdateMoneyRequestParams({
Expand All @@ -1260,6 +1271,7 @@ function updateMoneyRequestDistanceRate({
shouldBuildOptimisticModifiedExpenseReportAction,
distanceOriginalPolicy,
violations: currentTransactionViolations,
personalPolicyOutputCurrency,
});
if (created && transaction?.transactionID && transactions && transactionViolations) {
removeTransactionFromDuplicateTransactionViolation(data.onyxData, transaction.transactionID, transactions, transactionViolations);
Expand Down Expand Up @@ -1385,6 +1397,7 @@ type GetUpdateMoneyRequestParamsType = {
isOffline?: boolean;
delegateAccountID: number | undefined;
distanceOriginalPolicy?: OnyxEntry<OnyxTypes.Policy>;
personalPolicyOutputCurrency?: string;
};

type UpdateMoneyRequestDataKeys =
Expand Down Expand Up @@ -1427,6 +1440,7 @@ function getUpdateMoneyRequestParams(params: GetUpdateMoneyRequestParamsType): U
isOffline,
delegateAccountID,
distanceOriginalPolicy,
personalPolicyOutputCurrency,
} = params;
const optimisticData: Array<
OnyxUpdate<
Expand Down Expand Up @@ -1513,6 +1527,7 @@ function getUpdateMoneyRequestParams(params: GetUpdateMoneyRequestParamsType): U
isFromExpenseReport,
isSplitTransaction,
policy,
personalPolicyOutputCurrency,
})
: undefined;

Expand Down Expand Up @@ -2081,6 +2096,7 @@ function getUpdateTrackExpenseParams(
shouldBuildOptimisticModifiedExpenseReportAction = true,
distanceOriginalPolicy?: OnyxEntry<OnyxTypes.Policy>,
currentTransactionViolations?: OnyxEntry<OnyxTypes.TransactionViolations>,
personalPolicyOutputCurrency?: string,
): UpdateMoneyRequestData<
| typeof ONYXKEYS.COLLECTION.REPORT_ACTIONS
| typeof ONYXKEYS.COLLECTION.TRANSACTION
Expand Down Expand Up @@ -2127,6 +2143,7 @@ function getUpdateTrackExpenseParams(
transactionChanges,
isFromExpenseReport: false,
policy: policyForTransaction,
personalPolicyOutputCurrency,
})
: null;
const transactionDetails = getTransactionDetails(updatedTransaction);
Expand Down
3 changes: 2 additions & 1 deletion src/libs/actions/TransactionInlineEdit.ts
Original file line number Diff line number Diff line change
Expand Up @@ -290,7 +290,7 @@ function getIouParamsForTransaction({
}

/** Updates the date of an expense from the Search results table or the Expense Report page. */
function editTransactionDateInline(params: TransactionInlineEditParams, newDate: string) {
function editTransactionDateInline(params: TransactionInlineEditParams, newDate: string, personalPolicyOutputCurrency: string | undefined) {
const iouParams = getIouParamsForTransaction(params);
updateMoneyRequestDate({
...iouParams,
Expand All @@ -302,6 +302,7 @@ function editTransactionDateInline(params: TransactionInlineEditParams, newDate:
isOffline: params.isOffline,
hash: params.hash,
distanceOriginalPolicy: params.distanceOriginalPolicy,
personalPolicyOutputCurrency,
});
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import useCurrentUserPersonalDetails from '@hooks/useCurrentUserPersonalDetails'
import useDelegateAccountID from '@hooks/useDelegateAccountID';
import useLocalize from '@hooks/useLocalize';
import useOnyx from '@hooks/useOnyx';
import usePersonalPolicy from '@hooks/usePersonalPolicy';
import useThemeStyles from '@hooks/useThemeStyles';

import {clearBulkEditDraftTransaction, updateMultipleMoneyRequests} from '@libs/actions/IOU/BulkEdit';
Expand Down Expand Up @@ -51,6 +52,7 @@ function SearchEditMultiplePage() {
const {currentSearchResults} = useSearchResultsContext();
const {clearSelectedTransactions} = useSearchSelectionActions();
const {accountID: currentUserAccountID} = useCurrentUserPersonalDetails();
const personalPolicy = usePersonalPolicy();
const delegateAccountID = useDelegateAccountID();
const [policies] = useOnyx(ONYXKEYS.COLLECTION.POLICY);
const [activePolicyID] = useOnyx(ONYXKEYS.NVP_ACTIVE_POLICY_ID);
Expand Down Expand Up @@ -192,6 +194,7 @@ function SearchEditMultiplePage() {
allPolicies: policies,
currentUserAccountID,
delegateAccountID,
personalPolicyOutputCurrency: personalPolicy?.outputCurrency,
});
// Bulk edit can start from report (ID-based selection) or search (map-based selection),
// so clear both stores to keep deselection behavior consistent.
Expand Down
1 change: 1 addition & 0 deletions src/pages/iou/request/step/IOURequestStepDate.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,7 @@ function IOURequestStepDate({
isOffline,
delegateAccountID,
distanceOriginalPolicy,
personalPolicyOutputCurrency: personalPolicy?.outputCurrency,
});
} else {
setMoneyRequestCreated(transactionID, newCreated, isTransactionDraft, hasReceipt(transaction));
Expand Down
7 changes: 6 additions & 1 deletion src/pages/iou/request/step/IOURequestStepDistance.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -462,6 +462,7 @@ function IOURequestStepDistance({
originalSplitTransactionDraft,
{waypoints: currentTransaction?.comment?.waypoints, routes: currentTransaction?.routes},
policy,
personalPolicy?.outputCurrency,
);
navigateBackAfterSave();
return;
Expand Down Expand Up @@ -499,6 +500,7 @@ function IOURequestStepDistance({
parentReportNextStep,
delegateAccountID,
distanceOriginalPolicy,
personalPolicyOutputCurrency: personalPolicy?.outputCurrency,
});
}
transactionWasSaved.current = true;
Expand Down Expand Up @@ -543,6 +545,7 @@ function IOURequestStepDistance({
parentReportNextStep,
delegateAccountID,
distanceOriginalPolicy,
personalPolicy?.outputCurrency,
]);

const submitManualDistance = useCallback(() => {
Expand Down Expand Up @@ -572,7 +575,7 @@ function IOURequestStepDistance({

if (isEditingSplit && transaction) {
setMoneyRequestDistance(transactionID, distanceAsFloat, shouldUseTransactionDraft(action, iouType), distanceUnit);
setDraftSplitTransaction(CONST.IOU.OPTIMISTIC_TRANSACTION_ID, splitDraftTransaction, {distance: distanceAsFloat}, policy);
setDraftSplitTransaction(CONST.IOU.OPTIMISTIC_TRANSACTION_ID, splitDraftTransaction, {distance: distanceAsFloat}, policy, personalPolicy?.outputCurrency);
navigateBackAfterSave();
return;
}
Expand Down Expand Up @@ -610,6 +613,7 @@ function IOURequestStepDistance({
delegateAccountID,
recentWaypoints,
distanceOriginalPolicy,
personalPolicyOutputCurrency: personalPolicy?.outputCurrency,
});
transactionWasSaved.current = true;
// Remove the backup eagerly so the parent report view reads the optimistic transaction
Expand Down Expand Up @@ -646,6 +650,7 @@ function IOURequestStepDistance({
hasRouteError,
delegateAccountID,
distanceOriginalPolicy,
personalPolicy?.outputCurrency,
]);

const renderItem = useCallback(
Expand Down
Loading
Loading