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
16 changes: 12 additions & 4 deletions src/components/ReportActionItem/MoneyRequestView.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ import {
getLengthOfTag,
getPerDiemCustomUnit,
getPolicyByCustomUnitID,
getPolicyByCustomUnitRateID,
getTagLists,
hasDependentTags as hasDependentTagsPolicyUtils,
isAttendeeTrackingEnabled,
Expand Down Expand Up @@ -209,19 +210,26 @@ function MoneyRequestView({
const [policiesWithPerDiem] = useOnyx(ONYXKEYS.COLLECTION.POLICY, {
selector: perDiemPoliciesSelector,
});
const [allPolicies] = useOnyx(ONYXKEYS.COLLECTION.POLICY);
const isPerDiemRequest = isPerDiemRequestTransactionUtils(transaction);
const perDiemOriginalPolicy = getPolicyByCustomUnitID(transaction, policiesWithPerDiem);
const isDistanceRequestForPolicy = isDistanceRequestTransactionUtils(transaction);
const distanceOriginalPolicy = isDistanceRequestForPolicy ? getPolicyByCustomUnitRateID(transaction, allPolicies) : undefined;

let policy;
let policyID;
// If the expense is unreported the policy should be the user's default policy, if the expense is a per diem request and is unreported
// the policy should be the one where the per diem rates are enabled, otherwise it should be the expense's report policy
if (isExpenseUnreported && !isPerDiemRequest) {
policy = policyForMovingExpenses;
policyID = policyForMovingExpensesID;
// the policy should be the one where the per diem rates are enabled, if the expense is a distance request and is unreported
// the policy should be the one where the distance rate belongs to, otherwise it should be the expense's report policy
if (isExpenseUnreported && isDistanceRequestForPolicy && distanceOriginalPolicy) {
policy = distanceOriginalPolicy;
policyID = distanceOriginalPolicy?.id;
} else if (isExpenseUnreported && isPerDiemRequest) {
policy = perDiemOriginalPolicy;
policyID = perDiemOriginalPolicy?.id;
} else if (isExpenseUnreported) {
policy = policyForMovingExpenses;
policyID = policyForMovingExpensesID;
} else {
policy = expensePolicy;
policyID = parentReport?.policyID;
Expand Down
20 changes: 17 additions & 3 deletions src/hooks/usePolicyForTransaction.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import {useMemo} from 'react';
import type {OnyxEntry} from 'react-native-onyx';
import {getPolicyByCustomUnitID} from '@libs/PolicyUtils';
import {isExpenseUnreported} from '@libs/TransactionUtils';
import {getPolicyByCustomUnitID, getPolicyByCustomUnitRateID} from '@libs/PolicyUtils';
import {isDistanceRequest, isExpenseUnreported} from '@libs/TransactionUtils';
import CONST from '@src/CONST';
import ONYXKEYS from '@src/ONYXKEYS';
import type {Policy, Transaction} from '@src/types/onyx';
Expand Down Expand Up @@ -42,12 +42,26 @@ function usePolicyForTransaction({transaction, reportPolicyID, action, iouType,
return getPolicyByCustomUnitID(transaction, allPolicies);
}, [transaction, allPolicies]);

const distanceRatePolicy = useMemo(() => {
return getPolicyByCustomUnitRateID(transaction, allPolicies);
}, [transaction, allPolicies]);

const [reportPolicy] = useOnyx(`${ONYXKEYS.COLLECTION.POLICY}${reportPolicyID}`);

const isUnreportedExpense = isExpenseUnreported(transaction);
const isCreatingTrackExpense = action === CONST.IOU.ACTION.CREATE && iouType === CONST.IOU.TYPE.TRACK;
const isDistanceExpense = isDistanceRequest(transaction);

const policyForSelfDMExpense = isPerDiemRequest ? customUnitPolicy : policyForMovingExpenses;
const getPolicyForSelfDMExpense = () => {
if (isPerDiemRequest) {
return customUnitPolicy;
}
if (isDistanceExpense && distanceRatePolicy) {
return distanceRatePolicy;
}
return policyForMovingExpenses;
};
const policyForSelfDMExpense = getPolicyForSelfDMExpense();
const policy = isUnreportedExpense || isCreatingTrackExpense ? policyForSelfDMExpense : (reportPolicy ?? policyDraft);

return {policy};
Expand Down
1 change: 1 addition & 0 deletions src/libs/API/parameters/UpdateMoneyRequestParams.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ type UpdateMoneyRequestParams = Partial<TransactionDetails> & {
reportID?: string;
transactionID?: string;
reportActionID?: string;
policyID?: string;
/** Used for bulk updates - JSON stringified object containing only changed fields */
updates?: string;
};
Expand Down
17 changes: 17 additions & 0 deletions src/libs/PolicyUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@

let allPolicies: OnyxCollection<Policy>;

Onyx.connect({

Check warning on line 79 in src/libs/PolicyUtils.ts

View workflow job for this annotation

GitHub Actions / Changed files ESLint check

Onyx.connect() is deprecated. Use useOnyx() hook instead and pass the data as parameters to a pure function
key: ONYXKEYS.COLLECTION.POLICY,
waitForCollectionCallback: true,
callback: (value) => (allPolicies = value),
Expand Down Expand Up @@ -234,6 +234,22 @@
});
}

/**
* Finds a policy that contains the customUnitRateID from the transaction's distance rate
*/
function getPolicyByCustomUnitRateID(transaction: OnyxEntry<Transaction>, policies: OnyxCollection<Policy>): OnyxEntry<Policy> {
const customUnitRateID = transaction?.comment?.customUnit?.customUnitRateID;

if (!customUnitRateID || !policies) {
return undefined;
}

return Object.values(policies).find((policy) => {
const distanceUnit = getDistanceRateCustomUnit(policy);
return !!distanceUnit?.rates && customUnitRateID in distanceUnit.rates;
});
}

/**
* Retrieves custom unit rate object from the given customUnitRateID
*/
Expand Down Expand Up @@ -2208,6 +2224,7 @@
getDistanceRateCustomUnit,
getPerDiemCustomUnit,
getPolicyByCustomUnitID,
getPolicyByCustomUnitRateID,
getDistanceRateCustomUnitRate,
getPerDiemRateCustomUnitRate,
sortWorkspacesBySelected,
Expand Down
2 changes: 2 additions & 0 deletions src/libs/actions/IOU/UpdateMoneyRequest.ts
Original file line number Diff line number Diff line change
Expand Up @@ -964,6 +964,7 @@ function getUpdateMoneyRequestParams(params: GetUpdateMoneyRequestParamsType): U
...dataToIncludeInParams,
reportID: iouReport?.reportID,
transactionID,
policyID: policy?.id,
};

const hasPendingWaypoints = 'waypoints' in transactionChanges;
Expand Down Expand Up @@ -1482,6 +1483,7 @@ function getUpdateTrackExpenseParams(
...dataToIncludeInParams,
reportID: chatReport?.reportID,
transactionID,
policyID: policy?.id,
};

const hasPendingWaypoints = 'waypoints' in transactionChanges;
Expand Down
27 changes: 17 additions & 10 deletions src/pages/iou/request/step/IOURequestStepDistanceRate.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import useCurrentUserPersonalDetails from '@hooks/useCurrentUserPersonalDetails'
import useLocalize from '@hooks/useLocalize';
import useOnyx from '@hooks/useOnyx';
import usePermissions from '@hooks/usePermissions';
import usePolicyForMovingExpenses from '@hooks/usePolicyForMovingExpenses';
import usePolicyForTransaction from '@hooks/usePolicyForTransaction';
import useShowNotFoundPageInIOUStep from '@hooks/useShowNotFoundPageInIOUStep';
import useThemeStyles from '@hooks/useThemeStyles';
Expand Down Expand Up @@ -66,6 +67,7 @@ function IOURequestStepDistanceRate({
const [splitDraftTransaction] = useOnyx(`${ONYXKEYS.COLLECTION.SPLIT_TRANSACTION_DRAFT}${transactionID}`);

const {policy} = usePolicyForTransaction({transaction, reportPolicyID: report?.policyID, action, iouType, policyDraft});
const {policyForMovingExpenses} = usePolicyForMovingExpenses();

const styles = useThemeStyles();
const {translate, toLocaleDigit, localeCompare} = useLocalize();
Expand All @@ -76,7 +78,8 @@ function IOURequestStepDistanceRate({
const {getCurrencySymbol, getCurrencyDecimals} = useCurrencyListActions();
const isPolicyExpenseChat = isReportInGroupPolicy(report);
const isTrackExpense = iouType === CONST.IOU.TYPE.TRACK;
const shouldShowTax = isTaxTrackingEnabled(isPolicyExpenseChat || isTrackExpense || isExpenseUnreported(currentTransaction), policy, isDistanceRequest);
const isUnreportedExpense = isExpenseUnreported(currentTransaction);
const shouldShowTax = isTaxTrackingEnabled(isPolicyExpenseChat || isTrackExpense || isUnreportedExpense, policy, isDistanceRequest);

const currentRateID = getRateID(currentTransaction);
const transactionCurrency = getCurrency(currentTransaction);
Expand All @@ -91,7 +94,11 @@ function IOURequestStepDistanceRate({
// This keeps the problematic rate shown as selected so the user understands what they need to change.
const [pendingRateID, setPendingRateID] = useState<string | undefined>();

const rates = DistanceRequestUtils.getMileageRates(policy, false, currentRateID);
// For unreported distance expenses, use the default policy for the rate picker list
// so users see rates from their default workspace, not the original non-default workspace.
// The `policy` (from usePolicyForTransaction) still reflects the original policy for display purposes.
const policyForRates = isUnreportedExpense && isDistanceRequest && policyForMovingExpenses ? policyForMovingExpenses : policy;
const rates = DistanceRequestUtils.getMileageRates(policyForRates, false, currentRateID);
const isMovingTransactionFromTrackExpense = isMovingTransactionFromTrackExpenseUtil(action);
const transactionUnit = transaction?.comment?.customUnit?.distanceUnit;
const sortedRates = useMemo(() => Object.values(rates).sort((a, b) => localeCompare(a.name ?? '', b.name ?? '')), [rates, localeCompare]);
Expand All @@ -109,7 +116,7 @@ function IOURequestStepDistanceRate({
const effectiveRateID = pendingRateID ?? currentRateID;
const isSelected = effectiveRateID
? effectiveRateID === rate.customUnitRateID && !hasUnitMismatchForMovingTrackExpense
: DistanceRequestUtils.getDefaultMileageRate(policy)?.customUnitRateID === rate.customUnitRateID;
: DistanceRequestUtils.getDefaultMileageRate(policyForRates)?.customUnitRateID === rate.customUnitRateID;
const rateForDisplay = DistanceRequestUtils.getFormattedRateValue(unit, rate.rate, isSelected ? transactionCurrency : rate.currency, translate, toLocaleDigit, getCurrencySymbol);
return {
text: rate.name ?? rateForDisplay,
Expand Down Expand Up @@ -152,12 +159,12 @@ function IOURequestStepDistanceRate({
let taxRateExternalID;
let taxValue;
if (shouldShowTax) {
const policyCustomUnitRate = getDistanceRateCustomUnitRate(policy, customUnitRateID);
const defaultTaxCode = getDefaultTaxCode(policy, currentTransaction) ?? '';
const policyCustomUnitRate = getDistanceRateCustomUnitRate(policyForRates, customUnitRateID);
const defaultTaxCode = getDefaultTaxCode(policyForRates, currentTransaction) ?? '';
// eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing
taxRateExternalID = policyCustomUnitRate?.attributes?.taxRateExternalID || defaultTaxCode;
const taxableAmount = DistanceRequestUtils.getTaxableAmount(policy, customUnitRateID, getDistanceInMeters(currentTransaction, currentUnit));
taxValue = taxRateExternalID ? getTaxValue(policy, currentTransaction, taxRateExternalID) : undefined;
const taxableAmount = DistanceRequestUtils.getTaxableAmount(policyForRates, customUnitRateID, getDistanceInMeters(currentTransaction, currentUnit));
taxValue = taxRateExternalID ? getTaxValue(policyForRates, currentTransaction, taxRateExternalID) : undefined;
taxAmount = convertToBackendAmount(calculateTaxAmount(taxValue, taxableAmount, getCurrencyDecimals(rates[customUnitRateID].currency)));
setMoneyRequestTaxAmount(transactionID, taxAmount, shouldUseTransactionDraft(action));
setMoneyRequestTaxRate(transactionID, taxRateExternalID ?? null, shouldUseTransactionDraft(action));
Expand All @@ -167,12 +174,12 @@ function IOURequestStepDistanceRate({
if (currentRateID !== customUnitRateID || (isMovingTransactionFromTrackExpense && transactionUnit !== selectedRateUnit)) {
// In the split flow, when editing we use SPLIT_TRANSACTION_DRAFT to save draft value
if (isEditingSplit && transaction) {
setDraftSplitTransaction(transaction.transactionID, splitDraftTransaction, {customUnitRateID}, policy);
setDraftSplitTransaction(transaction.transactionID, splitDraftTransaction, {customUnitRateID}, policyForRates);
navigateBack();
return;
}

setMoneyRequestDistanceRate(transaction, customUnitRateID, policy, shouldUseTransactionDraft(action));
setMoneyRequestDistanceRate(transaction, customUnitRateID, policyForRates, shouldUseTransactionDraft(action));

if (isEditing && transaction?.transactionID) {
updateMoneyRequestDistanceRate({
Expand All @@ -181,7 +188,7 @@ function IOURequestStepDistanceRate({
parentReport,
parentReportNextStep,
rateID: customUnitRateID,
policy,
policy: policyForRates,
policyTagList: policyTags,
policyCategories,
currentUserAccountIDParam,
Expand Down
Loading