Skip to content

Commit

Permalink
Merge pull request Expensify#42909 from Expensify/monil-fixDistanceTa…
Browse files Browse the repository at this point in the history
…xOffline

Fix distance tax rate and amount not updating offline and inaccurate tax amount and refactor code
  • Loading branch information
MonilBhavsar authored Jun 4, 2024
2 parents d3e3920 + 5a61263 commit 1d5f83d
Show file tree
Hide file tree
Showing 9 changed files with 58 additions and 27 deletions.
10 changes: 6 additions & 4 deletions src/components/MoneyRequestConfirmationList.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -179,9 +179,11 @@ type MoneyRequestConfirmationListProps = MoneyRequestConfirmationListOnyxProps &

type MoneyRequestConfirmationListItem = Participant | ReportUtils.OptionData;

const getTaxAmount = (transaction: OnyxEntry<OnyxTypes.Transaction>, policy: OnyxEntry<OnyxTypes.Policy>) => {
const getTaxAmount = (transaction: OnyxEntry<OnyxTypes.Transaction>, policy: OnyxEntry<OnyxTypes.Policy>, isDistanceRequest: boolean) => {
if (isDistanceRequest) {
return DistanceRequestUtils.calculateTaxAmount(policy, transaction, TransactionUtils.getRateID(transaction) ?? '');
}
const defaultTaxCode = TransactionUtils.getDefaultTaxCode(policy, transaction) ?? '';

const taxPercentage = TransactionUtils.getTaxValue(policy, transaction, transaction?.taxCode ?? defaultTaxCode) ?? '';
return TransactionUtils.calculateTaxAmount(taxPercentage, transaction?.amount ?? 0);
};
Expand Down Expand Up @@ -372,15 +374,15 @@ function MoneyRequestConfirmationList({

// Calculate and set tax amount in transaction draft
useEffect(() => {
const taxAmount = getTaxAmount(transaction, policy).toString();
const taxAmount = getTaxAmount(transaction, policy, isDistanceRequest).toString();
const amountInSmallestCurrencyUnits = CurrencyUtils.convertToBackendAmount(Number.parseFloat(taxAmount));

if (transaction?.taxAmount && previousTransactionAmount === transaction?.amount && previousTransactionCurrency === transaction?.currency) {
return IOU.setMoneyRequestTaxAmount(transactionID, transaction?.taxAmount ?? 0, true);
}

IOU.setMoneyRequestTaxAmount(transactionID, amountInSmallestCurrencyUnits, true);
}, [policy, transaction, transactionID, previousTransactionAmount, previousTransactionCurrency]);
}, [policy, transaction, transactionID, previousTransactionAmount, previousTransactionCurrency, isDistanceRequest]);

// If completing a split expense fails, set didConfirm to false to allow the user to edit the fields again
if (isEditingSplitBill && didConfirm) {
Expand Down
26 changes: 23 additions & 3 deletions src/libs/DistanceRequestUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,14 @@ import type {LocaleContextProps} from '@components/LocaleContextProvider';
import type {RateAndUnit} from '@src/CONST';
import CONST from '@src/CONST';
import ONYXKEYS from '@src/ONYXKEYS';
import type {LastSelectedDistanceRates, Report} from '@src/types/onyx';
import type {LastSelectedDistanceRates, Report, Transaction} from '@src/types/onyx';
import type {Unit} from '@src/types/onyx/Policy';
import type Policy from '@src/types/onyx/Policy';
import type {EmptyObject} from '@src/types/utils/EmptyObject';
import * as CurrencyUtils from './CurrencyUtils';
import * as PolicyUtils from './PolicyUtils';
import * as ReportUtils from './ReportUtils';
import * as TransactionUtils from './TransactionUtils';

type MileageRate = {
customUnitRateID?: string;
Expand Down Expand Up @@ -53,7 +54,7 @@ function getDefaultMileageRate(policy: OnyxEntry<Policy> | EmptyObject): Mileage
return null;
}

const distanceUnit = Object.values(policy.customUnits).find((unit) => unit.name === CONST.CUSTOM_UNITS.NAME_DISTANCE);
const distanceUnit = PolicyUtils.getCustomUnit(policy);
if (!distanceUnit?.rates) {
return null;
}
Expand Down Expand Up @@ -193,7 +194,7 @@ function getMileageRates(policy: OnyxEntry<Policy>): Record<string, MileageRate>
return mileageRates;
}

const distanceUnit = Object.values(policy.customUnits).find((unit) => unit.name === CONST.CUSTOM_UNITS.NAME_DISTANCE);
const distanceUnit = PolicyUtils.getCustomUnit(policy);
if (!distanceUnit?.rates) {
return mileageRates;
}
Expand Down Expand Up @@ -266,6 +267,24 @@ function getCustomUnitRateID(reportID: string) {
return customUnitRateID;
}

function calculateTaxAmount(policy: OnyxEntry<Policy>, transaction: OnyxEntry<Transaction>, customUnitRateID: string) {
const distanceUnit = PolicyUtils.getCustomUnit(policy);
const customUnitID = distanceUnit?.customUnitID;
if (!policy?.customUnits || !customUnitID) {
return 0;
}
const policyCustomUnitRate = policy?.customUnits[customUnitID].rates[customUnitRateID];
const unit = policy?.customUnits[customUnitID]?.attributes?.unit ?? CONST.CUSTOM_UNITS.DISTANCE_UNIT_MILES;
const rate = policyCustomUnitRate?.rate ?? 0;
const distance = TransactionUtils.getDistance(transaction);
const amount = getDistanceRequestAmount(distance, unit, rate);
const taxClaimablePercentage = policyCustomUnitRate.attributes?.taxClaimablePercentage ?? 0;
const taxRateExternalID = policyCustomUnitRate.attributes?.taxRateExternalID ?? '';
const taxableAmount = amount * taxClaimablePercentage;
const taxPercentage = TransactionUtils.getTaxValue(policy, transaction, taxRateExternalID) ?? '';
return TransactionUtils.calculateTaxAmount(taxPercentage, taxableAmount);
}

export default {
getDefaultMileageRate,
getDistanceMerchant,
Expand All @@ -276,6 +295,7 @@ export default {
getRateForP2P,
getCustomUnitRateID,
convertToDistanceInMeters,
calculateTaxAmount,
};

export type {MileageRate};
10 changes: 9 additions & 1 deletion src/libs/PolicyUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,13 @@ function getNumericValue(value: number | string, toLocaleDigit: (arg: string) =>
return numValue.toFixed(CONST.CUSTOM_UNITS.RATE_DECIMALS);
}

/**
* Retrieves the distance custom unit object for the given policy
*/
function getCustomUnit(policy: OnyxEntry<Policy> | EmptyObject) {
return Object.values(policy?.customUnits ?? {}).find((unit) => unit.name === CONST.CUSTOM_UNITS.NAME_DISTANCE);
}

function getRateDisplayValue(value: number, toLocaleDigit: (arg: string) => string): string {
const numValue = getNumericValue(value, toLocaleDigit);
if (Number.isNaN(numValue)) {
Expand Down Expand Up @@ -278,7 +285,7 @@ function isPaidGroupPolicy(policy: OnyxEntry<Policy> | EmptyObject): boolean {
}

function isTaxTrackingEnabled(isPolicyExpenseChat: boolean, policy: OnyxEntry<Policy>, isDistanceRequest: boolean): boolean {
const distanceUnit = Object.values(policy?.customUnits ?? {}).find((unit) => unit.name === CONST.CUSTOM_UNITS.NAME_DISTANCE);
const distanceUnit = getCustomUnit(policy);
const customUnitID = distanceUnit?.customUnitID ?? 0;
const isPolicyTaxTrackingEnabled = isPolicyExpenseChat && policy?.tax?.trackingEnabled;
const isTaxEnabledForDistance = isPolicyTaxTrackingEnabled && policy?.customUnits?.[customUnitID]?.attributes?.taxEnabled;
Expand Down Expand Up @@ -505,6 +512,7 @@ export {
findCurrentXeroOrganization,
getCurrentXeroOrganizationName,
getXeroBankAccountsWithDefaultSelect,
getCustomUnit,
sortWorkspacesBySelected,
};

Expand Down
8 changes: 4 additions & 4 deletions src/libs/actions/Policy/Policy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1567,14 +1567,14 @@ function clearAvatarErrors(policyID: string) {
*/
function updateGeneralSettings(policyID: string, name: string, currencyValue?: string) {
const policy = allPolicies?.[`${ONYXKEYS.COLLECTION.POLICY}${policyID}`];
const distanceUnit = Object.values(policy?.customUnits ?? {}).find((unit) => unit.name === CONST.CUSTOM_UNITS.NAME_DISTANCE);
const customUnitID = distanceUnit?.customUnitID;
const currency = currencyValue ?? policy?.outputCurrency ?? CONST.CURRENCY.USD;

if (!policy) {
return;
}

const distanceUnit = PolicyUtils.getCustomUnit(policy);
const customUnitID = distanceUnit?.customUnitID;
const currency = currencyValue ?? policy?.outputCurrency ?? CONST.CURRENCY.USD;

const currentRates = distanceUnit?.rates ?? {};
const optimisticRates: Record<string, Rate> = {};
const finallyRates: Record<string, Rate> = {};
Expand Down
14 changes: 6 additions & 8 deletions src/pages/iou/request/step/IOURequestStepDistanceRate.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import * as CurrencyUtils from '@libs/CurrencyUtils';
import type {MileageRate} from '@libs/DistanceRequestUtils';
import DistanceRequestUtils from '@libs/DistanceRequestUtils';
import Navigation from '@libs/Navigation/Navigation';
import {isTaxTrackingEnabled} from '@libs/PolicyUtils';
import {getCustomUnit, isTaxTrackingEnabled} from '@libs/PolicyUtils';
import * as ReportUtils from '@libs/ReportUtils';
import * as TransactionUtils from '@libs/TransactionUtils';
import CONST from '@src/CONST';
Expand Down Expand Up @@ -50,7 +50,7 @@ function IOURequestStepDistanceRate({
const styles = useThemeStyles();
const {translate, toLocaleDigit} = useLocalize();
const isDistanceRequest = TransactionUtils.isDistanceRequest(transaction);
const distanceUnit = Object.values(policy?.customUnits ?? {}).find((unit) => unit.name === CONST.CUSTOM_UNITS.NAME_DISTANCE);
const distanceUnit = getCustomUnit(policy);
const customUnitID = distanceUnit?.customUnitID;
const isPolicyExpenseChat = ReportUtils.isReportInGroupPolicy(report);
const shouldShowTax = isTaxTrackingEnabled(isPolicyExpenseChat, policy, isDistanceRequest);
Expand Down Expand Up @@ -78,12 +78,10 @@ function IOURequestStepDistanceRate({
const initiallyFocusedOption = sections.find((item) => item.isSelected)?.keyForList;

function selectDistanceRate(customUnitRateID: string) {
if (transaction?.amount && policy?.customUnits && customUnitID && shouldShowTax) {
const taxClaimablePercentage = policy?.customUnits[customUnitID].rates[customUnitRateID].attributes?.taxClaimablePercentage ?? 0;
const taxRateExternalID = policy?.customUnits[customUnitID].rates[customUnitRateID].attributes?.taxRateExternalID ?? '';
const taxableAmount = -1 * transaction.amount * taxClaimablePercentage;
const taxPercentage = TransactionUtils.getTaxValue(policy, transaction, taxRateExternalID) ?? '';
const taxAmount = CurrencyUtils.convertToBackendAmount(TransactionUtils.calculateTaxAmount(taxPercentage, taxableAmount));
if (policy?.customUnits && customUnitID && shouldShowTax) {
const policyCustomUnitRate = policy?.customUnits[customUnitID].rates[customUnitRateID];
const taxRateExternalID = policyCustomUnitRate.attributes?.taxRateExternalID ?? '';
const taxAmount = CurrencyUtils.convertToBackendAmount(DistanceRequestUtils.calculateTaxAmount(policy, transaction, customUnitRateID));
IOU.setMoneyRequestTaxAmount(transactionID, taxAmount, true);
IOU.setMoneyRequestTaxRate(transactionID, taxRateExternalID);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import useThemeStyles from '@hooks/useThemeStyles';
import compose from '@libs/compose';
import * as CurrencyUtils from '@libs/CurrencyUtils';
import Navigation from '@libs/Navigation/Navigation';
import * as PolicyUtils from '@libs/PolicyUtils';
import {getUnitTranslationKey} from '@libs/WorkspacesSettingsUtils';
import withPolicy from '@pages/workspace/withPolicy';
import type {WithPolicyProps} from '@pages/workspace/withPolicy';
Expand Down Expand Up @@ -62,7 +63,7 @@ function WorkspaceRateAndUnitPage(props: WorkspaceRateAndUnitPageProps) {
}, [props]);

const saveUnitAndRate = (newUnit: Unit, newRate: string) => {
const distanceCustomUnit = Object.values(props.policy?.customUnits ?? {}).find((unit) => unit.name === CONST.CUSTOM_UNITS.NAME_DISTANCE);
const distanceCustomUnit = PolicyUtils.getCustomUnit(props.policy);
if (!distanceCustomUnit) {
return;
}
Expand All @@ -82,7 +83,7 @@ function WorkspaceRateAndUnitPage(props: WorkspaceRateAndUnitPageProps) {
Policy.updateWorkspaceCustomUnitAndRate(props.policy?.id ?? '', distanceCustomUnit, newCustomUnit, props.policy?.lastModified);
};

const distanceCustomUnit = Object.values(props.policy?.customUnits ?? {}).find((unit) => unit.name === CONST.CUSTOM_UNITS.NAME_DISTANCE);
const distanceCustomUnit = PolicyUtils.getCustomUnit(props.policy);
const distanceCustomRate = Object.values(distanceCustomUnit?.rates ?? {}).find((rate) => rate.name === CONST.CUSTOM_UNITS.DEFAULT_RATE);

const unitValue = props.workspaceRateAndUnit?.unit ?? distanceCustomUnit?.attributes.unit ?? CONST.CUSTOM_UNITS.DISTANCE_UNIT_MILES;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import useThemeStyles from '@hooks/useThemeStyles';
import compose from '@libs/compose';
import Navigation from '@libs/Navigation/Navigation';
import {validateRateValue} from '@libs/PolicyDistanceRatesUtils';
import * as PolicyUtils from '@libs/PolicyUtils';
import withPolicy from '@pages/workspace/withPolicy';
import type {WithPolicyProps} from '@pages/workspace/withPolicy';
import WorkspacePageWithSections from '@pages/workspace/WorkspacePageWithSections';
Expand Down Expand Up @@ -53,10 +54,10 @@ function WorkspaceRatePage(props: WorkspaceRatePageProps) {
);

const defaultValue = useMemo(() => {
const defaultDistanceCustomUnit = Object.values(props.policy?.customUnits ?? {}).find((unit) => unit.name === CONST.CUSTOM_UNITS.NAME_DISTANCE);
const defaultDistanceCustomUnit = PolicyUtils.getCustomUnit(props.policy);
const distanceCustomRate = Object.values(defaultDistanceCustomUnit?.rates ?? {}).find((rate) => rate.name === CONST.CUSTOM_UNITS.DEFAULT_RATE);
return distanceCustomRate?.rate ?? 0;
}, [props.policy?.customUnits]);
}, [props.policy]);

return (
<WorkspacePageWithSections
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import useLocalize from '@hooks/useLocalize';
import useThemeStyles from '@hooks/useThemeStyles';
import compose from '@libs/compose';
import Navigation from '@libs/Navigation/Navigation';
import * as PolicyUtils from '@libs/PolicyUtils';
import withPolicy from '@pages/workspace/withPolicy';
import type {WithPolicyProps} from '@pages/workspace/withPolicy';
import WorkspacePageWithSections from '@pages/workspace/WorkspacePageWithSections';
Expand Down Expand Up @@ -42,9 +43,9 @@ function WorkspaceUnitPage(props: WorkspaceUnitPageProps) {
};

const defaultValue = useMemo(() => {
const defaultDistanceCustomUnit = Object.values(props.policy?.customUnits ?? {}).find((unit) => unit.name === CONST.CUSTOM_UNITS.NAME_DISTANCE);
const defaultDistanceCustomUnit = PolicyUtils.getCustomUnit(props.policy);
return defaultDistanceCustomUnit?.attributes.unit ?? CONST.CUSTOM_UNITS.DISTANCE_UNIT_MILES;
}, [props.policy?.customUnits]);
}, [props.policy]);

return (
<WorkspacePageWithSections
Expand Down
2 changes: 1 addition & 1 deletion src/pages/workspace/reimburse/WorkspaceReimburseView.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ function WorkspaceReimburseView({policy, reimbursementAccount}: WorkspaceReimbur
const [currentRatePerUnit, setCurrentRatePerUnit] = useState<string>('');
const {isSmallScreenWidth} = useWindowDimensions();
const viewAllReceiptsUrl = `expenses?policyIDList=${policy?.id ?? ''}&billableReimbursable=reimbursable&submitterEmail=%2B%2B`;
const distanceCustomUnit = Object.values(policy?.customUnits ?? {}).find((unit) => unit.name === CONST.CUSTOM_UNITS.NAME_DISTANCE);
const distanceCustomUnit = PolicyUtils.getCustomUnit(policy);
const distanceCustomRate = Object.values(distanceCustomUnit?.rates ?? {}).find((rate) => rate.name === CONST.CUSTOM_UNITS.DEFAULT_RATE);
const {translate, toLocaleDigit} = useLocalize();
const {isOffline} = useNetwork();
Expand Down

0 comments on commit 1d5f83d

Please sign in to comment.