Skip to content

Commit 2cc56d9

Browse files
authored
Merge pull request #97671 from truph01/feat/95355
[Download receipts] Add "Download receipts" to the Expenses and Reports search pages
2 parents 76fff9f + b56b4d9 commit 2cc56d9

7 files changed

Lines changed: 452 additions & 6 deletions

File tree

src/CONST/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6862,6 +6862,7 @@ const CONST = {
68626862
EDIT: 'edit',
68636863
EXPORT: 'export',
68646864
DOWNLOAD_PDF: 'downloadPDF',
6865+
DOWNLOAD_RECEIPTS: 'downloadReceipts',
68656866
DOWNLOAD_STATEMENT_PDF: 'downloadStatementPDF',
68666867
APPROVE: 'approve',
68676868
CHANGE_APPROVER: 'changeApprover',

src/hooks/useExportActions.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -291,7 +291,7 @@ function useExportActions({reportID, policy, onPDFModalOpen}: UseExportActionsPa
291291
if (!moneyRequestReport?.reportID) {
292292
return;
293293
}
294-
const exportID = exportReceiptsToZip([moneyRequestReport.reportID]);
294+
const exportID = exportReceiptsToZip({reportIDs: [moneyRequestReport.reportID]});
295295
trackExport(exportID);
296296
},
297297
},

src/hooks/useSearchBulkActions.ts

Lines changed: 40 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ import {useSearchQueryContext, useSearchResultsContext, useSearchSelectionAction
88
import type {BulkPaySelectionData, PaymentData, SearchColumnType, SearchFilterKey, SearchQueryJSON, SelectedReports, SelectedTransactions} from '@components/Search/types';
99

1010
import {getExpensifyCardStatementPDF} from '@libs/actions/CompanyCards';
11-
import {exportReportsToPDF} from '@libs/actions/Export';
11+
import {exportReceiptsToZip, exportReportsToPDF} from '@libs/actions/Export';
1212
import {unholdRequest} from '@libs/actions/IOU/Hold';
1313
import {payInvoice, payMoneyRequest} from '@libs/actions/IOU/PayMoneyRequest';
1414
import {approveMoneyRequest} from '@libs/actions/IOU/ReportWorkflow';
@@ -2249,6 +2249,45 @@ function useSearchBulkActions({queryJSON}: UseSearchBulkActionsParams) {
22492249
});
22502250
}
22512251

2252+
const hasSelectedReportsWithExpenses = selectedReports.some((report) => (currentSearchResults?.data?.[`${ONYXKEYS.COLLECTION.REPORT}${report.reportID}`]?.transactionCount ?? 0) > 0);
2253+
if (isExpenseReportSearch && selectedReportIDs.length > 0 && hasSelectedReportsWithExpenses) {
2254+
options.push({
2255+
icon: expensifyIcons.Download,
2256+
text: translate('common.downloadReceipts'),
2257+
value: CONST.SEARCH.BULK_ACTION_TYPES.DOWNLOAD_RECEIPTS,
2258+
shouldCloseModalOnSelect: true,
2259+
onSelected: () => {
2260+
if (isOffline) {
2261+
setIsOfflineModalVisible(true);
2262+
return;
2263+
}
2264+
const exportID = exportReceiptsToZip({reportIDs: selectedReportIDs});
2265+
trackExport(exportID);
2266+
},
2267+
});
2268+
}
2269+
2270+
const isExpenseSearch = queryJSON?.type === CONST.SEARCH.DATA_TYPES.EXPENSE || searchResults?.search.type === CONST.SEARCH.DATA_TYPES.EXPENSE;
2271+
// A group selected before its children load is stored under a group_ key, which is not a real
2272+
// transaction ID. Drop those keys so ExportReceiptsToZip only receives valid transaction IDs.
2273+
const transactionIDs = selectedTransactionsKeys.filter((key) => !key.startsWith(CONST.SEARCH.GROUP_PREFIX));
2274+
if (isExpenseSearch && selectedTransactionsKeys.length > 0 && transactionIDs.length > 0) {
2275+
options.push({
2276+
icon: expensifyIcons.Download,
2277+
text: translate('common.downloadReceipts'),
2278+
value: CONST.SEARCH.BULK_ACTION_TYPES.DOWNLOAD_RECEIPTS,
2279+
shouldCloseModalOnSelect: true,
2280+
onSelected: () => {
2281+
if (isOffline) {
2282+
setIsOfflineModalVisible(true);
2283+
return;
2284+
}
2285+
const exportID = exportReceiptsToZip({transactionIDs});
2286+
trackExport(exportID);
2287+
},
2288+
});
2289+
}
2290+
22522291
// A standalone bulk action (not nested under Export). "Select all matching" only loads the visible
22532292
// rows, so we would export an incomplete set of settlements while the UI claims everything is selected;
22542293
// the statement has no whole-query export path (unlike CSV/templates), so require an explicit selection.

src/libs/API/parameters/ExportReceiptsToZipParams.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
type ExportReceiptsToZipParams = {
2-
reportIDs: string;
2+
transactionIDs?: string;
3+
reportIDs?: string;
34
exportID: string;
45
};
56

src/libs/actions/Export.ts

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -102,7 +102,7 @@ function exportReportsToPDF(reportIDs: string[]): string {
102102
return exportID;
103103
}
104104

105-
function exportReceiptsToZip(reportIDs: string[]): string {
105+
function exportReceiptsToZip({reportIDs, transactionIDs}: {reportIDs?: string[]; transactionIDs?: string[]}): string {
106106
const exportID = rand64();
107107
const onyxKey = `${ONYXKEYS.COLLECTION.EXPORT_DOWNLOAD}${exportID}` as const;
108108

@@ -122,7 +122,15 @@ function exportReceiptsToZip(reportIDs: string[]): string {
122122
},
123123
];
124124

125-
write(WRITE_COMMANDS.EXPORT_RECEIPTS_TO_ZIP, {reportIDs: JSON.stringify(reportIDs), exportID}, {optimisticData, failureData});
125+
write(
126+
WRITE_COMMANDS.EXPORT_RECEIPTS_TO_ZIP,
127+
{
128+
exportID,
129+
reportIDs: reportIDs ? JSON.stringify(reportIDs) : undefined,
130+
transactionIDs: transactionIDs ? JSON.stringify(transactionIDs) : undefined,
131+
},
132+
{optimisticData, failureData},
133+
);
126134

127135
return exportID;
128136
}

src/types/onyx/ExportDownload.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ type ExportDownload = {
1313
/** Current state of the export download */
1414
state: ExportDownloadState;
1515

16-
/** Type of export (csv or pdf), used to show the correct failure message */
16+
/** Type of export (csv, pdf or receipts), used to show the correct failure message */
1717
exportType?: ExportDownloadType;
1818

1919
/** URL to download the exported file when state is ready */

0 commit comments

Comments
 (0)