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
6 changes: 5 additions & 1 deletion src/hooks/useTransactionInlineEdit.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import {
} from '@libs/actions/TransactionInlineEdit';
import getNonEmptyStringOnyxID from '@libs/getNonEmptyStringOnyxID';
import {getIOUActionForTransactionID} from '@libs/ReportActionsUtils';
import {isTrackExpenseReportNew} from '@libs/ReportUtils';
import {isExpenseUnreported, isPerDiemRequest} from '@libs/TransactionUtils';
import CONST from '@src/CONST';
import ONYXKEYS from '@src/ONYXKEYS';
Expand Down Expand Up @@ -128,7 +129,9 @@ function useTransactionInlineEdit({transactionID, hash, linkedReportAction}: Use
const {hasSelectedTransactions} = useSearchSelectionContext();

const isPerDiem = isPerDiemRequest(transaction);
const {shouldSelectPolicy} = usePolicyForMovingExpenses(isPerDiem);
const {shouldSelectPolicy, policyForMovingExpenses} = usePolicyForMovingExpenses(isPerDiem);

const isTrackExpense = isTrackExpenseReportNew(transactionThreadReport, effectiveParentReport, parentReportAction);

const {isOffline} = useNetwork();

Expand Down Expand Up @@ -157,6 +160,7 @@ function useTransactionInlineEdit({transactionID, hash, linkedReportAction}: Use
parentReportAction,
transactionThreadReport,
policy: completePolicy ?? policy,
policyForTrackExpense: isTrackExpense ? policyForMovingExpenses : undefined,
policyCategories,
policyTags,
policyRecentlyUsedCategories,
Expand Down
21 changes: 21 additions & 0 deletions src/libs/TransactionUtils/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@ import type {
} from '@src/types/onyx';
import type {Attendee, DistanceExpenseType, Participant, SplitExpense} from '@src/types/onyx/IOU';
import type {Errors, PendingAction} from '@src/types/onyx/OnyxCommon';
import type {Unit} from '@src/types/onyx/Policy';
import type {OnyxData} from '@src/types/onyx/Request';
import type {
Comment,
Expand Down Expand Up @@ -2174,6 +2175,25 @@ function getTaxValue(policy: OnyxEntry<Policy>, transaction: OnyxEntry<Transacti
return Object.values(transformedTaxRates(policy, transaction)).find((taxRate) => taxRate.code === taxCode)?.value;
}

/**
* Computes tax amount, code, and value when a workspace distance expense uses a given mileage rate.
*/
function getDistanceRateTaxUpdates(
policy: OnyxEntry<Policy>,
transaction: OnyxEntry<Transaction>,
customUnitRateID: string,
distanceUnit?: Unit,
): {taxAmount: number; taxCode: string; taxValue: string | undefined} {
const taxCode = getDefaultTaxCode(policy, transaction, undefined, customUnitRateID) ?? '';
const taxableAmount = DistanceRequestUtils.getTaxableAmount(policy, customUnitRateID, getDistanceInMeters(transaction, distanceUnit ?? transaction?.comment?.customUnit?.distanceUnit));
const taxValue = taxCode ? getTaxValue(policy, transaction, taxCode) : undefined;
const mileageRates = DistanceRequestUtils.getMileageRates(policy);
const rateCurrency = mileageRates[customUnitRateID]?.currency ?? transaction?.currency ?? CONST.CURRENCY.USD;
const taxAmount = convertToBackendAmount(calculateTaxAmount(taxValue, taxableAmount, getCurrencyDecimals(rateCurrency)));

return {taxAmount, taxCode, taxValue};
}

/**
* Returns the maximum allowed tax amount (in the smallest currency units) for a transaction,
* i.e. the tax computed from the selected tax rate (or the policy default) and the expense amount.
Expand Down Expand Up @@ -2939,6 +2959,7 @@ export {
transformedTaxRates,
getTaxValue,
getCalculatedTaxAmount,
getDistanceRateTaxUpdates,
getTaxName,
getTaxRateTitle,
hasTaxRateWithMatchingValue,
Expand Down
128 changes: 126 additions & 2 deletions src/libs/actions/IOU/UpdateMoneyRequest.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import DistanceRequestUtils from '@libs/DistanceRequestUtils';
import {getMicroSecondOnyxErrorWithTranslationKey} from '@libs/ErrorUtils';
import {buildNextStepNew, buildOptimisticNextStep} from '@libs/NextStepUtils';
import {rand64} from '@libs/NumberUtils';
import {hasDependentTags, isGroupPolicy} from '@libs/PolicyUtils';
import {hasDependentTags, isGroupPolicy, isTaxTrackingEnabled} from '@libs/PolicyUtils';
import type {TransactionDetails} from '@libs/ReportUtils';
import {
buildOptimisticModifiedExpenseReportAction,
Expand All @@ -28,6 +28,7 @@ import {
import {
getAmount,
getClearedPendingFields,
getDistanceRateTaxUpdates,
getMerchant,
getUpdatedTransaction,
hasSubmissionBlockingViolationInReport,
Expand All @@ -51,6 +52,7 @@ import type {SearchResultDataType} from '@src/types/onyx/SearchResults';
import type {Routes, TransactionChanges, WaypointCollection} from '@src/types/onyx/Transaction';
import {isEmptyObject} from '@src/types/utils/EmptyObject';
import {getAllReports, getAllTransactions, getAllTransactionViolations, getPolicyTagsData, getRecentAttendees} from '.';
import {setLastSelectedDistanceRate} from './MoneyRequest';
import {getUpdatedMoneyRequestReportData, mergePolicyRecentlyUsedCategories, mergePolicyRecentlyUsedCurrencies} from './MoneyRequestBuilder';

type UpdateMoneyRequestData<TKey extends OnyxKey> = {
Expand All @@ -75,6 +77,7 @@ type UpdateMoneyRequestDateParams = {
isOffline: boolean;
hash?: number;
delegateAccountID: number | undefined;
policyForTrackExpense?: OnyxEntry<OnyxTypes.Policy>;
};

type SearchSnapshotOnyxData = {
Expand Down Expand Up @@ -142,6 +145,68 @@ function getSearchSnapshotUpdates({
};
}

function getRecalculatedDistanceRateIDForExpenseDate({
transaction,
transactionThreadReport,
parentReport,
policy,
policyForTrackExpense,
expenseDate,
}: {
transaction: OnyxEntry<OnyxTypes.Transaction>;
transactionThreadReport: OnyxEntry<OnyxTypes.Report>;
parentReport: OnyxEntry<OnyxTypes.Report>;
policy: OnyxEntry<OnyxTypes.Policy>;
policyForTrackExpense?: OnyxEntry<OnyxTypes.Policy>;
expenseDate: string;
}): string | undefined {
if (!transaction || !isDistanceRequestTransactionUtils(transaction)) {
return undefined;
}

const isTrackExpense = isTrackExpenseReport(transactionThreadReport) && isSelfDM(parentReport);
const isWorkspaceDistanceExpense = isExpenseReport(parentReport);

if (!isTrackExpense && !isWorkspaceDistanceExpense) {
return undefined;
}

const effectivePolicy = isTrackExpense ? (policyForTrackExpense ?? policy) : policy;

if (!effectivePolicy || (!isTrackExpense && !isGroupPolicy(effectivePolicy))) {
return undefined;
}

const currentRateID = transaction.comment?.customUnit?.customUnitRateID;
if (!currentRateID || currentRateID === CONST.CUSTOM_UNITS.FAKE_P2P_ID) {
return undefined;
}

const currentMileageRate = DistanceRequestUtils.getRateByCustomUnitRateID({customUnitRateID: currentRateID, policy: effectivePolicy});
if (!currentMileageRate) {
return undefined;
}

if (currentMileageRate.enabled !== false && DistanceRequestUtils.isRateEligibleForDate(currentMileageRate, expenseDate)) {
return undefined;
}

const reportID = parentReport?.reportID ?? transactionThreadReport?.reportID ?? transaction.reportID;
const newRateID = DistanceRequestUtils.getCustomUnitRateID({
reportID,
isPolicyExpenseChat: !isTrackExpense,
isTrackDistanceExpense: isTrackExpense,
policy: effectivePolicy,
expenseDate,
});

if (newRateID === CONST.CUSTOM_UNITS.FAKE_P2P_ID) {
return undefined;
}

return newRateID;
}

/** Updates the created date of an expense */
function updateMoneyRequestDate({
transactionID,
Expand All @@ -160,7 +225,50 @@ function updateMoneyRequestDate({
isOffline,
hash,
delegateAccountID,
policyForTrackExpense,
}: UpdateMoneyRequestDateParams) {
const transaction = getAllTransactions()[`${ONYXKEYS.COLLECTION.TRANSACTION}${transactionID}`];
const isTrackExpense = isTrackExpenseReport(transactionThreadReport) && isSelfDM(parentReport);
const effectivePolicy = isTrackExpense ? (policyForTrackExpense ?? policy) : policy;
const newRateID = getRecalculatedDistanceRateIDForExpenseDate({
transaction,
transactionThreadReport,
parentReport,
policy,
policyForTrackExpense,
expenseDate: value,
});
const currentRateID = transaction?.comment?.customUnit?.customUnitRateID;

if (newRateID && newRateID !== currentRateID && transaction && effectivePolicy) {
setLastSelectedDistanceRate(effectivePolicy, newRateID);
const distanceRateTaxUpdates =
!isTrackExpense && isTaxTrackingEnabled(true, effectivePolicy, true) && transaction ? getDistanceRateTaxUpdates(effectivePolicy, transaction, newRateID) : undefined;
updateMoneyRequestDistanceRate({
transaction,
transactionThreadReport,
parentReport,
rateID: newRateID,
created: value,
Comment thread
Krishna2323 marked this conversation as resolved.
policy: effectivePolicy,
policyTagList: policyTags,
policyCategories,
currentUserAccountIDParam,
currentUserEmailParam,
isASAPSubmitBetaEnabled,
parentReportNextStep,
delegateAccountID,
hash,
transactions,
transactionViolations,
isOffline,
updatedTaxAmount: distanceRateTaxUpdates?.taxAmount,
updatedTaxCode: distanceRateTaxUpdates?.taxCode,
updatedTaxValue: distanceRateTaxUpdates?.taxValue,
});
return;
}

const transactionChanges: TransactionChanges = {
created: value,
};
Expand Down Expand Up @@ -1032,6 +1140,7 @@ function updateMoneyRequestDistanceRate({
transactionThreadReport,
parentReport,
rateID,
created,
policy,
policyTagList,
policyCategories,
Expand All @@ -1043,11 +1152,16 @@ function updateMoneyRequestDistanceRate({
updatedTaxValue,
parentReportNextStep,
delegateAccountID,
hash,
transactions,
transactionViolations,
isOffline,
}: {
transaction: OnyxEntry<OnyxTypes.Transaction>;
transactionThreadReport: OnyxEntry<OnyxTypes.Report>;
parentReport: OnyxEntry<OnyxTypes.Report>;
rateID: string;
created?: string;
policy: OnyxEntry<OnyxTypes.Policy>;
policyTagList: OnyxEntry<OnyxTypes.PolicyTagLists>;
policyCategories: OnyxEntry<OnyxTypes.PolicyCategories>;
Expand All @@ -1059,9 +1173,14 @@ function updateMoneyRequestDistanceRate({
updatedTaxValue?: string;
parentReportNextStep: OnyxEntry<OnyxTypes.ReportNextStepDeprecated>;
delegateAccountID: number | undefined;
hash?: number;
transactions?: OnyxCollection<OnyxTypes.Transaction>;
transactionViolations?: OnyxCollection<OnyxTypes.TransactionViolations>;
isOffline?: boolean;
}) {
const transactionChanges: TransactionChanges = {
customUnitRateID: rateID,
...(created ? {created} : {}),
...(typeof updatedTaxAmount === 'number' ? {taxAmount: updatedTaxAmount} : {}),
...(updatedTaxCode ? {taxCode: updatedTaxCode} : {}),
...(updatedTaxValue ? {taxValue: updatedTaxValue} : {}),
Expand All @@ -1083,7 +1202,7 @@ function updateMoneyRequestDistanceRate({
let data: UpdateMoneyRequestData<UpdateMoneyRequestDataKeys>;

if (isTrackExpenseReport(transactionThreadReport) && isSelfDM(parentReport)) {
data = getUpdateTrackExpenseParams(transaction?.transactionID, transactionThreadReport?.reportID, transactionChanges, policy, delegateAccountID);
data = getUpdateTrackExpenseParams(transaction?.transactionID, transactionThreadReport?.reportID, transactionChanges, policy, delegateAccountID, hash);
} else {
data = getUpdateMoneyRequestParams({
transactionID: transaction?.transactionID,
Expand All @@ -1099,8 +1218,13 @@ function updateMoneyRequestDistanceRate({
currentUserEmailParam,
isASAPSubmitBetaEnabled,
iouReportNextStep: parentReportNextStep,
isOffline,
hash,
delegateAccountID,
});
if (created && transaction?.transactionID && transactions && transactionViolations) {
removeTransactionFromDuplicateTransactionViolation(data.onyxData, transaction.transactionID, transactions, transactionViolations);
}
}
const {params, onyxData} = data;
// `taxAmount` & `taxCode` only needs to be updated in the optimistic data, so we need to remove them from the params
Expand Down
3 changes: 3 additions & 0 deletions src/libs/actions/TransactionInlineEdit.ts
Original file line number Diff line number Diff line change
Expand Up @@ -178,6 +178,7 @@ type GetIouParamsInput = {
parentReportAction: OnyxEntry<ReportAction>;
transactionThreadReport: OnyxEntry<Report>;
policy: OnyxEntry<Policy>;
policyForTrackExpense?: OnyxEntry<Policy>;
policyCategories: OnyxEntry<PolicyCategories>;
policyTags: OnyxEntry<PolicyTagLists>;
policyRecentlyUsedCategories: OnyxEntry<RecentlyUsedCategories>;
Expand Down Expand Up @@ -205,6 +206,7 @@ function getIouParamsForTransaction({
parentReportAction,
transactionThreadReport,
policy,
policyForTrackExpense,
policyCategories,
policyTags,
policyRecentlyUsedCategories,
Expand Down Expand Up @@ -267,6 +269,7 @@ function getIouParamsForTransaction({
transactionThreadReport: resolvedTransactionThreadReport,
parentReport: resolvedParentReport,
policy,
policyForTrackExpense,
policyCategories,
parentReportNextStep,
currentUserAccountIDParam: currentUserAccountID,
Expand Down
4 changes: 3 additions & 1 deletion src/pages/iou/request/step/IOURequestStepDate.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -102,14 +102,16 @@ function IOURequestStepDate({
const isTransactionDraft = shouldUseTransactionDraft(action);

if (isEditing) {
const effectivePolicy = isTrackExpense ? policyForTrackExpense : policy;
updateMoneyRequestDate({
transactionID,
transactionThreadReport: report,
parentReport,
transactions: duplicateTransactions,
transactionViolations: duplicateTransactionViolations,
value: newCreated,
policy,
policy: effectivePolicy,
policyForTrackExpense,
policyTags,
policyCategories,
currentUserAccountIDParam: currentUserPersonalDetails.accountID,
Expand Down
Loading
Loading