Skip to content

Commit 996d334

Browse files
authored
Merge pull request Expensify#88386 from callstack-internal/bulk-edit-bug-merchant-not-disabled
fix: bulk edit, merchant should be disabled for unreported per diem
2 parents 79146fd + 5d12795 commit 996d334

3 files changed

Lines changed: 40 additions & 4 deletions

File tree

src/pages/Search/SearchEditMultiple/SearchEditMultiplePage.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ import type {TransactionChanges} from '@src/types/onyx/Transaction';
2828
import {
2929
areAllTransactionsExpenseCompatible,
3030
getTransactionEditContext,
31+
hasCustomUnitMerchantInSelection,
3132
isBulkEditTaxTrackingEnabled,
3233
withSnapshotReportActions,
3334
withSnapshotReports,
@@ -77,8 +78,7 @@ function SearchEditMultiplePage() {
7778

7879
const hasPartiallyEditableTransaction = isFieldDisabledForAnyTransaction(CONST.EDIT_REQUEST_FIELD.AMOUNT);
7980

80-
const hasPartiallyEditableMerchantTransaction =
81-
isFieldDisabledForAnyTransaction(CONST.EDIT_REQUEST_FIELD.MERCHANT) || selectedTransactionContexts.some(({transaction}) => isDistanceRequest(transaction));
81+
const hasPartiallyEditableMerchantTransaction = isFieldDisabledForAnyTransaction(CONST.EDIT_REQUEST_FIELD.MERCHANT) || hasCustomUnitMerchantInSelection(selectedTransactionContexts);
8282

8383
const hasPartiallyEditableTaxRateTransaction =
8484
isFieldDisabledForAnyTransaction(CONST.EDIT_REQUEST_FIELD.TAX_RATE) || selectedTransactionContexts.some(({transaction}) => isDistanceRequest(transaction));

src/pages/Search/SearchEditMultiple/SearchEditMultipleUtils.ts

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import type {OnyxCollection, OnyxEntry} from 'react-native-onyx';
22
import {getIOUActionForTransactionID} from '@libs/ReportActionsUtils';
33
import {isIOUReport} from '@libs/ReportUtils';
4-
import {getTagArrayFromName} from '@libs/TransactionUtils';
4+
import {getTagArrayFromName, isDistanceRequest, isPerDiemRequest} from '@libs/TransactionUtils';
55
import CONST from '@src/CONST';
66
import ONYXKEYS from '@src/ONYXKEYS';
77
import type {Policy, Report, ReportActions, SearchResults, Transaction} from '@src/types/onyx';
@@ -62,6 +62,14 @@ function getTransactionEditContext(
6262
return {transaction, report, reportAction, transactionPolicy};
6363
}
6464

65+
/**
66+
* Distance and per-diem transactions have a system-derived merchant that cannot be user-edited
67+
* regardless of whether the transaction is reported or unreported.
68+
*/
69+
function hasCustomUnitMerchantInSelection(selectedTransactionContexts: Array<{transaction: Transaction}>): boolean {
70+
return selectedTransactionContexts.some(({transaction}) => isDistanceRequest(transaction) || isPerDiemRequest(transaction));
71+
}
72+
6573
/**
6674
* Category/Tag/Tax only apply to expense/invoice reports and unreported (track) expenses.
6775
* Returns true only when every selected transaction is eligible.
@@ -149,9 +157,10 @@ function withSnapshotReports(onyxReports: OnyxCollection<Report> | undefined, sn
149157
}
150158

151159
export {
152-
areAllTransactionsExpenseCompatible,
153160
getCommonDependentTag,
154161
getTransactionEditContext,
162+
hasCustomUnitMerchantInSelection,
163+
areAllTransactionsExpenseCompatible,
155164
isBulkEditTaxTrackingEnabled,
156165
withSnapshotTransactions,
157166
withSnapshotReportActions,

tests/unit/SearchEditMultipleUtilsTest.ts

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import ONYXKEYS from '@src/ONYXKEYS';
44
import type {Policy, Report, SearchResults, Transaction} from '@src/types/onyx';
55
import {
66
areAllTransactionsExpenseCompatible,
7+
hasCustomUnitMerchantInSelection,
78
isBulkEditTaxTrackingEnabled,
89
withSnapshotReports,
910
withSnapshotTransactions,
@@ -15,6 +16,7 @@ const POLICY_C = 'policyC';
1516
const REPORT_ID = 'report1';
1617
const TRANSACTION_ID_1 = 'tx1';
1718
const TRANSACTION_ID_2 = 'tx2';
19+
const TRANSACTION_ID_3 = 'tx3';
1820

1921
function makeTransaction(transactionID: string, reportID: string): Transaction {
2022
return {transactionID, reportID, amount: 100, currency: 'USD', created: '2025-01-01', comment: {}} as Transaction;
@@ -138,6 +140,31 @@ describe('SearchEditMultipleUtils', () => {
138140
});
139141
});
140142

143+
describe('hasCustomUnitMerchantInSelection', () => {
144+
const manualTransaction = {transactionID: TRANSACTION_ID_1, reportID: 'report1', comment: {}} as Transaction;
145+
const perDiemTransaction = {transactionID: TRANSACTION_ID_2, reportID: CONST.REPORT.UNREPORTED_REPORT_ID, iouRequestType: CONST.IOU.REQUEST_TYPE.PER_DIEM} as unknown as Transaction;
146+
const distanceTransaction = {transactionID: TRANSACTION_ID_3, reportID: CONST.REPORT.UNREPORTED_REPORT_ID, iouRequestType: CONST.IOU.REQUEST_TYPE.DISTANCE} as unknown as Transaction;
147+
148+
it('returns true when any transaction is an unreported per-diem request', () => {
149+
const contexts = [{transaction: manualTransaction}, {transaction: perDiemTransaction}];
150+
expect(hasCustomUnitMerchantInSelection(contexts)).toBe(true);
151+
});
152+
153+
it('returns true when any transaction is a distance request', () => {
154+
const contexts = [{transaction: manualTransaction}, {transaction: distanceTransaction}];
155+
expect(hasCustomUnitMerchantInSelection(contexts)).toBe(true);
156+
});
157+
158+
it('returns false when no transaction is a distance or per-diem request', () => {
159+
const contexts = [{transaction: manualTransaction}];
160+
expect(hasCustomUnitMerchantInSelection(contexts)).toBe(false);
161+
});
162+
163+
it('returns false for an empty selection', () => {
164+
expect(hasCustomUnitMerchantInSelection([])).toBe(false);
165+
});
166+
});
167+
141168
describe('areAllTransactionsExpenseCompatible', () => {
142169
const expenseReport = {reportID: 'expenseReport1', type: CONST.REPORT.TYPE.EXPENSE} as Report;
143170
const iouReport = {reportID: 'iouReport1', type: CONST.REPORT.TYPE.IOU} as Report;

0 commit comments

Comments
 (0)