Skip to content

Commit a0ad766

Browse files
authored
Merge pull request Expensify#90408 from mukhrr/fix/82252-tax-columns-policy-enabled
fixed tax rate in expenses created before tax rate is enabled in WS
2 parents 3e5e449 + f4d8169 commit a0ad766

4 files changed

Lines changed: 95 additions & 3 deletions

File tree

src/components/MoneyRequestReportView/MoneyRequestReportTransactionList.tsx

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -334,8 +334,18 @@ function MoneyRequestReportTransactionList({
334334
shouldShowCommentsColumn,
335335
shouldShowReimbursableColumn: hasNonReimbursableTransactions(transactions),
336336
reportCurrency: report?.currency,
337+
isPolicyTaxEnabled: isTaxEnabled,
337338
});
338-
}, [transactions, currentUserDetails?.accountID, isExpenseReportViewFromIOUReport, shouldShowBillableColumn, shouldShowCommentsColumn, reportDetailsColumns, report?.currency]);
339+
}, [
340+
transactions,
341+
currentUserDetails?.accountID,
342+
isExpenseReportViewFromIOUReport,
343+
shouldShowBillableColumn,
344+
shouldShowCommentsColumn,
345+
reportDetailsColumns,
346+
report?.currency,
347+
isTaxEnabled,
348+
]);
339349

340350
const {windowWidth, windowHeight} = useWindowDimensions();
341351
const minTableWidth = getTableMinWidth(columnsToShow);

