Skip to content

Commit

Permalink
Merge pull request #54579 from bernhardoj/fix/54513-don't-apply-the-c…
Browse files Browse the repository at this point in the history
…ategory-rule-for-distance

Don't apply the category tax rules for distance request
  • Loading branch information
MonilBhavsar authored Dec 27, 2024
2 parents 32fcf17 + c35bddc commit f593c21
Show file tree
Hide file tree
Showing 4 changed files with 269 additions and 87 deletions.
10 changes: 8 additions & 2 deletions src/libs/TransactionUtils/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -376,6 +376,11 @@ function getUpdatedTransaction({

if (Object.hasOwn(transactionChanges, 'category') && typeof transactionChanges.category === 'string') {
updatedTransaction.category = transactionChanges.category;
const {categoryTaxCode, categoryTaxAmount} = getCategoryTaxCodeAndAmount(transactionChanges.category, transaction, policy);
if (categoryTaxCode && categoryTaxAmount !== undefined) {
updatedTransaction.taxCode = categoryTaxCode;
updatedTransaction.taxAmount = categoryTaxAmount;
}
}

if (Object.hasOwn(transactionChanges, 'tag') && typeof transactionChanges.tag === 'string') {
Expand Down Expand Up @@ -1258,11 +1263,12 @@ function buildTransactionsMergeParams(reviewDuplicates: OnyxEntry<ReviewDuplicat

function getCategoryTaxCodeAndAmount(category: string, transaction: OnyxEntry<Transaction>, policy: OnyxEntry<Policy>) {
const taxRules = policy?.rules?.expenseRules?.filter((rule) => rule.tax);
if (!taxRules || taxRules?.length === 0) {
if (!taxRules || taxRules?.length === 0 || isDistanceRequest(transaction)) {
return {categoryTaxCode: undefined, categoryTaxAmount: undefined};
}

const categoryTaxCode = getCategoryDefaultTaxRate(taxRules, category, policy?.taxRates?.defaultExternalID);
const defaultTaxCode = getDefaultTaxCode(policy, transaction, getCurrency(transaction));
const categoryTaxCode = getCategoryDefaultTaxRate(taxRules, category, defaultTaxCode);
const categoryTaxPercentage = getTaxValue(policy, transaction, categoryTaxCode ?? '');
let categoryTaxAmount;

Expand Down
19 changes: 2 additions & 17 deletions src/libs/actions/IOU.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3463,15 +3463,8 @@ function updateMoneyRequestCategory(
policyTagList: OnyxEntry<OnyxTypes.PolicyTagLists>,
policyCategories: OnyxEntry<OnyxTypes.PolicyCategories>,
) {
const transaction = allTransactions[`${ONYXKEYS.COLLECTION.TRANSACTION}${transactionID}`];
const {categoryTaxCode, categoryTaxAmount} = TransactionUtils.getCategoryTaxCodeAndAmount(category, transaction, policy);
const transactionChanges: TransactionChanges = {
category,
...(categoryTaxCode &&
categoryTaxAmount !== undefined && {
taxCode: categoryTaxCode,
taxAmount: categoryTaxAmount,
}),
};

const {params, onyxData} = getUpdateMoneyRequestParams(transactionID, transactionThreadReportID, transactionChanges, policy, policyTagList, policyCategories);
Expand Down Expand Up @@ -5399,27 +5392,19 @@ function completeSplitBill(chatReportID: string, reportAction: OnyxTypes.ReportA
}

function setDraftSplitTransaction(transactionID: string, transactionChanges: TransactionChanges = {}, policy?: OnyxEntry<OnyxTypes.Policy>) {
const newTransactionChanges = {...transactionChanges};
let draftSplitTransaction = allDraftSplitTransactions[`${ONYXKEYS.COLLECTION.SPLIT_TRANSACTION_DRAFT}${transactionID}`];

if (!draftSplitTransaction) {
draftSplitTransaction = allTransactions[`${ONYXKEYS.COLLECTION.TRANSACTION}${transactionID}`];
}

if (transactionChanges.category) {
const {categoryTaxCode, categoryTaxAmount} = TransactionUtils.getCategoryTaxCodeAndAmount(transactionChanges.category, draftSplitTransaction, policy);
if (categoryTaxCode && categoryTaxAmount !== undefined) {
newTransactionChanges.taxCode = categoryTaxCode;
newTransactionChanges.taxAmount = categoryTaxAmount;
}
}

const updatedTransaction = draftSplitTransaction
? TransactionUtils.getUpdatedTransaction({
transaction: draftSplitTransaction,
transactionChanges: newTransactionChanges,
transactionChanges,
isFromExpenseReport: false,
shouldUpdateReceiptState: false,
policy,
})
: null;

Expand Down
224 changes: 167 additions & 57 deletions tests/actions/IOUTest.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3550,40 +3550,82 @@ describe('actions/IOU', () => {
});
});

it('should not change the tax if there are no tax expense rules', async () => {
// Given a policy without tax expense rules
const transactionID = '1';
const category = 'Advertising';
const policyID = '2';
const taxCode = 'id_TAX_EXEMPT';
const taxAmount = 0;
const fakePolicy: OnyxTypes.Policy = {
...createRandomPolicy(Number(policyID)),
taxRates: CONST.DEFAULT_TAX,
rules: {},
};
await Onyx.merge(`${ONYXKEYS.COLLECTION.TRANSACTION_DRAFT}${transactionID}`, {
taxCode,
taxAmount,
amount: 100,
describe('should not change the tax', () => {
it('if the transaction type is distance', async () => {
// Given a policy with tax expense rules associated with category and a distance transaction
const transactionID = '1';
const category = 'Advertising';
const policyID = '2';
const taxCode = 'id_TAX_EXEMPT';
const ruleTaxCode = 'id_TAX_RATE_1';
const taxAmount = 0;
const fakePolicy: OnyxTypes.Policy = {
...createRandomPolicy(Number(policyID)),
taxRates: CONST.DEFAULT_TAX,
rules: {expenseRules: createCategoryTaxExpenseRules(category, ruleTaxCode)},
};
await Onyx.merge(`${ONYXKEYS.COLLECTION.TRANSACTION_DRAFT}${transactionID}`, {
taxCode,
taxAmount,
amount: 100,
iouRequestType: CONST.IOU.REQUEST_TYPE.DISTANCE,
});
await Onyx.merge(`${ONYXKEYS.COLLECTION.POLICY}${policyID}`, fakePolicy);

// When setting the money request category
IOU.setMoneyRequestCategory(transactionID, category, policyID);

await waitForBatchedUpdates();

// Then the transaction tax rate and amount shouldn't be updated
await new Promise<void>((resolve) => {
const connection = Onyx.connect({
key: `${ONYXKEYS.COLLECTION.TRANSACTION_DRAFT}${transactionID}`,
callback: (transaction) => {
Onyx.disconnect(connection);
expect(transaction?.taxCode).toBe(taxCode);
expect(transaction?.taxAmount).toBe(taxAmount);
resolve();
},
});
});
});
await Onyx.merge(`${ONYXKEYS.COLLECTION.POLICY}${policyID}`, fakePolicy);

// When setting the money request category
IOU.setMoneyRequestCategory(transactionID, category, policyID);
it('if there are no tax expense rules', async () => {
// Given a policy without tax expense rules
const transactionID = '1';
const category = 'Advertising';
const policyID = '2';
const taxCode = 'id_TAX_EXEMPT';
const taxAmount = 0;
const fakePolicy: OnyxTypes.Policy = {
...createRandomPolicy(Number(policyID)),
taxRates: CONST.DEFAULT_TAX,
rules: {},
};
await Onyx.merge(`${ONYXKEYS.COLLECTION.TRANSACTION_DRAFT}${transactionID}`, {
taxCode,
taxAmount,
amount: 100,
});
await Onyx.merge(`${ONYXKEYS.COLLECTION.POLICY}${policyID}`, fakePolicy);

await waitForBatchedUpdates();
// When setting the money request category
IOU.setMoneyRequestCategory(transactionID, category, policyID);

// Then the transaction tax rate and amount shouldn't be updated
await new Promise<void>((resolve) => {
const connection = Onyx.connect({
key: `${ONYXKEYS.COLLECTION.TRANSACTION_DRAFT}${transactionID}`,
callback: (transaction) => {
Onyx.disconnect(connection);
expect(transaction?.taxCode).toBe(taxCode);
expect(transaction?.taxAmount).toBe(taxAmount);
resolve();
},
await waitForBatchedUpdates();

// Then the transaction tax rate and amount shouldn't be updated
await new Promise<void>((resolve) => {
const connection = Onyx.connect({
key: `${ONYXKEYS.COLLECTION.TRANSACTION_DRAFT}${transactionID}`,
callback: (transaction) => {
Onyx.disconnect(connection);
expect(transaction?.taxCode).toBe(taxCode);
expect(transaction?.taxAmount).toBe(taxAmount);
resolve();
},
});
});
});
});
Expand Down Expand Up @@ -3623,6 +3665,7 @@ describe('actions/IOU', () => {
// Given a policy with tax expense rules associated with category
const transactionID = '1';
const policyID = '2';
const transactionThreadReportID = '3';
const category = 'Advertising';
const taxCode = 'id_TAX_EXEMPT';
const ruleTaxCode = 'id_TAX_RATE_1';
Expand All @@ -3637,9 +3680,10 @@ describe('actions/IOU', () => {
amount: 100,
});
await Onyx.merge(`${ONYXKEYS.COLLECTION.POLICY}${policyID}`, fakePolicy);
await Onyx.merge(`${ONYXKEYS.COLLECTION.REPORT}${transactionThreadReportID}`, {reportID: transactionThreadReportID});

// When updating a money request category
IOU.updateMoneyRequestCategory(transactionID, '3', category, fakePolicy, undefined, undefined);
IOU.updateMoneyRequestCategory(transactionID, transactionThreadReportID, category, fakePolicy, undefined, undefined);

await waitForBatchedUpdates();

Expand All @@ -3655,37 +3699,103 @@ describe('actions/IOU', () => {
},
});
});
});

it('should not update the tax when there are no tax expense rules', async () => {
// Given a policy without tax expense rules
const transactionID = '1';
const policyID = '2';
const category = 'Advertising';
const fakePolicy: OnyxTypes.Policy = {
...createRandomPolicy(Number(policyID)),
taxRates: CONST.DEFAULT_TAX,
rules: {},
};
await Onyx.merge(`${ONYXKEYS.COLLECTION.TRANSACTION}${transactionID}`, {amount: 100});
await Onyx.merge(`${ONYXKEYS.COLLECTION.POLICY}${policyID}`, fakePolicy);

// When updating the money request category
IOU.updateMoneyRequestCategory(transactionID, '3', category, fakePolicy, undefined, undefined);

await waitForBatchedUpdates();

// Then the transaction tax rate and amount shouldn't be updated
// But the original message should only contains the old and new category data
await new Promise<void>((resolve) => {
const connection = Onyx.connect({
key: `${ONYXKEYS.COLLECTION.TRANSACTION}${transactionID}`,
callback: (transaction) => {
key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${transactionThreadReportID}`,
callback: (reportActions) => {
Onyx.disconnect(connection);
expect(transaction?.taxCode).toBeUndefined();
expect(transaction?.taxAmount).toBeUndefined();
resolve();
const reportAction = Object.values(reportActions ?? {}).at(0);
if (ReportActionsUtils.isActionOfType(reportAction, CONST.REPORT.ACTIONS.TYPE.MODIFIED_EXPENSE)) {
const originalMessage = ReportActionsUtils.getOriginalMessage(reportAction);
expect(originalMessage?.oldCategory).toBe('');
expect(originalMessage?.category).toBe(category);
expect(originalMessage?.oldTaxRate).toBeUndefined();
expect(originalMessage?.oldTaxAmount).toBeUndefined();
resolve();
}
},
});
});
});

describe('should not update the tax', () => {
it('if the transaction type is distance', async () => {
// Given a policy with tax expense rules associated with category and a distance transaction
const transactionID = '1';
const policyID = '2';
const category = 'Advertising';
const taxCode = 'id_TAX_EXEMPT';
const taxAmount = 0;
const ruleTaxCode = 'id_TAX_RATE_1';
const fakePolicy: OnyxTypes.Policy = {
...createRandomPolicy(Number(policyID)),
taxRates: CONST.DEFAULT_TAX,
rules: {expenseRules: createCategoryTaxExpenseRules(category, ruleTaxCode)},
};
await Onyx.merge(`${ONYXKEYS.COLLECTION.TRANSACTION}${transactionID}`, {
taxCode,
taxAmount,
amount: 100,
comment: {
type: CONST.TRANSACTION.TYPE.CUSTOM_UNIT,
customUnit: {
name: CONST.CUSTOM_UNITS.NAME_DISTANCE,
},
},
});
await Onyx.merge(`${ONYXKEYS.COLLECTION.POLICY}${policyID}`, fakePolicy);

// When updating a money request category
IOU.updateMoneyRequestCategory(transactionID, '3', category, fakePolicy, undefined, undefined);

await waitForBatchedUpdates();

// Then the transaction tax rate and amount shouldn't be updated
await new Promise<void>((resolve) => {
const connection = Onyx.connect({
key: `${ONYXKEYS.COLLECTION.TRANSACTION}${transactionID}`,
callback: (transaction) => {
Onyx.disconnect(connection);
expect(transaction?.taxCode).toBe(taxCode);
expect(transaction?.taxAmount).toBe(taxAmount);
resolve();
},
});
});
});

it('if there are no tax expense rules', async () => {
// Given a policy without tax expense rules
const transactionID = '1';
const policyID = '2';
const category = 'Advertising';
const fakePolicy: OnyxTypes.Policy = {
...createRandomPolicy(Number(policyID)),
taxRates: CONST.DEFAULT_TAX,
rules: {},
};
await Onyx.merge(`${ONYXKEYS.COLLECTION.TRANSACTION}${transactionID}`, {amount: 100});
await Onyx.merge(`${ONYXKEYS.COLLECTION.POLICY}${policyID}`, fakePolicy);

// When updating the money request category
IOU.updateMoneyRequestCategory(transactionID, '3', category, fakePolicy, undefined, undefined);

await waitForBatchedUpdates();

// Then the transaction tax rate and amount shouldn't be updated
await new Promise<void>((resolve) => {
const connection = Onyx.connect({
key: `${ONYXKEYS.COLLECTION.TRANSACTION}${transactionID}`,
callback: (transaction) => {
Onyx.disconnect(connection);
expect(transaction?.taxCode).toBeUndefined();
expect(transaction?.taxAmount).toBeUndefined();
resolve();
},
});
});
});
});
});
Expand Down Expand Up @@ -3730,7 +3840,7 @@ describe('actions/IOU', () => {
});

describe('should not change the tax', () => {
it('if there is no tax expense rules', async () => {
it('if there are no tax expense rules', async () => {
// Given a policy without tax expense rules
const transactionID = '1';
const category = 'Advertising';
Expand Down
Loading

0 comments on commit f593c21

Please sign in to comment.