Skip to content

Commit

Permalink
Merge pull request #42737 from Expensify/revert-42670-revert-40240-mo…
Browse files Browse the repository at this point in the history
…nil-splitBillTaxUpdate

Revert "Revert "Handle tax for split requests"" and fix reported bugs
  • Loading branch information
MonilBhavsar authored Jun 6, 2024
2 parents 198b473 + 62169f6 commit 0ae7feb
Show file tree
Hide file tree
Showing 15 changed files with 188 additions and 60 deletions.
29 changes: 13 additions & 16 deletions src/components/MoneyRequestConfirmationList.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -179,15 +179,6 @@ type MoneyRequestConfirmationListProps = MoneyRequestConfirmationListOnyxProps &

type MoneyRequestConfirmationListItem = Participant | ReportUtils.OptionData;

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);
};

function MoneyRequestConfirmationList({
transaction = null,
onSendMoney,
Expand Down Expand Up @@ -376,15 +367,21 @@ function MoneyRequestConfirmationList({

// Calculate and set tax amount in transaction draft
useEffect(() => {
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);
if (!shouldShowTax || (transaction?.taxAmount !== undefined && previousTransactionAmount === transaction?.amount && previousTransactionCurrency === transaction?.currency)) {
return;
}

IOU.setMoneyRequestTaxAmount(transactionID, amountInSmallestCurrencyUnits, true);
}, [policy, transaction, transactionID, previousTransactionAmount, previousTransactionCurrency, isDistanceRequest]);
let taxAmount;
if (isDistanceRequest) {
taxAmount = DistanceRequestUtils.calculateTaxAmount(policy, transaction, TransactionUtils.getRateID(transaction) ?? '');
} else {
const defaultTaxCode = TransactionUtils.getDefaultTaxCode(policy, transaction) ?? '';
const taxPercentage = TransactionUtils.getTaxValue(policy, transaction, transaction?.taxCode ?? defaultTaxCode) ?? '';
taxAmount = TransactionUtils.calculateTaxAmount(taxPercentage, transaction?.amount ?? 0);
}
const taxAmountInSmallestCurrencyUnits = CurrencyUtils.convertToBackendAmount(Number.parseFloat(taxAmount.toString()));
IOU.setMoneyRequestTaxAmount(transaction?.transactionID ?? '', taxAmountInSmallestCurrencyUnits);
}, [policy, shouldShowTax, previousTransactionAmount, previousTransactionCurrency, transaction, 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
21 changes: 18 additions & 3 deletions src/components/TaxPicker.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import React, {useMemo, useState} from 'react';
import {withOnyx} from 'react-native-onyx';
import type {OnyxEntry} from 'react-native-onyx';
import type {EdgeInsets} from 'react-native-safe-area-context';
import type {ValueOf} from 'type-fest';
import useLocalize from '@hooks/useLocalize';
import useStyleUtils from '@hooks/useStyleUtils';
import * as IOUUtils from '@libs/IOUUtils';
Expand All @@ -11,6 +12,7 @@ import CONST from '@src/CONST';
import type {IOUAction} from '@src/CONST';
import ONYXKEYS from '@src/ONYXKEYS';
import type {Policy, Transaction} from '@src/types/onyx';
import {isEmptyObject} from '@src/types/utils/EmptyObject';
import SelectionList from './SelectionList';
import RadioListItem from './SelectionList/RadioListItem';

Expand All @@ -20,6 +22,9 @@ type TaxPickerOnyxProps = {

/** All the data for the transaction */
transaction: OnyxEntry<Transaction>;

/** The draft transaction that holds data to be persisted on the current split transaction */
splitDraftTransaction: OnyxEntry<Transaction>;
};

type TaxPickerProps = TaxPickerOnyxProps & {
Expand All @@ -46,13 +51,20 @@ type TaxPickerProps = TaxPickerOnyxProps & {
/** The action to take */
// eslint-disable-next-line react/no-unused-prop-types
action?: IOUAction;

/** The type of IOU */
iouType?: ValueOf<typeof CONST.IOU.TYPE>;
};

function TaxPicker({selectedTaxRate = '', policy, transaction, insets, onSubmit}: TaxPickerProps) {
function TaxPicker({selectedTaxRate = '', policy, transaction, insets, onSubmit, action, splitDraftTransaction, iouType}: TaxPickerProps) {
const StyleUtils = useStyleUtils();
const {translate} = useLocalize();
const [searchValue, setSearchValue] = useState('');

const isEditing = action === CONST.IOU.ACTION.EDIT;
const isEditingSplitBill = isEditing && iouType === CONST.IOU.TYPE.SPLIT;
const currentTransaction = isEditingSplitBill && !isEmptyObject(splitDraftTransaction) ? splitDraftTransaction : transaction;

const taxRates = policy?.taxRates;
const taxRatesCount = TransactionUtils.getEnabledTaxRateCount(taxRates?.taxes ?? {});
const isTaxRatesCountBelowThreshold = taxRatesCount < CONST.TAX_RATES_LIST_THRESHOLD;
Expand All @@ -74,8 +86,8 @@ function TaxPicker({selectedTaxRate = '', policy, transaction, insets, onSubmit}
}, [selectedTaxRate]);

const sections = useMemo(
() => OptionsListUtils.getTaxRatesSection(policy, selectedOptions as OptionsListUtils.Tax[], searchValue, transaction),
[searchValue, selectedOptions, policy, transaction],
() => OptionsListUtils.getTaxRatesSection(policy, selectedOptions as OptionsListUtils.Tax[], searchValue, currentTransaction),
[searchValue, selectedOptions, policy, currentTransaction],
);

const headerMessage = OptionsListUtils.getHeaderMessageForNonUserList(sections[0].data.length > 0, searchValue);
Expand Down Expand Up @@ -112,4 +124,7 @@ export default withOnyx<TaxPickerProps, TaxPickerOnyxProps>({
return `${ONYXKEYS.COLLECTION.TRANSACTION}${transactionID}`;
},
},
splitDraftTransaction: {
key: ({transactionID}) => `${ONYXKEYS.COLLECTION.SPLIT_TRANSACTION_DRAFT}${transactionID}`,
},
})(TaxPicker);
2 changes: 2 additions & 0 deletions src/libs/API/parameters/CompleteSplitBillParams.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ type CompleteSplitBillParams = {
category?: string;
tag?: string;
splits: string;
taxCode?: string;
taxAmount?: number;
};

export default CompleteSplitBillParams;
2 changes: 2 additions & 0 deletions src/libs/API/parameters/SplitBillParams.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ type SplitBillParams = {
policyID: string | undefined;
chatType: string | undefined;
splitPayerAccountIDs: number[];
taxCode: string;
taxAmount: number;
};

export default SplitBillParams;
2 changes: 2 additions & 0 deletions src/libs/API/parameters/StartSplitBillParams.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@ type StartSplitBillParams = {
createdReportActionID?: string;
billable: boolean;
chatType?: string;
taxCode?: string;
taxAmount?: number;
};

export default StartSplitBillParams;
53 changes: 42 additions & 11 deletions src/libs/actions/IOU.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3786,6 +3786,8 @@ function createSplitsAndOnyxData(
existingSplitChatReportID = '',
billable = false,
iouRequestType: IOURequestType = CONST.IOU.REQUEST_TYPE.MANUAL,
taxCode = '',
taxAmount = 0,
): SplitsAndOnyxData {
const currentUserEmailForIOUSplit = PhoneNumber.addSMSDomainIfPhoneNumber(currentUserLogin);
const participantAccountIDs = participants.map((participant) => Number(participant.accountID));
Expand All @@ -3807,8 +3809,8 @@ function createSplitsAndOnyxData(
undefined,
category,
tag,
undefined,
undefined,
taxCode,
taxAmount,
billable,
);

Expand Down Expand Up @@ -3963,14 +3965,16 @@ function createSplitsAndOnyxData(

// Loop through participants creating individual chats, iouReports and reportActionIDs as needed
const currentUserAmount = splitShares?.[currentUserAccountID]?.amount ?? IOUUtils.calculateAmount(participants.length, amount, currency, true);
const currentUserTaxAmount = IOUUtils.calculateAmount(participants.length, taxAmount, currency, true);

const splits: Split[] = [{email: currentUserEmailForIOUSplit, accountID: currentUserAccountID, amount: currentUserAmount}];
const splits: Split[] = [{email: currentUserEmailForIOUSplit, accountID: currentUserAccountID, amount: currentUserAmount, taxAmount: currentUserTaxAmount}];

const hasMultipleParticipants = participants.length > 1;
participants.forEach((participant) => {
// In a case when a participant is a workspace, even when a current user is not an owner of the workspace
const isPolicyExpenseChat = ReportUtils.isPolicyExpenseChat(participant);
const splitAmount = splitShares?.[participant.accountID ?? -1]?.amount ?? IOUUtils.calculateAmount(participants.length, amount, currency, false);
const splitTaxAmount = IOUUtils.calculateAmount(participants.length, taxAmount, currency, false);

// To exclude someone from a split, the amount can be 0. The scenario for this is when creating a split from a group chat, we have remove the option to deselect users to exclude them.
// We can input '0' next to someone we want to exclude.
Expand Down Expand Up @@ -4040,8 +4044,8 @@ function createSplitsAndOnyxData(
undefined,
category,
tag,
undefined,
undefined,
taxCode,
ReportUtils.isExpenseReport(oneOnOneIOUReport) ? -splitTaxAmount : splitTaxAmount,
billable,
);

Expand Down Expand Up @@ -4132,6 +4136,7 @@ function createSplitsAndOnyxData(
reportPreviewReportActionID: oneOnOneReportPreviewAction.reportActionID,
transactionThreadReportID: optimisticTransactionThread.reportID,
createdReportActionIDForThread: optimisticCreatedActionForTransactionThread.reportActionID,
taxAmount: splitTaxAmount,
};

splits.push(individualSplit);
Expand Down Expand Up @@ -4185,6 +4190,8 @@ type SplitBillActionsParams = {
existingSplitChatReportID?: string;
splitShares?: SplitShares;
splitPayerAccountIDs?: number[];
taxCode?: string;
taxAmount?: number;
};

/**
Expand All @@ -4207,6 +4214,8 @@ function splitBill({
existingSplitChatReportID = '',
splitShares = {},
splitPayerAccountIDs = [],
taxCode = '',
taxAmount = 0,
}: SplitBillActionsParams) {
const currentCreated = DateUtils.enrichMoneyRequestTimestamp(created);
const {splitData, splits, onyxData} = createSplitsAndOnyxData(
Expand All @@ -4224,6 +4233,8 @@ function splitBill({
existingSplitChatReportID,
billable,
iouRequestType,
taxCode,
taxAmount,
);

const parameters: SplitBillParams = {
Expand All @@ -4243,6 +4254,8 @@ function splitBill({
policyID: splitData.policyID,
chatType: splitData.chatType,
splitPayerAccountIDs,
taxCode,
taxAmount,
};

API.write(WRITE_COMMANDS.SPLIT_BILL, parameters, onyxData);
Expand All @@ -4269,6 +4282,8 @@ function splitBillAndOpenReport({
iouRequestType = CONST.IOU.REQUEST_TYPE.MANUAL,
splitShares = {},
splitPayerAccountIDs = [],
taxCode = '',
taxAmount = 0,
}: SplitBillActionsParams) {
const currentCreated = DateUtils.enrichMoneyRequestTimestamp(created);
const {splitData, splits, onyxData} = createSplitsAndOnyxData(
Expand All @@ -4286,6 +4301,8 @@ function splitBillAndOpenReport({
'',
billable,
iouRequestType,
taxCode,
taxAmount,
);

const parameters: SplitBillParams = {
Expand All @@ -4305,6 +4322,8 @@ function splitBillAndOpenReport({
policyID: splitData.policyID,
chatType: splitData.chatType,
splitPayerAccountIDs,
taxCode,
taxAmount,
};

API.write(WRITE_COMMANDS.SPLIT_BILL_AND_OPEN_REPORT, parameters, onyxData);
Expand All @@ -4324,6 +4343,8 @@ type StartSplitBilActionParams = {
category: string | undefined;
tag: string | undefined;
currency: string;
taxCode: string;
taxAmount: number;
};

/** Used exclusively for starting a split expense request that contains a receipt, the split request will be completed once the receipt is scanned
Expand All @@ -4342,6 +4363,8 @@ function startSplitBill({
category = '',
tag = '',
currency,
taxCode = '',
taxAmount = 0,
}: StartSplitBilActionParams) {
const currentUserEmailForIOUSplit = PhoneNumber.addSMSDomainIfPhoneNumber(currentUserLogin);
const participantAccountIDs = participants.map((participant) => Number(participant.accountID));
Expand All @@ -4366,8 +4389,8 @@ function startSplitBill({
undefined,
category,
tag,
undefined,
undefined,
taxCode,
taxAmount,
billable,
);

Expand Down Expand Up @@ -4609,6 +4632,8 @@ function startSplitBill({
billable,
...(existingSplitChatReport ? {} : {createdReportActionID: splitChatCreatedReportAction.reportActionID}),
chatType: splitChatReport?.chatType,
taxCode,
taxAmount,
};

API.write(WRITE_COMMANDS.START_SPLIT_BILL, parameters, {optimisticData, successData, failureData});
Expand Down Expand Up @@ -4693,9 +4718,11 @@ function completeSplitBill(chatReportID: string, reportAction: OnyxTypes.ReportA
const splitParticipants: Split[] = updatedTransaction?.comment.splits ?? [];
const amount = updatedTransaction?.modifiedAmount;
const currency = updatedTransaction?.modifiedCurrency;
console.debug(updatedTransaction);

// Exclude the current user when calculating the split amount, `calculateAmount` takes it into account
const splitAmount = IOUUtils.calculateAmount(splitParticipants.length - 1, amount ?? 0, currency ?? '', false);
const splitTaxAmount = IOUUtils.calculateAmount(splitParticipants.length - 1, updatedTransaction?.taxAmount ?? 0, currency ?? '', false);

const splits: Split[] = [{email: currentUserEmailForIOUSplit}];
splitParticipants.forEach((participant) => {
Expand Down Expand Up @@ -4759,8 +4786,8 @@ function completeSplitBill(chatReportID: string, reportAction: OnyxTypes.ReportA
undefined,
updatedTransaction?.category,
updatedTransaction?.tag,
undefined,
undefined,
updatedTransaction?.taxCode,
isPolicyExpenseChat ? -splitTaxAmount : splitAmount,
updatedTransaction?.billable,
);

Expand Down Expand Up @@ -4834,6 +4861,8 @@ function completeSplitBill(chatReportID: string, reportAction: OnyxTypes.ReportA
comment: transactionComment,
category: transactionCategory,
tag: transactionTag,
taxCode: transactionTaxCode,
taxAmount: transactionTaxAmount,
} = ReportUtils.getTransactionDetails(updatedTransaction) ?? {};

const parameters: CompleteSplitBillParams = {
Expand All @@ -4846,6 +4875,8 @@ function completeSplitBill(chatReportID: string, reportAction: OnyxTypes.ReportA
category: transactionCategory,
tag: transactionTag,
splits: JSON.stringify(splits),
taxCode: transactionTaxCode,
taxAmount: transactionTaxAmount,
};

API.write(WRITE_COMMANDS.COMPLETE_SPLIT_BILL, parameters, {optimisticData, successData, failureData});
Expand Down Expand Up @@ -6607,8 +6638,8 @@ function setMoneyRequestTaxRate(transactionID: string, taxCode: string) {
Onyx.merge(`${ONYXKEYS.COLLECTION.TRANSACTION_DRAFT}${transactionID}`, {taxCode});
}

function setMoneyRequestTaxAmount(transactionID: string, taxAmount: number, isDraft: boolean) {
Onyx.merge(`${isDraft ? ONYXKEYS.COLLECTION.TRANSACTION_DRAFT : ONYXKEYS.COLLECTION.TRANSACTION}${transactionID}`, {taxAmount});
function setMoneyRequestTaxAmount(transactionID: string, taxAmount: number | null) {
Onyx.merge(`${ONYXKEYS.COLLECTION.TRANSACTION_DRAFT}${transactionID}`, {taxAmount});
}

function setShownHoldUseExplanation() {
Expand Down
Loading

0 comments on commit 0ae7feb

Please sign in to comment.