src/libs/SearchUIUtils.ts

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5151,6 +5151,7 @@ function getColumnsToShow({
51515151
shouldShowCommentsColumn = false,
51525152
reportCurrency,
51535153
shouldUseStrictDefaultExpenseColumns = false,
5154+
isPolicyTaxEnabled = false,
51545155
}: {
51555156
currentAccountID: number | undefined;
51565157
data: OnyxTypes.SearchResults['data'] | OnyxTypes.Transaction[];
@@ -5164,7 +5165,7 @@ function getColumnsToShow({
51645165
shouldShowCommentsColumn?: boolean;
51655166
reportCurrency?: string;
51665167
shouldUseStrictDefaultExpenseColumns?: boolean;
5167-
policy?: OnyxTypes.Policy;
5168+
isPolicyTaxEnabled?: boolean;
51685169
}): SearchColumnType[] {
51695170
if (type === CONST.SEARCH.DATA_TYPES.EXPENSE_REPORT) {
51705171
const defaultReportColumns: SearchColumnType[] = [
@@ -5408,7 +5409,10 @@ function getColumnsToShow({
54085409
// Use truthy checks so default/no-tax values (0, null, '', undefined) don't trigger
54095410
// false positives — buildOptimisticTransaction seeds taxAmount: 0 on every new draft,
54105411
// which would otherwise flash tax columns on for offline-pending transactions.
5411-
const hasTaxInfo = !!transaction.taxCode || !!transaction.taxAmount || !!transaction.taxValue;
5412+
// When the user explicitly selected the tax columns (customResult) and the workspace
5413+
// has taxes enabled, keep them regardless of per-transaction values — older expenses
5414+
// created before taxes were turned on still have null taxCode/taxAmount/taxValue.
5415+
const hasTaxInfo = (!!customResult && isPolicyTaxEnabled) || !!transaction.taxCode || !!transaction.taxAmount || !!transaction.taxValue;
54125416
if (hasTaxInfo) {
54135417
columns[CONST.SEARCH.TABLE_COLUMNS.TAX_RATE] = true;
54145418
columns[CONST.SEARCH.TABLE_COLUMNS.TAX_AMOUNT] = true;

src/pages/settings/Report/ReportDetailsColumnsPage.tsx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import {setReportDetailsColumns} from '@libs/actions/ReportLayout';
99
import {hasNonReimbursableTransactions, isBillableEnabledOnPolicy} from '@libs/MoneyRequestReportUtils';
1010
import Navigation from '@libs/Navigation/Navigation';
1111
import type {PlatformStackRouteProp} from '@libs/Navigation/PlatformStackNavigation/types';
12+
import {isPolicyTaxEnabled} from '@libs/PolicyUtils';
1213
import {isIOUReport} from '@libs/ReportUtils';
1314
import {getColumnsToShow} from '@libs/SearchUIUtils';
1415
import type {ReportSettingsNavigatorParamList} from '@navigation/types';
@@ -80,6 +81,7 @@ function ReportDetailsColumnsPage() {
8081
shouldShowBillableColumn: isBillableEnabledOnPolicy(policy),
8182
shouldShowReimbursableColumn: hasNonReimbursableTransactions(reportTransactions),
8283
reportCurrency: report?.currency,
84+
isPolicyTaxEnabled: isPolicyTaxEnabled(policy),
8385
});
8486

8587
// Filter to only columns available in the custom columns list (drops RECEIPT/TYPE/COMMENTS etc.)

tests/unit/Search/SearchUIUtilsTest.ts

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8355,6 +8355,82 @@ describe('SearchUIUtils', () => {
83558355
expect(columns).toContain(CONST.SEARCH.TABLE_COLUMNS.TAX_AMOUNT);
83568356
});
83578357

8358+
test('Should show TAX columns when user selected them and the workspace has taxes enabled, even for transactions with null tax fields', () => {
8359+
// Repro for the issue raised on GH #82252: expenses created before taxes were
8360+
// enabled have null taxCode/taxAmount/taxValue and never get backfilled, so the
8361+
// per-transaction check alone would hide the columns even though the user has
8362+
// both selected the columns and enabled taxes on the workspace.
8363+
const baseTransaction = searchResults.data[`transactions_${transactionID}`];
8364+
const legacyTransaction = {
8365+
...baseTransaction,
8366+
transactionID: 'legacy',
8367+
merchant: 'Legacy Expense',
8368+
taxCode: undefined,
8369+
taxAmount: undefined,
8370+
};
8371+
const visibleColumns = [CONST.SEARCH.TABLE_COLUMNS.DATE, CONST.SEARCH.TABLE_COLUMNS.TAX_RATE, CONST.SEARCH.TABLE_COLUMNS.TAX_AMOUNT, CONST.SEARCH.TABLE_COLUMNS.TOTAL_AMOUNT];
8372+
const columns = SearchUIUtils.getColumnsToShow({
8373+
currentAccountID: submitterAccountID,
8374+
data: [legacyTransaction],
8375+
visibleColumns,
8376+
isExpenseReportView: true,
8377+
isPolicyTaxEnabled: true,
8378+
});
8379+
8380+
expect(columns).toContain(CONST.SEARCH.TABLE_COLUMNS.TAX_RATE);
8381+
expect(columns).toContain(CONST.SEARCH.TABLE_COLUMNS.TAX_AMOUNT);
8382+
});
8383+
8384+
test('Should NOT inject TAX columns when the workspace has taxes enabled but the user did not select them', () => {
8385+
// Guard: enabling taxes on the workspace must not force the columns into the
8386+
// result if the user deselected them in the column selector. The customResult
8387+
// path filters to the user's selection, so unselected columns stay hidden even
8388+
// when columns[TAX_RATE]/[TAX_AMOUNT] get flipped on internally.
8389+
const baseTransaction = searchResults.data[`transactions_${transactionID}`];
8390+
const legacyTransaction = {
8391+
...baseTransaction,
8392+
transactionID: 'legacy',
8393+
merchant: 'Legacy Expense',
8394+
taxCode: undefined,
8395+
taxAmount: undefined,
8396+
};
8397+
const visibleColumns = [CONST.SEARCH.TABLE_COLUMNS.DATE, CONST.SEARCH.TABLE_COLUMNS.MERCHANT, CONST.SEARCH.TABLE_COLUMNS.TOTAL_AMOUNT];
8398+
const columns = SearchUIUtils.getColumnsToShow({
8399+
currentAccountID: submitterAccountID,
8400+
data: [legacyTransaction],
8401+
visibleColumns,
8402+
isExpenseReportView: true,
8403+
isPolicyTaxEnabled: true,
8404+
});
8405+
8406+
expect(columns).not.toContain(CONST.SEARCH.TABLE_COLUMNS.TAX_RATE);
8407+
expect(columns).not.toContain(CONST.SEARCH.TABLE_COLUMNS.TAX_AMOUNT);
8408+
});
8409+
8410+
test('Should hide TAX columns when the workspace does not have taxes enabled and transactions have no tax data', () => {
8411+
// Regression guard: without a tax-enabled policy and without per-transaction tax
8412+
// data, the columns must stay hidden even if the user selected them.
8413+
const baseTransaction = searchResults.data[`transactions_${transactionID}`];
8414+
const legacyTransaction = {
8415+
...baseTransaction,
8416+
transactionID: 'legacy',
8417+
merchant: 'Legacy Expense',
8418+
taxCode: undefined,
8419+
taxAmount: undefined,
8420+
};
8421+
const visibleColumns = [CONST.SEARCH.TABLE_COLUMNS.DATE, CONST.SEARCH.TABLE_COLUMNS.TAX_RATE, CONST.SEARCH.TABLE_COLUMNS.TAX_AMOUNT, CONST.SEARCH.TABLE_COLUMNS.TOTAL_AMOUNT];
8422+
const columns = SearchUIUtils.getColumnsToShow({
8423+
currentAccountID: submitterAccountID,
8424+
data: [legacyTransaction],
8425+
visibleColumns,
8426+
isExpenseReportView: true,
8427+
isPolicyTaxEnabled: false,
8428+
});
8429+
8430+
expect(columns).not.toContain(CONST.SEARCH.TABLE_COLUMNS.TAX_RATE);
8431+
expect(columns).not.toContain(CONST.SEARCH.TABLE_COLUMNS.TAX_AMOUNT);
8432+
});
8433+
83588434
test('Should hide empty AMOUNT column in expense report view when no conversion', () => {
83598435
const baseTransaction = searchResults.data[`transactions_${transactionID}`];
83608436
const testTransaction = {

0 commit comments

Comments
 (0)