diff --git a/src/libs/OptionsListUtils.ts b/src/libs/OptionsListUtils.ts index f1bdac4a24948..ec4fe88a9ef08 100644 --- a/src/libs/OptionsListUtils.ts +++ b/src/libs/OptionsListUtils.ts @@ -165,7 +165,7 @@ type GetOptionsConfig = { includeSelectedOptions?: boolean; includeTaxRates?: boolean; taxRates?: TaxRatesWithDefault; - policy?: OnyxEntry; + policy?: OnyxEntry | EmptyObject; transaction?: OnyxEntry; includePolicyReportFieldOptions?: boolean; policyReportFieldOptions?: string[]; @@ -1383,7 +1383,7 @@ function getTaxRatesOptions(taxRates: Array>): TaxRatesOption[] /** * Builds the section list for tax rates */ -function getTaxRatesSection(policy: OnyxEntry | undefined, selectedOptions: Tax[], searchInputValue: string, transaction?: OnyxEntry): TaxSection[] { +function getTaxRatesSection(policy: OnyxEntry | EmptyObject, selectedOptions: Tax[], searchInputValue: string, transaction?: OnyxEntry): TaxSection[] { const policyRatesSections = []; const taxes = TransactionUtils.transformedTaxRates(policy, transaction); @@ -1705,7 +1705,7 @@ function getOptions( } if (includeTaxRates) { - const taxRatesOptions = getTaxRatesSection(policy, selectedOptions as Tax[], searchInputValue, transaction); + const taxRatesOptions = getTaxRatesSection(policy ?? {}, selectedOptions as Tax[], searchInputValue, transaction); return { recentReports: [], diff --git a/src/libs/PolicyUtils.ts b/src/libs/PolicyUtils.ts index c234a61bdbd91..7672be56d1020 100644 --- a/src/libs/PolicyUtils.ts +++ b/src/libs/PolicyUtils.ts @@ -265,7 +265,7 @@ function isPaidGroupPolicy(policy: OnyxEntry | EmptyObject): boolean { return policy?.type === CONST.POLICY.TYPE.TEAM || policy?.type === CONST.POLICY.TYPE.CORPORATE; } -function isTaxTrackingEnabled(isPolicyExpenseChat: boolean, policy: OnyxEntry): boolean { +function isTaxTrackingEnabled(isPolicyExpenseChat: boolean, policy: OnyxEntry | EmptyObject): boolean { return (isPolicyExpenseChat && (policy?.tax?.trackingEnabled ?? policy?.isTaxTrackingEnabled)) ?? false; } diff --git a/src/libs/TransactionUtils.ts b/src/libs/TransactionUtils.ts index aa9a874049242..bb38f36808846 100644 --- a/src/libs/TransactionUtils.ts +++ b/src/libs/TransactionUtils.ts @@ -6,6 +6,7 @@ import CONST from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; import type {Policy, RecentWaypoint, Report, TaxRate, TaxRates, Transaction, TransactionViolation} from '@src/types/onyx'; import type {Comment, Receipt, TransactionChanges, TransactionPendingFieldsKey, Waypoint, WaypointCollection} from '@src/types/onyx/Transaction'; +import type {EmptyObject} from '@src/types/utils/EmptyObject'; import {isEmptyObject} from '@src/types/utils/EmptyObject'; import type {IOURequestType} from './actions/IOU'; import {isCorporateCard, isExpensifyCard} from './CardUtils'; @@ -658,7 +659,7 @@ function getRateID(transaction: OnyxEntry): string | undefined { * Gets the tax code based on selected currency. * Returns policy default tax rate if transaction is in policy default currency, otherwise returns foreign default tax rate */ -function getDefaultTaxCode(policy: OnyxEntry, transaction: OnyxEntry, currency?: string | undefined) { +function getDefaultTaxCode(policy: OnyxEntry | EmptyObject, transaction: OnyxEntry, currency?: string | undefined) { const defaultExternalID = policy?.taxRates?.defaultExternalID; const foreignTaxDefault = policy?.taxRates?.foreignTaxDefault; return policy?.outputCurrency === (currency ?? getCurrency(transaction)) ? defaultExternalID : foreignTaxDefault; @@ -667,10 +668,9 @@ function getDefaultTaxCode(policy: OnyxEntry, transaction: OnyxEntry | undefined, transaction?: OnyxEntry): Record { +function transformedTaxRates(policy: OnyxEntry | EmptyObject, transaction?: OnyxEntry): Record { const taxRates = policy?.taxRates; const defaultExternalID = taxRates?.defaultExternalID; @@ -684,14 +684,23 @@ function transformedTaxRates(policy: OnyxEntry | undefined, transaction? const getModifiedName = (data: TaxRate, code: string) => `${data.name} (${data.value})${defaultTaxCode() === code ? ` ${CONST.DOT_SEPARATOR} ${Localize.translateLocal('common.default')}` : ''}`; - const taxes = Object.fromEntries(Object.entries(taxRates?.taxes ?? {}).map(([code, data]) => [code, {...data, code, modifiedName: getModifiedName(data, code), name: data.name}])); - return taxes; + return Object.fromEntries( + Object.entries(taxRates?.taxes ?? {}).map(([code, data]) => [ + code, + { + ...data, + code, + modifiedName: getModifiedName(data, code), + name: data.name, + }, + ]), + ); } /** * Gets the tax value of a selected tax */ -function getTaxValue(policy: OnyxEntry, transaction: OnyxEntry, taxCode: string) { +function getTaxValue(policy: OnyxEntry | EmptyObject, transaction: OnyxEntry, taxCode: string) { return Object.values(transformedTaxRates(policy, transaction)).find((taxRate) => taxRate.code === taxCode)?.value; } diff --git a/src/libs/actions/IOU.ts b/src/libs/actions/IOU.ts index 708060c481314..6a95ebd156385 100644 --- a/src/libs/actions/IOU.ts +++ b/src/libs/actions/IOU.ts @@ -6517,8 +6517,8 @@ function setMoneyRequestParticipantsFromReport(transactionID: string, report: On return participants; } -function setMoneyRequestTaxRate(transactionID: string, taxCode: string) { - Onyx.merge(`${ONYXKEYS.COLLECTION.TRANSACTION_DRAFT}${transactionID}`, {taxCode}); +function setMoneyRequestTaxRate(transactionID: string, taxCode: string, isDraft: boolean) { + Onyx.merge(`${isDraft ? ONYXKEYS.COLLECTION.TRANSACTION_DRAFT : ONYXKEYS.COLLECTION.TRANSACTION}${transactionID}`, {taxCode}); } function setMoneyRequestTaxAmount(transactionID: string, taxAmount: number, isDraft: boolean) { diff --git a/src/pages/iou/request/step/IOURequestStepParticipants.tsx b/src/pages/iou/request/step/IOURequestStepParticipants.tsx index 45e644607d349..a428949587bc0 100644 --- a/src/pages/iou/request/step/IOURequestStepParticipants.tsx +++ b/src/pages/iou/request/step/IOURequestStepParticipants.tsx @@ -4,9 +4,11 @@ import {withOnyx} from 'react-native-onyx'; import FormHelpMessage from '@components/FormHelpMessage'; import useLocalize from '@hooks/useLocalize'; import useThemeStyles from '@hooks/useThemeStyles'; +import * as CurrencyUtils from '@libs/CurrencyUtils'; import DistanceRequestUtils from '@libs/DistanceRequestUtils'; import * as IOUUtils from '@libs/IOUUtils'; import Navigation from '@libs/Navigation/Navigation'; +import {getPolicy, isTaxTrackingEnabled} from '@libs/PolicyUtils'; import * as TransactionUtils from '@libs/TransactionUtils'; import MoneyRequestParticipantsSelector from '@pages/iou/request/MoneyRequestParticipantsSelector'; import * as IOU from '@userActions/IOU'; @@ -81,6 +83,31 @@ function IOURequestStepParticipants({ IOU.navigateToStartStepIfScanFileCannotBeRead(receiptFilename ?? '', receiptPath ?? '', () => {}, iouRequestType, iouType, transactionID, reportID, receiptType ?? ''); }, [receiptType, receiptPath, receiptFilename, iouRequestType, iouType, transactionID, reportID, action]); + const setTaxDetailsOnCategorizing = useCallback( + (participantsArray: Participant[]) => { + if (action !== CONST.IOU.ACTION.CATEGORIZE) { + return; + } + + const isPolicyExpenseChat = participantsArray.length === 1 && participantsArray[0]?.isPolicyExpenseChat; + if (!isPolicyExpenseChat) { + return; + } + + const policyID = participantsArray[0].policyID; + const policy = getPolicy(policyID); + if (!isTaxTrackingEnabled(isPolicyExpenseChat, policy)) { + return; + } + const taxCode = TransactionUtils.getDefaultTaxCode(policy, transaction) ?? ''; + const taxPercentage = TransactionUtils.getTaxValue(policy, transaction, taxCode) ?? ''; + const taxAmount = CurrencyUtils.convertToBackendAmount(TransactionUtils.calculateTaxAmount(taxPercentage, transaction?.amount ?? 0)); + IOU.setMoneyRequestTaxRate(transactionID, taxCode, true); + IOU.setMoneyRequestTaxAmount(transactionID, taxAmount, true); + }, + [action, transaction, transactionID], + ); + const addParticipant = useCallback( (val: Participant[]) => { IOU.setMoneyRequestParticipants(transactionID, val); @@ -96,10 +123,13 @@ function IOURequestStepParticipants({ return; } + // If user is categorizing tracked expense with respective workspace on policy expense chat then update tax details on draft transaction + setTaxDetailsOnCategorizing(val); + // When a participant is selected, the reportID needs to be saved because that's the reportID that will be used in the confirmation step. selectedReportID.current = val[0]?.reportID ?? reportID; }, - [reportID, transactionID], + [reportID, transactionID, setTaxDetailsOnCategorizing], ); const goToNextStep = useCallback(() => { diff --git a/src/pages/iou/request/step/IOURequestStepTaxRatePage.tsx b/src/pages/iou/request/step/IOURequestStepTaxRatePage.tsx index 9376aa65e4e66..66bb49156b4b7 100644 --- a/src/pages/iou/request/step/IOURequestStepTaxRatePage.tsx +++ b/src/pages/iou/request/step/IOURequestStepTaxRatePage.tsx @@ -91,7 +91,7 @@ function IOURequestStepTaxRatePage({ return; } const amountInSmallestCurrencyUnits = CurrencyUtils.convertToBackendAmount(taxAmount); - IOU.setMoneyRequestTaxRate(transaction?.transactionID, taxes?.code ?? ''); + IOU.setMoneyRequestTaxRate(transaction?.transactionID, taxes?.code ?? '', true); IOU.setMoneyRequestTaxAmount(transaction.transactionID, amountInSmallestCurrencyUnits, true); navigateBack();