Skip to content

Commit 82870c0

Browse files
authored
Merge pull request #88422 from callstack-internal/bulk-edit-tag-wrong-avaialble
fix: bulk edit, disable tags edit for non WS expenses
2 parents e59c062 + 17d2758 commit 82870c0

3 files changed

Lines changed: 83 additions & 10 deletions

File tree

src/pages/Search/SearchEditMultiple/SearchEditMultiplePage.tsx

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,14 @@ import ONYXKEYS from '@src/ONYXKEYS';
2525
import ROUTES from '@src/ROUTES';
2626
import type {Route} from '@src/ROUTES';
2727
import type {TransactionChanges} from '@src/types/onyx/Transaction';
28-
import {getTransactionEditContext, isBulkEditTaxTrackingEnabled, withSnapshotReportActions, withSnapshotReports, withSnapshotTransactions} from './SearchEditMultipleUtils';
28+
import {
29+
areAllTransactionsExpenseCompatible,
30+
getTransactionEditContext,
31+
isBulkEditTaxTrackingEnabled,
32+
withSnapshotReportActions,
33+
withSnapshotReports,
34+
withSnapshotTransactions,
35+
} from './SearchEditMultipleUtils';
2936

3037
function SearchEditMultiplePage() {
3138
const {translate} = useLocalize();
@@ -102,14 +109,9 @@ function SearchEditMultiplePage() {
102109
const policyTagLists = getTagLists(policyTags);
103110

104111
const isTaxTrackingEnabled = isBulkEditTaxTrackingEnabled(selectedTransactionContexts, policy, hasPerDiemOrTimeTransaction);
105-
const areSelectedTransactionsExpenses = selectedTransactionContexts.every(({transaction, report}) => {
106-
if (!transaction.reportID || transaction.reportID === CONST.REPORT.UNREPORTED_REPORT_ID) {
107-
return true;
108-
}
109-
return !isIOUReport(report);
110-
});
112+
const areSelectedTransactionsExpenses = areAllTransactionsExpenseCompatible(selectedTransactionContexts);
111113
const areCategoriesEnabled = areSelectedTransactionsExpenses && !!policy?.areCategoriesEnabled && hasEnabledOptions(policyCategories ?? {});
112-
const areTagsEnabled = !!policy?.areTagsEnabled && hasEnabledTags(policyTagLists);
114+
const areTagsEnabled = areSelectedTransactionsExpenses && !!policy?.areTagsEnabled && hasEnabledTags(policyTagLists);
113115

114116
useEffect(() => {
115117
return () => {

src/pages/Search/SearchEditMultiple/SearchEditMultipleUtils.ts

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import type {OnyxCollection, OnyxEntry} from 'react-native-onyx';
22
import {getIOUActionForTransactionID} from '@libs/ReportActionsUtils';
3+
import {isIOUReport} from '@libs/ReportUtils';
34
import {getTagArrayFromName} from '@libs/TransactionUtils';
45
import CONST from '@src/CONST';
56
import ONYXKEYS from '@src/ONYXKEYS';
@@ -61,6 +62,19 @@ function getTransactionEditContext(
6162
return {transaction, report, reportAction, transactionPolicy};
6263
}
6364

65+
/**
66+
* Category/Tag/Tax only apply to expense/invoice reports and unreported (track) expenses.
67+
* Returns true only when every selected transaction is eligible.
68+
*/
69+
function areAllTransactionsExpenseCompatible(selectedTransactionContexts: Array<{transaction: Transaction; report: OnyxEntry<Report>}>): boolean {
70+
return selectedTransactionContexts.every(({transaction, report}) => {
71+
if (!transaction.reportID || transaction.reportID === CONST.REPORT.UNREPORTED_REPORT_ID) {
72+
return true;
73+
}
74+
return !isIOUReport(report);
75+
});
76+
}
77+
6478
/**
6579
* Reported expenses check their own workspace policy; unreported (track) expenses fall back to
6680
* the bulk-edit workspace policy because they have no report to resolve a per-transaction policy from.
@@ -134,4 +148,12 @@ function withSnapshotReports(onyxReports: OnyxCollection<Report> | undefined, sn
134148
return merged;
135149
}
136150

137-
export {getCommonDependentTag, getTransactionEditContext, isBulkEditTaxTrackingEnabled, withSnapshotTransactions, withSnapshotReportActions, withSnapshotReports};
151+
export {
152+
areAllTransactionsExpenseCompatible,
153+
getCommonDependentTag,
154+
getTransactionEditContext,
155+
isBulkEditTaxTrackingEnabled,
156+
withSnapshotTransactions,
157+
withSnapshotReportActions,
158+
withSnapshotReports,
159+
};

tests/unit/SearchEditMultipleUtilsTest.ts

Lines changed: 50 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,12 @@ import {getSearchBulkEditPolicyID} from '@libs/SearchUIUtils';
22
import CONST from '@src/CONST';
33
import ONYXKEYS from '@src/ONYXKEYS';
44
import type {Policy, Report, SearchResults, Transaction} from '@src/types/onyx';
5-
import {isBulkEditTaxTrackingEnabled, withSnapshotReports, withSnapshotTransactions} from '../../src/pages/Search/SearchEditMultiple/SearchEditMultipleUtils';
5+
import {
6+
areAllTransactionsExpenseCompatible,
7+
isBulkEditTaxTrackingEnabled,
8+
withSnapshotReports,
9+
withSnapshotTransactions,
10+
} from '../../src/pages/Search/SearchEditMultiple/SearchEditMultipleUtils';
611

712
const POLICY_A = 'policyA';
813
const POLICY_B = 'policyB';
@@ -133,6 +138,50 @@ describe('SearchEditMultipleUtils', () => {
133138
});
134139
});
135140

141+
describe('areAllTransactionsExpenseCompatible', () => {
142+
const expenseReport = {reportID: 'expenseReport1', type: CONST.REPORT.TYPE.EXPENSE} as Report;
143+
const iouReport = {reportID: 'iouReport1', type: CONST.REPORT.TYPE.IOU} as Report;
144+
const invoiceReport = {reportID: 'invoiceReport1', type: CONST.REPORT.TYPE.INVOICE} as Report;
145+
146+
it('returns true when every reported transaction is on an expense report', () => {
147+
const contexts = [
148+
{transaction: makeTransaction(TRANSACTION_ID_1, 'expenseReport1'), report: expenseReport},
149+
{transaction: makeTransaction(TRANSACTION_ID_2, 'expenseReport1'), report: expenseReport},
150+
];
151+
expect(areAllTransactionsExpenseCompatible(contexts)).toBe(true);
152+
});
153+
154+
it('returns true for unreported (track) transactions', () => {
155+
const contexts = [{transaction: makeTransaction(TRANSACTION_ID_1, CONST.REPORT.UNREPORTED_REPORT_ID), report: undefined}];
156+
expect(areAllTransactionsExpenseCompatible(contexts)).toBe(true);
157+
});
158+
159+
it('returns false when any reported transaction is on an IOU report', () => {
160+
const contexts = [
161+
{transaction: makeTransaction(TRANSACTION_ID_1, 'expenseReport1'), report: expenseReport},
162+
{transaction: makeTransaction(TRANSACTION_ID_2, 'iouReport1'), report: iouReport},
163+
];
164+
expect(areAllTransactionsExpenseCompatible(contexts)).toBe(false);
165+
});
166+
167+
it('returns false when a mix of unreported and IOU transactions is selected', () => {
168+
const contexts = [
169+
{transaction: makeTransaction(TRANSACTION_ID_1, CONST.REPORT.UNREPORTED_REPORT_ID), report: undefined},
170+
{transaction: makeTransaction(TRANSACTION_ID_2, 'iouReport1'), report: iouReport},
171+
];
172+
expect(areAllTransactionsExpenseCompatible(contexts)).toBe(false);
173+
});
174+
175+
it('returns true for invoice reports (not IOU)', () => {
176+
const contexts = [{transaction: makeTransaction(TRANSACTION_ID_1, 'invoiceReport1'), report: invoiceReport}];
177+
expect(areAllTransactionsExpenseCompatible(contexts)).toBe(true);
178+
});
179+
180+
it('returns true for an empty selection', () => {
181+
expect(areAllTransactionsExpenseCompatible([])).toBe(true);
182+
});
183+
});
184+
136185
describe('isBulkEditTaxTrackingEnabled', () => {
137186
const taxEnabledPolicy = {id: POLICY_A, tax: {trackingEnabled: true}} as unknown as Policy;
138187
const taxDisabledPolicy = {id: POLICY_B, tax: {trackingEnabled: false}} as unknown as Policy;

0 commit comments

Comments
 (0)