Skip to content

Commit 921f299

Browse files
committed
Check CAD eligibility across mixed selections
1 parent 53fcbe0 commit 921f299

3 files changed

Lines changed: 61 additions & 8 deletions

File tree

src/hooks/useSearchBulkActions.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -535,9 +535,10 @@ function useSearchBulkActions({queryJSON}: UseSearchBulkActionsParams) {
535535
[selectedTransactions],
536536
);
537537

538-
// A bulk selection can span several workspaces, so the Canadian Multiple Tax Export template is only offered when every selected item belongs to a workspace that outputs in CAD
538+
// A bulk selection can span several workspaces, so the Canadian Multiple Tax Export template is only offered when every selected item belongs to a workspace that outputs in CAD.
539+
// Reports and transactions are both checked because a selection can mix whole reports with individual transactions from other reports, and the export request covers all of them.
539540
const doAllSelectedItemsBelongToCADPolicies = useMemo(() => {
540-
const selectedItems = selectedReports.length > 0 ? selectedReports : Object.values(selectedTransactions);
541+
const selectedItems = [...selectedReports, ...Object.values(selectedTransactions)];
541542
if (selectedItems.length === 0) {
542543
return false;
543544
}

tests/unit/SearchActionsTest.ts

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import ONYXKEYS from '@src/ONYXKEYS';
99
import type {ExportTemplate, Policy} from '@src/types/onyx';
1010
import type {AnyOnyxUpdate} from '@src/types/onyx/Request';
1111

12+
import createRandomPolicy from '../utils/collections/policies';
1213
import {translateLocal} from '../utils/TestHelper';
1314

1415
jest.mock('@libs/API');
@@ -219,6 +220,7 @@ describe('getExportTemplates', () => {
219220
const translate = translateLocal;
220221
const localeCompare = (first: string, second: string) => first.localeCompare(second);
221222
const makeTemplate = (name: string): ExportTemplate => ({name, templateName: name, type: '', policyID: undefined, description: ''});
223+
const makePolicyWithOutputCurrency = (outputCurrency: string): Policy => ({...createRandomPolicy(1), outputCurrency});
222224

223225
it('returns the custom templates and the default templates as separate groups, each sorted alphabetically', () => {
224226
const integrationsExportTemplates: ExportTemplate[] = [makeTemplate('Zebra integration'), makeTemplate('Apple integration')];
@@ -260,15 +262,13 @@ describe('getExportTemplates', () => {
260262
});
261263

262264
it('includes the Canadian Multiple Tax Export template when the policy outputs in CAD', () => {
263-
const policy = {outputCurrency: CONST.CURRENCY.CAD} as Policy;
264-
const {defaultTemplates} = getExportTemplates([], {}, translate, localeCompare, policy);
265+
const {defaultTemplates} = getExportTemplates([], {}, translate, localeCompare, makePolicyWithOutputCurrency(CONST.CURRENCY.CAD));
265266

266267
expect(defaultTemplates.map((template) => template.templateName)).toContain(CONST.REPORT.EXPORT_OPTIONS.MULTIPLE_TAX_EXPORT);
267268
});
268269

269270
it('excludes the Canadian Multiple Tax Export template when the policy outputs in another currency', () => {
270-
const policy = {outputCurrency: CONST.CURRENCY.USD} as Policy;
271-
const {defaultTemplates} = getExportTemplates([], {}, translate, localeCompare, policy);
271+
const {defaultTemplates} = getExportTemplates([], {}, translate, localeCompare, makePolicyWithOutputCurrency(CONST.CURRENCY.USD));
272272

273273
expect(defaultTemplates.map((template) => template.templateName)).not.toContain(CONST.REPORT.EXPORT_OPTIONS.MULTIPLE_TAX_EXPORT);
274274
});
@@ -280,8 +280,7 @@ describe('getExportTemplates', () => {
280280
});
281281

282282
it('excludes the Canadian Multiple Tax Export template when includeMultipleTaxExport is false for a CAD policy', () => {
283-
const policy = {outputCurrency: CONST.CURRENCY.CAD} as Policy;
284-
const {defaultTemplates} = getExportTemplates([], {}, translate, localeCompare, policy, true, false, false);
283+
const {defaultTemplates} = getExportTemplates([], {}, translate, localeCompare, makePolicyWithOutputCurrency(CONST.CURRENCY.CAD), true, false, false);
285284

286285
expect(defaultTemplates.map((template) => template.templateName)).not.toContain(CONST.REPORT.EXPORT_OPTIONS.MULTIPLE_TAX_EXPORT);
287286
});

tests/unit/hooks/useSearchBulkActionsExportTest.ts

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import type {SearchQueryJSON, SelectedReports, SelectedTransactions} from '@comp
55

66
import useSearchBulkActions from '@hooks/useSearchBulkActions';
77

8+
import {getExportTemplates} from '@libs/actions/Search';
89
import type * as ReportSecondaryActionUtilsModule from '@libs/ReportSecondaryActionUtils';
910

1011
import CONST from '@src/CONST';
@@ -229,6 +230,8 @@ jest.mock('@components/Search/SearchContext', () => ({
229230
}),
230231
}));
231232

233+
const mockGetExportTemplates = jest.mocked(getExportTemplates);
234+
232235
const CURRENT_USER_ACCOUNT_ID = 1;
233236

234237
jest.mock('@hooks/useCurrentUserPersonalDetails', () => ({
@@ -486,4 +489,54 @@ describe('useSearchBulkActions - export options', () => {
486489
expect(getExportOptionTexts(result.current.headerButtonsOptions)).toEqual(['export.currentView']);
487490
});
488491
});
492+
493+
describe('Canadian Multiple Tax Export eligibility', () => {
494+
const SECOND_POLICY_ID = 'policy2';
495+
const SECOND_REPORT_ID = 'report2';
496+
497+
/** The includeMultipleTaxExport argument getExportTemplates was last called with */
498+
function getIncludeMultipleTaxExportArgument() {
499+
return mockGetExportTemplates.mock.calls.at(-1)?.at(7);
500+
}
501+
502+
beforeEach(async () => {
503+
await Onyx.merge(`${ONYXKEYS.COLLECTION.POLICY}${POLICY_ID}`, {outputCurrency: CONST.CURRENCY.CAD});
504+
});
505+
506+
it('offers the template when every selected workspace outputs in CAD, even across several workspaces', async () => {
507+
await Onyx.merge(`${ONYXKEYS.COLLECTION.POLICY}${SECOND_POLICY_ID}`, {id: SECOND_POLICY_ID, outputCurrency: CONST.CURRENCY.CAD});
508+
509+
mockCurrentSearchResults = makeSearchResults([makeSnapshotReport()]);
510+
mockSelectedReports = [makeSelectedReport(), makeSelectedReport({reportID: SECOND_REPORT_ID, policyID: SECOND_POLICY_ID})];
511+
mockSelectedTransactions = {
512+
tx1: makeSelectedTransaction(),
513+
tx2: makeSelectedTransaction({reportID: SECOND_REPORT_ID, policyID: SECOND_POLICY_ID}),
514+
};
515+
516+
renderHook(() => useSearchBulkActions({queryJSON: expenseReportQueryJSON}), {wrapper: OnyxListItemProvider});
517+
518+
await waitFor(() => {
519+
expect(getIncludeMultipleTaxExportArgument()).toBe(true);
520+
});
521+
});
522+
523+
it('hides the template when a transaction from a non-CAD workspace is selected alongside a CAD report', async () => {
524+
await Onyx.merge(`${ONYXKEYS.COLLECTION.POLICY}${SECOND_POLICY_ID}`, {id: SECOND_POLICY_ID, outputCurrency: CONST.CURRENCY.USD});
525+
526+
mockCurrentSearchResults = makeSearchResults([makeSnapshotReport()]);
527+
// Only the CAD report is fully selected, but an extra transaction from a USD workspace is part of the same export request
528+
mockSelectedReports = [makeSelectedReport()];
529+
mockSelectedTransactions = {
530+
tx1: makeSelectedTransaction(),
531+
tx2: makeSelectedTransaction({reportID: SECOND_REPORT_ID, policyID: SECOND_POLICY_ID}),
532+
};
533+
534+
renderHook(() => useSearchBulkActions({queryJSON: expenseReportQueryJSON}), {wrapper: OnyxListItemProvider});
535+
536+
await waitFor(() => {
537+
expect(mockGetExportTemplates).toHaveBeenCalled();
538+
});
539+
expect(getIncludeMultipleTaxExportArgument()).toBe(false);
540+
});
541+
});
489542
});

0 commit comments

Comments
 (0)