@zeniai/client-epic-state 4.19.84-betaVR10 → 4.19.84-betaVR12

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (26) hide show
  1. package/lib/esm/index.js +5 -2
  2. package/lib/esm/view/expenseAutomationView/bulkUploadTiming.js +5 -0
  3. package/lib/esm/view/expenseAutomationView/epics/missingReceipts/bulkUploadReceiptsEpic.js +4 -3
  4. package/lib/esm/view/expenseAutomationView/epics/missingReceipts/searchTransactionsForManualMatchEpic.js +5 -5
  5. package/lib/esm/view/expenseAutomationView/epics/missingReceipts/watchBulkUploadBatchStatusEpic.js +1 -1
  6. package/lib/esm/view/expenseAutomationView/payload/missingReceiptsPayload.js +14 -11
  7. package/lib/esm/view/expenseAutomationView/reducers/missingReceiptsViewReducer.js +21 -20
  8. package/lib/esm/view/expenseAutomationView/selectors/missingReceiptsSelector.js +57 -34
  9. package/lib/esm/view/expenseAutomationView/types/missingReceiptsViewState.js +30 -1
  10. package/lib/index.d.ts +3 -2
  11. package/lib/index.js +43 -32
  12. package/lib/tsconfig.typecheck.tsbuildinfo +1 -1
  13. package/lib/view/expenseAutomationView/bulkUploadTiming.d.ts +5 -0
  14. package/lib/view/expenseAutomationView/bulkUploadTiming.js +8 -0
  15. package/lib/view/expenseAutomationView/epics/missingReceipts/bulkUploadReceiptsEpic.d.ts +3 -0
  16. package/lib/view/expenseAutomationView/epics/missingReceipts/bulkUploadReceiptsEpic.js +2 -1
  17. package/lib/view/expenseAutomationView/epics/missingReceipts/searchTransactionsForManualMatchEpic.js +5 -5
  18. package/lib/view/expenseAutomationView/epics/missingReceipts/watchBulkUploadBatchStatusEpic.js +1 -1
  19. package/lib/view/expenseAutomationView/payload/missingReceiptsPayload.d.ts +1 -1
  20. package/lib/view/expenseAutomationView/payload/missingReceiptsPayload.js +14 -11
  21. package/lib/view/expenseAutomationView/reducers/missingReceiptsViewReducer.d.ts +7 -3
  22. package/lib/view/expenseAutomationView/reducers/missingReceiptsViewReducer.js +21 -20
  23. package/lib/view/expenseAutomationView/selectors/missingReceiptsSelector.js +57 -34
  24. package/lib/view/expenseAutomationView/types/missingReceiptsViewState.d.ts +20 -9
  25. package/lib/view/expenseAutomationView/types/missingReceiptsViewState.js +39 -2
  26. package/package.json +1 -1
package/lib/esm/index.js CHANGED
@@ -169,7 +169,7 @@ import { backgroundRefetchReviewTab, clearExpenseAutomationTransactionsView, fet
169
169
  import { getExpenseAutomationFluxAnalysisView } from './view/expenseAutomationView/selectors/fluxAnalysisViewSelector';
170
170
  import { getExpenseAutomationReconciliationView, isAccountReconReport, } from './view/expenseAutomationView/selectors/reconciliationViewSelector';
171
171
  import { getExpenseAutomationTransactionView } from './view/expenseAutomationView/selectors/transactionCategorizationSelector';
172
- import { isUnmatchedTabFileStatus, } from './view/expenseAutomationView/types/missingReceiptsViewState';
172
+ import { BATCH_FILE_STATUSES, isUnmatchedTabFileStatus, toBatchFileStatus, toBatchStatusValue, toBulkUploadPhase, toBulkUploadResultsTab, toBulkUploadSortKey, toCompletedSubTab, toMatchSource, toMissingReceiptsTab, } from './view/expenseAutomationView/types/missingReceiptsViewState';
173
173
  import { toMissingReceiptsSortKey as toExpenseAutomationMissingReceiptsSortKey, } from './view/expenseAutomationView/types/missingReceiptsViewState';
174
174
  import { toReconciliationTabsType, } from './view/expenseAutomationView/types/reconciliationViewState';
175
175
  import { toTransactionsTabKey as toExpenseAutomationTransactionsTabKey, toTransactionsSortKey, } from './view/expenseAutomationView/types/transactionsViewState';
@@ -416,7 +416,9 @@ export { newBalancesFilterClassesView };
416
416
  export { toCOABalanceTypeStrict, toCOABalanceType as toCOABlanaceType, isCalculatedBalanceType, };
417
417
  export { stringToUnion, stringToUnionStrict };
418
418
  export { fetchMonthEndCloseChecks, fetchMonthClosePerformanceTrend, getMonthEndCloseChecksViewByTenantId, ALL_MONTH_END_CLOSE_CHECKS_FREQUENCY, };
419
- export { isUnmatchedTabFileStatus, getExpenseAutomationView, toExpenseAutomationMissingReceiptsSortKey, toExpenseAutomationTransactionsTabKey, toExpenseAutomationViewType, uploadExpenseAutomationMissingReceiptSuccess, markExpenseAutomationMissingReceiptAsDone, fetchAllExpenseAutomationTabs, refreshExpenseAutomationCurrentTab, updateCurrentSelectedTransactionCategorizationTab, fetchExpenseAutomationMissingReceipts,
419
+ export {
420
+ // Bulk Upload Types
421
+ BATCH_FILE_STATUSES, isUnmatchedTabFileStatus, toBatchFileStatus, toBatchStatusValue, toBulkUploadPhase, toBulkUploadResultsTab, toBulkUploadSortKey, toCompletedSubTab, toMatchSource, toMissingReceiptsTab, getExpenseAutomationView, toExpenseAutomationMissingReceiptsSortKey, toExpenseAutomationTransactionsTabKey, toExpenseAutomationViewType, uploadExpenseAutomationMissingReceiptSuccess, markExpenseAutomationMissingReceiptAsDone, fetchAllExpenseAutomationTabs, refreshExpenseAutomationCurrentTab, updateCurrentSelectedTransactionCategorizationTab, fetchExpenseAutomationMissingReceipts,
420
422
  // Bulk Upload Actions
421
423
  bulkUploadReceipts, bulkUploadReceiptsSuccess, bulkUploadReceiptsFailure, updateBulkUploadProgress, pusherBatchStatusUpdate, requestMissingReceiptsTabNavigation, clearMissingReceiptsTabNavigation, fetchBulkUploadBatchDetails, fetchBulkUploadBatchDetailsSuccess, fetchBulkUploadBatchDetailsFailure, storeBatchDetails, fetchMoreBatchDetails, fetchMoreBatchDetailsComplete, fetchMoreBatchDetailsFailure, fetchBulkUploadBatches, fetchBulkUploadBatchesSuccess, fetchBulkUploadBatchesFailure, confirmBulkUploadMatch, confirmBulkUploadMatchSuccess, confirmBulkUploadMatchFailure, setBulkUploadResultsTab, setBulkUploadCompletedSubTab, setBulkUploadSortConfig, clearBulkUpload, searchTransactionsForManualMatch, searchTransactionsForManualMatchSuccess, searchTransactionsForManualMatchFailure, clearManualSearchResults, acknowledgeBulkUploadConfirmMatchComplete, fetchCompletedTransactions, fetchCompletedTransactionsSuccess, fetchCompletedTransactionsFailure, fetchFluxAnalysisView, clearExpenseAutomationFluxAnalysisView, updateOperatingExpensesIdsForReview as updateFluxOperatingExpensesIdsForReview, updateSelectedSectionIdsForReview as updateFluxAnalysisSelectedSectionIdsForReview, reviewFluxAnalysisView, updateExpenseAutomationMissingReceiptUploadState, updateExpenseAutomationMissingReceiptsUIState, updateTransactionCategorizationUploadReceiptState, uploadTransactionCategorizationReceiptSuccess, getExpenseAutomationFluxAnalysisView, updateCurrentSelectedView, updateCurrentSelectedPeriod, getExpenseAutomationTransactionView, updateFluxAnalysisViewUIState, updateFluxAnalysisViewPageMetaData, MAX_SELECTION_LIMIT, checkIfAllLineItemsAreCategoryClassFilled, getLineItemsByTransactionIdsFromLocalData, isAnyItemWithUncategorizedExpenseAccount, saveExpenseAutomationReconciliationDetail, updateExpenseAutomationReconcileTabListScrollState, updateExpenseAutomationReconReviewTabListSortState, updateExpenseAutomationReconcileTabListSortState, updateExpenseAutomationReconcileTabLocalData, updateExpenseAutomationAccountReconciliationSelectedTab, updateExpenseAutomationAccountReconciliationSelectedAccountId, getExpenseAutomationReconciliationView, fetchReconciliationView, uploadAccountStatementIntoDocumentAI, updateExpenseAutomationReconListScrollPosition, setConnectionInProgressForAccountReconciliation, getAccountReconByAccountIdAndSelectedPeriod, toReconciliationTabsType, isAccountReconReport, updateExpenseAutomationReconReviewTabLocalData, updateExpenseAutomationSelectedDrawerAccountId, saveExpenseAutomationReconciliationReview, updateExpenseAutomationAccountReconciliationLocalData, toReconciliationAccountSource, deleteAccountStatement, uploadAccountStatement, updateStatementUploadChosen, isReviewTransactionBankTransferType, isReviewTransactionBillPaymentType, isReviewTransactionCreditCardPaymentType, isReviewTransactionDepositType, isReviewTransactionExpenseType, isReviewTransactionCreditCardCreditType, setStatementParseInProgress, };
422
424
  export { fetchTransactionCategorization, fetchTransactionCategorizationView, updateTransactionCategorizationUIState, updateSelectedCheckboxTransactionIds, setEntityRecommendationForLineIdsForCategorization, initializeTransactionCategorizationViewLocalData, setAllItemsToCategoryClassInLocalDataForCategorization, saveTransactionCategorizationLocalData, fetchTransactionCategorizationFailure, saveTransactionCategorization, updateTransactionCategorization, updateTransactionCategorizationSaveStatus, markTransactionAsNotMiscategorized, updateSelectedVendorForTransaction, updateSelectedCustomerForTransaction, updateSelectedTransactionId, syncTransactionCategorizationFromDetailSave, backgroundRefetchReviewTab, clearExpenseAutomationTransactionsView, toTransactionsSortKey, };
@@ -610,5 +612,6 @@ export { fetchTreasuryStatementList } from './view/spendManagement/treasury/trea
610
612
  export { getTreasuryStatements, } from './view/spendManagement/treasury/treasuryStatementList/treasuryStatementListSelector';
611
613
  export { fetchTreasuryTaxLetterList } from './view/spendManagement/treasury/treasuryTaxLetterList/treasuryTaxLetterListReducer';
612
614
  export { getTreasuryTaxLetters, } from './view/spendManagement/treasury/treasuryTaxLetterList/treasuryTaxLetterListSelector';
615
+ export { BULK_UPLOAD_BAR_COMPLETE_HOLD_MS } from './view/expenseAutomationView/bulkUploadTiming';
613
616
  export { fetchTransactionActivityLog } from './view/transactionActivityLogView/transactionActivityLogViewReducer';
614
617
  export { getTransactionActivityLogView, } from './view/transactionActivityLogView/transactionActivityLogViewSelector';
@@ -0,0 +1,5 @@
1
+ /**
2
+ * After upload API success, hold the bar at 100% this long before transitioning to matching,
3
+ * so the fill animation can complete without an abrupt swap to the auto-matching banner.
4
+ */
5
+ export const BULK_UPLOAD_BAR_COMPLETE_HOLD_MS = 400;
@@ -1,7 +1,8 @@
1
- import { of } from 'rxjs';
1
+ import { concat, of, timer } from 'rxjs';
2
2
  import { catchError, filter, mergeMap } from 'rxjs/operators';
3
3
  import { createZeniAPIStatus, isSuccessResponse, } from '../../../../responsePayload';
4
- import { bulkUploadReceipts, bulkUploadReceiptsFailure, bulkUploadReceiptsSuccess, } from '../../reducers/missingReceiptsViewReducer';
4
+ import { BULK_UPLOAD_BAR_COMPLETE_HOLD_MS } from '../../bulkUploadTiming';
5
+ import { bulkUploadReceipts, bulkUploadReceiptsFailure, bulkUploadReceiptsSuccess, updateBulkUploadProgress, } from '../../reducers/missingReceiptsViewReducer';
5
6
  export const bulkUploadReceiptsEpic = (actions$, _state$, zeniAPI) => actions$.pipe(filter(bulkUploadReceipts.match), mergeMap((action) => {
6
7
  const { files } = action.payload;
7
8
  const formData = new FormData();
@@ -18,7 +19,7 @@ export const bulkUploadReceiptsEpic = (actions$, _state$, zeniAPI) => actions$.p
18
19
  error: createZeniAPIStatus('Unexpected Error', 'Bulk upload succeeded but batch_id was missing or empty.'),
19
20
  }));
20
21
  }
21
- return of(bulkUploadReceiptsSuccess({ batchId }));
22
+ return concat(of(updateBulkUploadProgress(100)), timer(BULK_UPLOAD_BAR_COMPLETE_HOLD_MS).pipe(mergeMap(() => of(bulkUploadReceiptsSuccess({ batchId })))));
22
23
  }
23
24
  return of(bulkUploadReceiptsFailure({ error: response.status }));
24
25
  }), catchError((error) => of(bulkUploadReceiptsFailure({
@@ -15,14 +15,14 @@ import { toTransactionsSortKey } from '../../types/transactionsViewState';
15
15
  export const MANUAL_TRANSACTION_SEARCH_AUTO_CATEGORIZED = false;
16
16
  export const searchTransactionsForManualMatchEpic = (actions$, state$, zeniAPI) => {
17
17
  const searchActions$ = actions$.pipe(filter(searchTransactionsForManualMatch.match));
18
- const pagination$ = searchActions$.pipe(filter((a) => a.payload.pageToken != null));
18
+ const pagination$ = searchActions$.pipe(filter((action) => action.payload.pageToken != null));
19
19
  /**
20
20
  * No API for empty or 1-char queries; immediate merge so switchMap cancels any in-flight HTTP.
21
21
  */
22
- const newSearchTooShortOrClear$ = searchActions$.pipe(filter((a) => a.payload.pageToken == null &&
23
- a.payload.query.trim().length < 2));
24
- const newSearchDebounced$ = searchActions$.pipe(filter((a) => a.payload.pageToken == null &&
25
- a.payload.query.trim().length >= 2), debounceTime(300));
22
+ const newSearchTooShortOrClear$ = searchActions$.pipe(filter((action) => action.payload.pageToken == null &&
23
+ action.payload.query.trim().length < 2));
24
+ const newSearchDebounced$ = searchActions$.pipe(filter((action) => action.payload.pageToken == null &&
25
+ action.payload.query.trim().length >= 2), debounceTime(300));
26
26
  return merge(pagination$, newSearchTooShortOrClear$, newSearchDebounced$).pipe(switchMap((action) => {
27
27
  const { query, pageToken } = action.payload;
28
28
  if (pageToken == null &&
@@ -27,7 +27,7 @@ export const pusherBatchStatusCompletionEpic = (actions$) => actions$.pipe(filte
27
27
  export const pollBulkUploadBatchStatusEpic = (actions$, _state$, zeniAPI) => actions$.pipe(filter(bulkUploadReceiptsSuccess.match), mergeMap((action) => {
28
28
  const { batchId } = action.payload;
29
29
  let pollErrorNotified = false;
30
- return timer(FALLBACK_FIRST_DELAY_MS, FALLBACK_POLL_INTERVAL_MS).pipe(takeUntil(merge(actions$.pipe(filter(clearBulkUpload.match)), actions$.pipe(filter(pusherBatchStatusUpdate.match), filter((a) => a.payload.batchId === batchId)), actions$.pipe(filter(fetchBulkUploadBatchDetailsSuccess.match), filter((a) => a.payload.batchId === batchId)))), switchMap(() => zeniAPI
30
+ return timer(FALLBACK_FIRST_DELAY_MS, FALLBACK_POLL_INTERVAL_MS).pipe(takeUntil(merge(actions$.pipe(filter(clearBulkUpload.match)), actions$.pipe(filter(pusherBatchStatusUpdate.match), filter((action) => action.payload.batchId === batchId)), actions$.pipe(filter(fetchBulkUploadBatchDetailsSuccess.match), filter((action) => action.payload.batchId === batchId)))), switchMap(() => zeniAPI
31
31
  .getJSON(`${zeniAPI.apiEndPoints.communicationAgentMicroServiceBaseUrl}/1.0/batches/${batchId}`)
32
32
  .pipe(mergeMap((response) => {
33
33
  /** Same batch-details URL; polls until `status` is completed (Pusher may win first). */
@@ -1,5 +1,6 @@
1
1
  import { toURL } from '../../../commonPayloadTypes/urlPayload';
2
2
  import { getTransactionPayloadAmount, } from '../../../entity/transaction/payloadTypes/transactionPayload';
3
+ import { toBatchFileStatus, toBatchStatusValue, toMatchSource, } from '../types/missingReceiptsViewState';
3
4
  // -- Converter functions --
4
5
  /**
5
6
  * Maps batch-details API `files[].status` strings to canonical {@link BatchFileStatus}.
@@ -7,8 +8,8 @@ import { getTransactionPayloadAmount, } from '../../../entity/transaction/payloa
7
8
  * holds untyped status values.
8
9
  */
9
10
  export function parseBatchFileStatus(raw) {
10
- const s = raw.trim().toLowerCase().replace(/-/g, '_');
11
- switch (s) {
11
+ const normalizedStatus = raw.trim().toLowerCase().replace(/-/g, '_');
12
+ switch (normalizedStatus) {
12
13
  case 'exact_match':
13
14
  case 'matched':
14
15
  return 'exact_match';
@@ -30,9 +31,9 @@ export function parseBatchFileStatus(raw) {
30
31
  export function toBatchFile(payload, filesEndPoint) {
31
32
  return {
32
33
  attachmentId: payload.attachment_id,
33
- candidates: payload.candidates?.map((c) => ({
34
- transactionId: c.transaction_id,
35
- matchScore: c.match_score,
34
+ candidates: payload.candidates?.map((candidate) => ({
35
+ transactionId: candidate.transaction_id,
36
+ matchScore: candidate.match_score,
36
37
  })),
37
38
  fileDownloadUrl: payload.file_id != null && filesEndPoint != null
38
39
  ? `${filesEndPoint}/1.0/files/${payload.file_id}?query=${encodeURIComponent(JSON.stringify({ download_file: true }))}`
@@ -40,9 +41,11 @@ export function toBatchFile(payload, filesEndPoint) {
40
41
  fileId: payload.file_id,
41
42
  filePreviewUrl: payload.file_preview_url,
42
43
  filename: payload.filename,
43
- matchSource: payload.match_source,
44
+ matchSource: payload.match_source != null
45
+ ? toMatchSource(payload.match_source)
46
+ : undefined,
44
47
  matchedTransactionId: payload.matched_transaction?.transaction_id,
45
- status: parseBatchFileStatus(payload.status),
48
+ status: toBatchFileStatus(payload.status),
46
49
  };
47
50
  }
48
51
  export function extractTransactionPayloadsFromBatchFiles(files) {
@@ -92,8 +95,8 @@ export function toBatchDetails(payload, filesEndPoint) {
92
95
  return {
93
96
  batchId: payload.batch_id,
94
97
  createdAt: payload.created_at,
95
- files: payload.files.map((f) => toBatchFile(f, filesEndPoint)),
96
- status: payload.status,
98
+ files: payload.files.map((file) => toBatchFile(file, filesEndPoint)),
99
+ status: toBatchStatusValue(payload.status),
97
100
  summary: toBatchSummary(payload.summary),
98
101
  };
99
102
  }
@@ -107,7 +110,7 @@ export function isBatchListStatusCompleted(status) {
107
110
  * statuses for UI; only `completed` rows should trigger batch-details requests.
108
111
  */
109
112
  export function filterBatchListItemsForBatchDetailsFetch(batches) {
110
- return batches.filter((b) => isBatchListStatusCompleted(b.status));
113
+ return batches.filter((batch) => isBatchListStatusCompleted(batch.status));
111
114
  }
112
115
  /**
113
116
  * Batch details API response `status` field — only completed payloads should be stored from
@@ -118,7 +121,7 @@ export function isBatchDetailsApiStatusCompleted(status) {
118
121
  }
119
122
  export function findBatchListItemForBatchId(batchListByPeriod, batchId) {
120
123
  for (const list of Object.values(batchListByPeriod)) {
121
- const found = list.find((b) => b.batchId === batchId);
124
+ const found = list.find((batch) => batch.batchId === batchId);
122
125
  if (found != null) {
123
126
  return found;
124
127
  }
@@ -1,4 +1,4 @@
1
- import { createSlice } from '@reduxjs/toolkit';
1
+ import { createAction, createSlice } from '@reduxjs/toolkit';
2
2
  import { toMonthYearPeriodId } from '../../../commonStateTypes/timePeriod';
3
3
  import { MIN_MANUAL_TRANSACTION_SEARCH_LENGTH, } from '../types/missingReceiptsViewState';
4
4
  export const getCompletedTransactionsCacheKey = (periodId, sortKey, sortOrder, subTab) => `completed-${subTab}-${sortKey}-${sortOrder === 'ascending' ? 'asc' : 'desc'}-${periodId}`;
@@ -51,6 +51,8 @@ export const initialState = {
51
51
  return this.fetchState == 'Completed';
52
52
  },
53
53
  };
54
+ /** Epic trigger only; batch-details fetch is handled in epics. */
55
+ export const fetchBulkUploadBatchDetails = createAction('expenseAutomationMissingReceiptsView/fetchBulkUploadBatchDetails');
54
56
  const expenseAutomationMissingReceiptsView = createSlice({
55
57
  name: 'expenseAutomationMissingReceiptsView',
56
58
  initialState,
@@ -154,8 +156,7 @@ const expenseAutomationMissingReceiptsView = createSlice({
154
156
  },
155
157
  // -- Bulk Upload Actions --
156
158
  bulkUploadReceipts: {
157
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
158
- reducer(draft, _action) {
159
+ reducer(draft) {
159
160
  draft.bulkUpload.phase = 'uploading';
160
161
  draft.bulkUpload.uploadProgress = 0;
161
162
  draft.bulkUpload.uploadStatus = {
@@ -172,6 +173,7 @@ const expenseAutomationMissingReceiptsView = createSlice({
172
173
  },
173
174
  bulkUploadReceiptsSuccess(draft, action) {
174
175
  draft.bulkUpload.currentBatchId = action.payload.batchId;
176
+ draft.bulkUpload.uploadProgress = 100;
175
177
  draft.bulkUpload.uploadStatus = {
176
178
  fetchState: 'Completed',
177
179
  error: undefined,
@@ -205,18 +207,18 @@ const expenseAutomationMissingReceiptsView = createSlice({
205
207
  clearMissingReceiptsTabNavigation(draft) {
206
208
  draft.pendingMissingReceiptsTabNavigation = null;
207
209
  },
208
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
209
- fetchBulkUploadBatchDetails(_draft) {
210
- // trigger epic, no state change needed
211
- },
212
210
  fetchBulkUploadBatchDetailsSuccess(draft, action) {
213
211
  const details = action.payload;
214
212
  draft.bulkUpload.batchDetailsById[details.batchId] = details;
215
213
  draft.bulkUpload.phase = 'completed';
216
214
  },
217
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
218
- fetchBulkUploadBatchDetailsFailure(draft, _action) {
219
- draft.bulkUpload.phase = 'completed';
215
+ fetchBulkUploadBatchDetailsFailure: {
216
+ reducer(draft) {
217
+ draft.bulkUpload.phase = 'completed';
218
+ },
219
+ prepare(payload) {
220
+ return { payload };
221
+ },
220
222
  },
221
223
  storeBatchDetails(draft, action) {
222
224
  const details = action.payload;
@@ -247,8 +249,8 @@ const expenseAutomationMissingReceiptsView = createSlice({
247
249
  error: undefined,
248
250
  };
249
251
  },
250
- fetchMoreBatchDetails(_draft) {
251
- _draft.bulkUpload.batchDetailsPaginationState = {
252
+ fetchMoreBatchDetails(draft) {
253
+ draft.bulkUpload.batchDetailsPaginationState = {
252
254
  fetchState: 'In-Progress',
253
255
  error: undefined,
254
256
  };
@@ -286,11 +288,11 @@ const expenseAutomationMissingReceiptsView = createSlice({
286
288
  };
287
289
  },
288
290
  prepare(input) {
289
- const o = input ?? {};
291
+ const fetchOptions = input ?? {};
290
292
  return {
291
293
  payload: {
292
- cacheOverride: o.cacheOverride === true,
293
- invalidateBatchDetailsCache: o.invalidateBatchDetailsCache === true,
294
+ cacheOverride: fetchOptions.cacheOverride === true,
295
+ invalidateBatchDetailsCache: fetchOptions.invalidateBatchDetailsCache === true,
294
296
  },
295
297
  };
296
298
  },
@@ -324,8 +326,7 @@ const expenseAutomationMissingReceiptsView = createSlice({
324
326
  };
325
327
  },
326
328
  confirmBulkUploadMatch: {
327
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
328
- reducer(draft, _action) {
329
+ reducer(draft) {
329
330
  draft.bulkUpload.confirmMatchStatus = {
330
331
  fetchState: 'In-Progress',
331
332
  error: undefined,
@@ -343,7 +344,7 @@ const expenseAutomationMissingReceiptsView = createSlice({
343
344
  };
344
345
  const details = draft.bulkUpload.batchDetailsById[batchId];
345
346
  if (details != null) {
346
- const file = details.files.find((f) => f.attachmentId === attachmentId);
347
+ const file = details.files.find((batchFile) => batchFile.attachmentId === attachmentId);
347
348
  if (file != null) {
348
349
  const originalStatus = file.status;
349
350
  file.status = 'exact_match';
@@ -426,7 +427,7 @@ const expenseAutomationMissingReceiptsView = createSlice({
426
427
  const { append, nextPageToken, results, totalCount } = action.payload;
427
428
  if (append) {
428
429
  const merged = [...draft.bulkUpload.manualSearch.results, ...results];
429
- const byId = new Map(merged.map((r) => [r.transactionId, r]));
430
+ const byId = new Map(merged.map((result) => [result.transactionId, result]));
430
431
  draft.bulkUpload.manualSearch.results = Array.from(byId.values());
431
432
  }
432
433
  else {
@@ -531,7 +532,7 @@ const expenseAutomationMissingReceiptsView = createSlice({
531
532
  });
532
533
  export const { fetchMissingReceipts, fetchMissingReceiptsSuccess, fetchMissingReceiptsFailure, uploadMissingReceiptSuccess, updateMissingReceiptUploadState, updateMissingReceiptsUIState, markMissingReceiptAsDone, clearExpenseAutomationMissingReceiptsView,
533
534
  // Bulk Upload
534
- bulkUploadReceipts, updateBulkUploadProgress, bulkUploadReceiptsSuccess, bulkUploadReceiptsFailure, pusherBatchStatusUpdate, requestMissingReceiptsTabNavigation, clearMissingReceiptsTabNavigation, fetchBulkUploadBatchDetails, fetchBulkUploadBatchDetailsSuccess, fetchBulkUploadBatchDetailsFailure, storeBatchDetails, batchDetailFetchFailed, setInitialBatchDetailsLoading, fetchMoreBatchDetails, fetchMoreBatchDetailsComplete, fetchMoreBatchDetailsFailure, fetchBulkUploadBatches, fetchBulkUploadBatchesSuccess, fetchBulkUploadBatchesFailure, confirmBulkUploadMatch, confirmBulkUploadMatchSuccess, confirmBulkUploadMatchFailure, setBulkUploadResultsTab, setBulkUploadCompletedSubTab, setBulkUploadSortConfig, clearBulkUpload, searchTransactionsForManualMatch, searchTransactionsForManualMatchSuccess, searchTransactionsForManualMatchFailure, clearManualSearchResults, acknowledgeBulkUploadConfirmMatchComplete,
535
+ bulkUploadReceipts, updateBulkUploadProgress, bulkUploadReceiptsSuccess, bulkUploadReceiptsFailure, pusherBatchStatusUpdate, requestMissingReceiptsTabNavigation, clearMissingReceiptsTabNavigation, fetchBulkUploadBatchDetailsSuccess, fetchBulkUploadBatchDetailsFailure, storeBatchDetails, batchDetailFetchFailed, setInitialBatchDetailsLoading, fetchMoreBatchDetails, fetchMoreBatchDetailsComplete, fetchMoreBatchDetailsFailure, fetchBulkUploadBatches, fetchBulkUploadBatchesSuccess, fetchBulkUploadBatchesFailure, confirmBulkUploadMatch, confirmBulkUploadMatchSuccess, confirmBulkUploadMatchFailure, setBulkUploadResultsTab, setBulkUploadCompletedSubTab, setBulkUploadSortConfig, clearBulkUpload, searchTransactionsForManualMatch, searchTransactionsForManualMatchSuccess, searchTransactionsForManualMatchFailure, clearManualSearchResults, acknowledgeBulkUploadConfirmMatchComplete,
535
536
  // Completed Transactions
536
537
  fetchCompletedTransactions, fetchCompletedTransactionsSuccess, fetchCompletedTransactionsFailure, } = expenseAutomationMissingReceiptsView.actions;
537
538
  export default expenseAutomationMissingReceiptsView.reducer;
@@ -64,45 +64,68 @@ export function getExpenseAutomationMissingReceiptsView(state) {
64
64
  * so we do not block the whole tab while other rows are not fetched yet.
65
65
  */
66
66
  const primaryBatchIdFromDetailsOrder = getPrimaryBatchIdFromBatchListOrder(batchList, bulkUpload.batchDetailsById, bulkUpload.failedBatchDetailIds);
67
- /** During upload/matching, the in-flight batch may not appear in batchList yet — prefer currentBatchId. */
68
- const unmatchedSectionBatchId = bulkUpload.phase === 'matching' || bulkUpload.phase === 'uploading'
69
- ? bulkUpload.currentBatchId ?? primaryBatchIdFromDetailsOrder
70
- : primaryBatchIdFromDetailsOrder;
71
- const completedBatchesInApiOrder = batchList.filter((b) => isBatchListStatusCompleted(b.status));
67
+ /**
68
+ * During upload/matching, prefer `currentBatchId` only when it is not yet in the period
69
+ * `batchList` (true in-flight), or when its details are completed and include unmatched-tab work.
70
+ * Otherwise keep `primaryBatchIdFromDetailsOrder` so a new batch with no `possible_matches` /
71
+ * `no_match` rows yet does not vacate the primary column and push older batches into "past".
72
+ */
73
+ const unmatchedSectionBatchId = (() => {
74
+ const phase = bulkUpload.phase;
75
+ if (phase !== 'matching' && phase !== 'uploading') {
76
+ return primaryBatchIdFromDetailsOrder;
77
+ }
78
+ const currentId = bulkUpload.currentBatchId;
79
+ if (currentId == null) {
80
+ return primaryBatchIdFromDetailsOrder;
81
+ }
82
+ const currentInBatchList = batchList.some((b) => b.batchId === currentId);
83
+ if (!currentInBatchList) {
84
+ return currentId;
85
+ }
86
+ const currentDetails = bulkUpload.batchDetailsById[currentId];
87
+ if (currentDetails != null &&
88
+ currentDetails.status === 'completed' &&
89
+ batchDetailsHasUnmatchedWork(currentDetails)) {
90
+ return currentId;
91
+ }
92
+ return primaryBatchIdFromDetailsOrder;
93
+ })();
94
+ const completedBatchesInApiOrder = batchList.filter((batchListItem) => isBatchListStatusCompleted(batchListItem.status));
72
95
  const currentBatchDetails = unmatchedSectionBatchId != null
73
96
  ? bulkUpload.batchDetailsById[unmatchedSectionBatchId]
74
97
  : undefined;
75
98
  const resolvedFiles = currentBatchDetails?.files.map((file) => resolveBatchFile(file, currentBatchDetails.batchId, transactionState));
76
99
  const failedIds = new Set(bulkUpload.failedBatchDetailIds);
77
- const hasMoreBatchDetails = completedBatchesInApiOrder.some((b) => bulkUpload.batchDetailsById[b.batchId] == null &&
78
- !failedIds.has(b.batchId));
100
+ const hasMoreBatchDetails = completedBatchesInApiOrder.some((batchListItem) => bulkUpload.batchDetailsById[batchListItem.batchId] == null &&
101
+ !failedIds.has(batchListItem.batchId));
79
102
  const getSortValue = (file) => {
80
- const t = file.matchedTransaction;
81
- if (t == null) {
103
+ const matchedTransaction = file.matchedTransaction;
104
+ if (matchedTransaction == null) {
82
105
  return null;
83
106
  }
84
107
  switch (bulkUpload.sortKey) {
85
108
  case 'vendor':
86
- return (t.vendorName ?? t.description)?.toLowerCase() ?? null;
109
+ return (matchedTransaction.vendorName ?? matchedTransaction.description)?.toLowerCase() ?? null;
87
110
  case 'category': {
88
- const line = t.lines?.[0];
111
+ const line = matchedTransaction.lines?.[0];
89
112
  return line?.account?.accountName?.toLowerCase() ?? null;
90
113
  }
91
114
  case 'class': {
92
- const line = t.lines?.[0];
115
+ const line = matchedTransaction.lines?.[0];
93
116
  return line?.class?.className?.toLowerCase() ?? null;
94
117
  }
95
118
  case 'date':
96
- return t.date.valueOf();
119
+ return matchedTransaction.date.valueOf();
97
120
  case 'amount':
98
- return t.amount.amount;
121
+ return matchedTransaction.amount.amount;
99
122
  default:
100
123
  return null;
101
124
  }
102
125
  };
103
126
  const bulkUploadSortDirection = bulkUpload.sortOrder === 'ascending' ? 'asc' : 'desc';
104
- const matchedFiles = orderBy(resolvedFiles?.filter((f) => f.status === 'exact_match') ?? [], getSortValue, bulkUploadSortDirection);
105
- const unmatchedFiles = orderBy(resolvedFiles?.filter((f) => isUnmatchedTabFileStatus(f.status)) ?? [], getSortValue, bulkUploadSortDirection);
127
+ const matchedFiles = orderBy(resolvedFiles?.filter((resolvedFile) => resolvedFile.status === 'exact_match') ?? [], getSortValue, bulkUploadSortDirection);
128
+ const unmatchedFiles = orderBy(resolvedFiles?.filter((resolvedFile) => isUnmatchedTabFileStatus(resolvedFile.status)) ?? [], getSortValue, bulkUploadSortDirection);
106
129
  const progress = currentBatchStatus != null
107
130
  ? {
108
131
  ...currentBatchStatus.progress,
@@ -119,16 +142,16 @@ export function getExpenseAutomationMissingReceiptsView(state) {
119
142
  * that has details loaded (otherwise past is empty and receipts vanish from the UI).
120
143
  */
121
144
  const pastBatches = unmatchedSectionBatchId != null
122
- ? batchList.filter((b) => b.batchId !== unmatchedSectionBatchId)
145
+ ? batchList.filter((batchListItem) => batchListItem.batchId !== unmatchedSectionBatchId)
123
146
  : batchList;
124
- const pastUnmatchedFiles = pastBatches.flatMap((b) => {
125
- const details = bulkUpload.batchDetailsById[b.batchId];
147
+ const pastUnmatchedFiles = pastBatches.flatMap((pastBatch) => {
148
+ const details = bulkUpload.batchDetailsById[pastBatch.batchId];
126
149
  if (details == null) {
127
150
  return [];
128
151
  }
129
152
  return details.files
130
- .filter((f) => isUnmatchedTabFileStatus(f.status))
131
- .map((f) => resolveBatchFile(f, b.batchId, transactionState));
153
+ .filter((batchFile) => isUnmatchedTabFileStatus(batchFile.status))
154
+ .map((batchFile) => resolveBatchFile(batchFile, pastBatch.batchId, transactionState));
132
155
  });
133
156
  const completedTransactionsCacheKey = monthYearPeriodId != null
134
157
  ? getCompletedTransactionsCacheKey(monthYearPeriodId, bulkUpload.sortKey, bulkUpload.sortOrder, bulkUpload.completedSubTab)
@@ -147,11 +170,11 @@ export function getExpenseAutomationMissingReceiptsView(state) {
147
170
  summary: currentBatchDetails.summary,
148
171
  }
149
172
  : undefined;
150
- const manualSearchResults = bulkUpload.manualSearch.results.map((r) => {
151
- const t = getSupportedTransactionById(transactionState, r.transactionId);
173
+ const manualSearchResults = bulkUpload.manualSearch.results.map((result) => {
174
+ const transaction = getSupportedTransactionById(transactionState, result.transactionId);
152
175
  return {
153
- ...r,
154
- vendorLogo: r.vendorLogo ?? t?.logo?.href,
176
+ ...result,
177
+ vendorLogo: result.vendorLogo ?? transaction?.logo?.href,
155
178
  };
156
179
  });
157
180
  return {
@@ -201,7 +224,7 @@ export function getExpenseAutomationMissingReceiptsView(state) {
201
224
  };
202
225
  }
203
226
  function batchDetailsHasUnmatchedWork(details) {
204
- return details.files.some((f) => isUnmatchedTabFileStatus(f.status));
227
+ return details.files.some((file) => isUnmatchedTabFileStatus(file.status));
205
228
  }
206
229
  /** List row summary before batch details load — aligns with unmatched / possible-match work. */
207
230
  function batchListItemHasUnmatchedWork(batch) {
@@ -218,17 +241,17 @@ function batchListItemHasUnmatchedWork(batch) {
218
241
  */
219
242
  function getPrimaryBatchIdFromBatchListOrder(batchListInPlatformOrder, batchDetailsById, failedBatchDetailIds) {
220
243
  const failedIds = new Set(failedBatchDetailIds);
221
- const anyCompletedBatchHasUnmatchedWork = batchListInPlatformOrder.some((b) => {
222
- if (failedIds.has(b.batchId)) {
244
+ const anyCompletedBatchHasUnmatchedWork = batchListInPlatformOrder.some((batch) => {
245
+ if (failedIds.has(batch.batchId)) {
223
246
  return false;
224
247
  }
225
- const d = batchDetailsById[b.batchId];
226
- if (d != null &&
227
- d.status === 'completed' &&
228
- batchDetailsHasUnmatchedWork(d)) {
248
+ const details = batchDetailsById[batch.batchId];
249
+ if (details != null &&
250
+ details.status === 'completed' &&
251
+ batchDetailsHasUnmatchedWork(details)) {
229
252
  return true;
230
253
  }
231
- return d == null && batchListItemHasUnmatchedWork(b);
254
+ return details == null && batchListItemHasUnmatchedWork(batch);
232
255
  });
233
256
  for (const batch of batchListInPlatformOrder) {
234
257
  if (failedIds.has(batch.batchId)) {
@@ -265,7 +288,7 @@ function resolveBatchFile(file, batchId, transactionState) {
265
288
  ? { transaction, matchScore: ref.matchScore }
266
289
  : undefined;
267
290
  })
268
- .filter((c) => c != null);
291
+ .filter((candidate) => candidate != null);
269
292
  return {
270
293
  attachmentId: file.attachmentId,
271
294
  batchId,
@@ -13,7 +13,36 @@ export const toMissingReceiptsSortKey = (v) => stringToUnion(v, MISSING_RECEIPTS
13
13
  * Kept in sync with `ManualSearchInput` in web-components (fires search only when length ≥ this).
14
14
  */
15
15
  export const MIN_MANUAL_TRANSACTION_SEARCH_LENGTH = 2;
16
+ const BATCH_STATUS_VALUES = ['pending', 'processing', 'completed'];
17
+ export const toBatchStatusValue = (v) => stringToUnion(v.trim().toLowerCase(), BATCH_STATUS_VALUES);
18
+ /** Canonical batch file statuses (API ingress may use aliases; see `parseBatchFileStatus`). */
19
+ export const BATCH_FILE_STATUSES = [
20
+ 'exact_match',
21
+ 'possible_matches',
22
+ 'no_match',
23
+ 'failed',
24
+ ];
25
+ export const toBatchFileStatus = (v) => stringToUnion(v.trim().toLowerCase().replace(/-/g, '_'), BATCH_FILE_STATUSES);
26
+ const UNMATCHED_TAB_FILE_STATUSES = ['possible_matches', 'no_match'];
16
27
  /** True for files that belong in the Unmatched tab (possible matches or no match). */
17
28
  export function isUnmatchedTabFileStatus(status) {
18
- return status === 'possible_matches' || status === 'no_match';
29
+ return UNMATCHED_TAB_FILE_STATUSES.includes(status);
19
30
  }
31
+ const BULK_UPLOAD_PHASES = ['idle', 'uploading', 'matching', 'completed'];
32
+ export const toBulkUploadPhase = (v) => stringToUnion(v.trim().toLowerCase(), BULK_UPLOAD_PHASES);
33
+ const BULK_UPLOAD_RESULTS_TABS = ['completed', 'unmatched'];
34
+ export const toBulkUploadResultsTab = (v) => stringToUnion(v.trim().toLowerCase(), BULK_UPLOAD_RESULTS_TABS);
35
+ const MISSING_RECEIPTS_TABS = ['missing', 'completed', 'unmatched'];
36
+ export const toMissingReceiptsTab = (v) => stringToUnion(v.trim().toLowerCase(), MISSING_RECEIPTS_TABS);
37
+ const COMPLETED_SUB_TABS = ['all', 'ai_accountant', 'manual'];
38
+ export const toCompletedSubTab = (v) => stringToUnion(v.trim().toLowerCase(), COMPLETED_SUB_TABS);
39
+ const MATCH_SOURCES = ['ai', 'manual'];
40
+ export const toMatchSource = (v) => stringToUnion(v.trim().toLowerCase(), MATCH_SOURCES);
41
+ const BULK_UPLOAD_SORT_KEYS = [
42
+ 'amount',
43
+ 'category',
44
+ 'class',
45
+ 'date',
46
+ 'vendor',
47
+ ];
48
+ export const toBulkUploadSortKey = (v) => stringToUnion(v.trim().toLowerCase(), BULK_UPLOAD_SORT_KEYS);
package/lib/index.d.ts CHANGED
@@ -281,7 +281,7 @@ import { getExpenseAutomationReconciliationView, isAccountReconReport } from './
281
281
  import { getExpenseAutomationTransactionView } from './view/expenseAutomationView/selectors/transactionCategorizationSelector';
282
282
  import { FluxAnalysisActionType, FluxAnalysisReviewStatus, FluxAnalysisSortKey, FluxAnalysisViewUIState, FluxBalancesByMonth } from './view/expenseAutomationView/types/fluxAnalysisViewState';
283
283
  import { AccountSettingsLocalData, JEScheduleLocalData } from './view/expenseAutomationView/types/jeSchedulesViewState';
284
- import { BatchDetails, BatchFile, BatchFileStatus, BatchListItem, BatchStatus, BatchStatusValue, BatchSummary, BulkUploadPhase, BulkUploadResultsTab, BulkUploadSortKey, BulkUploadState, CandidateRef, CompletedSubTab, isUnmatchedTabFileStatus, MatchCandidate, MatchSource, MissingReceiptsTab } from './view/expenseAutomationView/types/missingReceiptsViewState';
284
+ import { BATCH_FILE_STATUSES, BatchDetails, BatchFile, BatchFileStatus, BatchListItem, BatchStatus, BatchStatusValue, BatchSummary, BulkUploadPhase, BulkUploadResultsTab, BulkUploadSortKey, BulkUploadState, CandidateRef, CompletedSubTab, isUnmatchedTabFileStatus, MatchCandidate, MatchSource, MissingReceiptsTab, toBatchFileStatus, toBatchStatusValue, toBulkUploadPhase, toBulkUploadResultsTab, toBulkUploadSortKey, toCompletedSubTab, toMatchSource, toMissingReceiptsTab } from './view/expenseAutomationView/types/missingReceiptsViewState';
285
285
  import { CompletedTransactionsSelectorData, ResolvedBatchFile, ResolvedCandidate, ResolvedBatchDetails } from './view/expenseAutomationView/selectorTypes/missingReceiptsSelectorTypes';
286
286
  import { MissingReceiptsSortKey as ExpenseAutomationMissingReceiptsSortKey, MissingReceiptsViewState as ExpenseAutomationMissingReceiptsViewState, MissingReceiptsViewUIState as ExpenseAutomationMissingReceiptsViewUIState, toMissingReceiptsSortKey as toExpenseAutomationMissingReceiptsSortKey } from './view/expenseAutomationView/types/missingReceiptsViewState';
287
287
  import { AccountReconciliationLocalData, ReconciliationViewTabType as ExpenseAutomationReconciliationViewTab, ReconReconcileSortKey, ReconReviewSortKey, ReconciliationReconcileTabLocalData, ReconciliationReviewTabLocalData, SaveReconcileDetailActionPayload as SaveExpenseAutomationReconciliationActionType, toReconciliationTabsType } from './view/expenseAutomationView/types/reconciliationViewState';
@@ -623,7 +623,7 @@ export { TransactionsOrder, COABalancesSliceOrder, EntityOrder, Section, Section
623
623
  export { ClassesViewSelectorReportV2 };
624
624
  export { BalancesTimeseries, TrendTimeseries, BalanceKind };
625
625
  export { fetchMonthEndCloseChecks, fetchMonthClosePerformanceTrend, MonthClosePerformanceTrend, MonthEndCloseCheck, getMonthEndCloseChecksViewByTenantId, MonthEndCloseChecksView, MonthEndCloseCheckFrequency, MonthCloseCheckMetrics, ALL_MONTH_END_CLOSE_CHECKS_FREQUENCY, MonthEndAuditSummary, };
626
- export { ExpenseAutomationViewSelector, ExpenseAutomationStepDetails, ExpenseAutomationViewType, ExpenseAutomationMissingReceiptsViewSelector, BulkUploadSelectorData, ExpenseAutomationFluxAnalysisViewSelector, FluxAnalysisVendorView, FluxAnalysisViewSectionReport, FluxVendorAccountsAndClassesView, ExpenseAutomationMissingReceiptsViewUIState, ExpenseAutomationMissingReceiptsViewState, ExpenseAutomationViewState, ExpenseAutomationTransactionsTab, ExpenseAutomationMissingReceiptsSortKey, BatchDetails, BatchFile, BatchFileStatus, BatchListItem, isUnmatchedTabFileStatus, BatchStatus, BatchStatusValue, BatchSummary, BulkUploadPhase, BulkUploadResultsTab, BulkUploadSortKey, BulkUploadState, CandidateRef, CompletedSubTab, CompletedTransactionsSelectorData, MatchCandidate, MatchSource, MissingReceiptsTab, ResolvedBatchFile, ResolvedBatchDetails, ResolvedCandidate, getExpenseAutomationView, toExpenseAutomationMissingReceiptsSortKey, toExpenseAutomationTransactionsTabKey, toExpenseAutomationViewType, uploadExpenseAutomationMissingReceiptSuccess, markExpenseAutomationMissingReceiptAsDone, fetchAllExpenseAutomationTabs, refreshExpenseAutomationCurrentTab, updateCurrentSelectedTransactionCategorizationTab, fetchExpenseAutomationMissingReceipts, bulkUploadReceipts, bulkUploadReceiptsSuccess, bulkUploadReceiptsFailure, updateBulkUploadProgress, pusherBatchStatusUpdate, requestMissingReceiptsTabNavigation, clearMissingReceiptsTabNavigation, fetchBulkUploadBatchDetails, fetchBulkUploadBatchDetailsSuccess, fetchBulkUploadBatchDetailsFailure, storeBatchDetails, fetchMoreBatchDetails, fetchMoreBatchDetailsComplete, fetchMoreBatchDetailsFailure, fetchBulkUploadBatches, fetchBulkUploadBatchesSuccess, fetchBulkUploadBatchesFailure, confirmBulkUploadMatch, confirmBulkUploadMatchSuccess, confirmBulkUploadMatchFailure, setBulkUploadResultsTab, setBulkUploadCompletedSubTab, setBulkUploadSortConfig, clearBulkUpload, searchTransactionsForManualMatch, searchTransactionsForManualMatchSuccess, searchTransactionsForManualMatchFailure, clearManualSearchResults, acknowledgeBulkUploadConfirmMatchComplete, fetchCompletedTransactions, fetchCompletedTransactionsSuccess, fetchCompletedTransactionsFailure, fetchFluxAnalysisView, clearExpenseAutomationFluxAnalysisView, updateOperatingExpensesIdsForReview as updateFluxOperatingExpensesIdsForReview, updateSelectedSectionIdsForReview as updateFluxAnalysisSelectedSectionIdsForReview, reviewFluxAnalysisView, updateExpenseAutomationMissingReceiptUploadState, updateExpenseAutomationMissingReceiptsUIState, updateTransactionCategorizationUploadReceiptState, uploadTransactionCategorizationReceiptSuccess, FluxAnalysisOperatingExpenseView, FluxAnalysisSectionType, getExpenseAutomationFluxAnalysisView, FluxAnalysisSortKey, FluxAnalysisActionType, FluxBalancesByMonth, updateCurrentSelectedView, updateCurrentSelectedPeriod, getExpenseAutomationTransactionView, ReconReconcileSortKey, ReconciliationReconcileTabLocalData, FluxAnalysisReviewStatus, updateFluxAnalysisViewUIState, FluxAnalysisViewUIState, updateFluxAnalysisViewPageMetaData, MAX_SELECTION_LIMIT, checkIfAllLineItemsAreCategoryClassFilled, getLineItemsByTransactionIdsFromLocalData, isAnyItemWithUncategorizedExpenseAccount, SaveExpenseAutomationReconciliationActionType, saveExpenseAutomationReconciliationDetail, updateExpenseAutomationReconcileTabListScrollState, updateExpenseAutomationReconReviewTabListSortState, updateExpenseAutomationReconcileTabListSortState, updateExpenseAutomationReconcileTabLocalData, updateExpenseAutomationAccountReconciliationSelectedTab, updateExpenseAutomationAccountReconciliationSelectedAccountId, ExpenseAutomationReconciliationViewSelector, getExpenseAutomationReconciliationView, AccountReconciliationBySection, fetchReconciliationView, uploadAccountStatementIntoDocumentAI, UploadStatementDocumentAIResponse, updateExpenseAutomationReconListScrollPosition, setConnectionInProgressForAccountReconciliation, AccountReconciliationByAccount, AccountReconciliationEntity, getAccountReconByAccountIdAndSelectedPeriod, ExpenseAutomationReconciliationViewTab, toReconciliationTabsType, isAccountReconReport, ReconReviewSortKey, AccountReconSectionID, ReconciliationReviewTabLocalData, TransactionsToReview, RecommendedActionCodeType, ReconciliationStatusCodeType, BalanceDataStatusCodeType, updateExpenseAutomationReconReviewTabLocalData, updateExpenseAutomationSelectedDrawerAccountId, saveExpenseAutomationReconciliationReview, updateExpenseAutomationAccountReconciliationLocalData, BankStatusCodeType, ReconciliationAccountSourceType, toReconciliationAccountSource, StatementStatusCodeType, AccountReconciliationLocalData, StatementDataStatusCodeType, deleteAccountStatement, uploadAccountStatement, UploadStatementDocumentAIPayload, updateStatementUploadChosen, isReviewTransactionBankTransferType, isReviewTransactionBillPaymentType, isReviewTransactionCreditCardPaymentType, isReviewTransactionDepositType, isReviewTransactionExpenseType, isReviewTransactionCreditCardCreditType, setStatementParseInProgress, };
626
+ export { ExpenseAutomationViewSelector, ExpenseAutomationStepDetails, ExpenseAutomationViewType, ExpenseAutomationMissingReceiptsViewSelector, BulkUploadSelectorData, ExpenseAutomationFluxAnalysisViewSelector, FluxAnalysisVendorView, FluxAnalysisViewSectionReport, FluxVendorAccountsAndClassesView, ExpenseAutomationMissingReceiptsViewUIState, ExpenseAutomationMissingReceiptsViewState, ExpenseAutomationViewState, ExpenseAutomationTransactionsTab, ExpenseAutomationMissingReceiptsSortKey, BATCH_FILE_STATUSES, BatchDetails, BatchFile, BatchFileStatus, BatchListItem, isUnmatchedTabFileStatus, BatchStatus, BatchStatusValue, BatchSummary, BulkUploadPhase, BulkUploadResultsTab, BulkUploadSortKey, BulkUploadState, CandidateRef, CompletedSubTab, CompletedTransactionsSelectorData, MatchCandidate, MatchSource, MissingReceiptsTab, toBatchFileStatus, toBatchStatusValue, toBulkUploadPhase, toBulkUploadResultsTab, toBulkUploadSortKey, toCompletedSubTab, toMatchSource, toMissingReceiptsTab, ResolvedBatchFile, ResolvedBatchDetails, ResolvedCandidate, getExpenseAutomationView, toExpenseAutomationMissingReceiptsSortKey, toExpenseAutomationTransactionsTabKey, toExpenseAutomationViewType, uploadExpenseAutomationMissingReceiptSuccess, markExpenseAutomationMissingReceiptAsDone, fetchAllExpenseAutomationTabs, refreshExpenseAutomationCurrentTab, updateCurrentSelectedTransactionCategorizationTab, fetchExpenseAutomationMissingReceipts, bulkUploadReceipts, bulkUploadReceiptsSuccess, bulkUploadReceiptsFailure, updateBulkUploadProgress, pusherBatchStatusUpdate, requestMissingReceiptsTabNavigation, clearMissingReceiptsTabNavigation, fetchBulkUploadBatchDetails, fetchBulkUploadBatchDetailsSuccess, fetchBulkUploadBatchDetailsFailure, storeBatchDetails, fetchMoreBatchDetails, fetchMoreBatchDetailsComplete, fetchMoreBatchDetailsFailure, fetchBulkUploadBatches, fetchBulkUploadBatchesSuccess, fetchBulkUploadBatchesFailure, confirmBulkUploadMatch, confirmBulkUploadMatchSuccess, confirmBulkUploadMatchFailure, setBulkUploadResultsTab, setBulkUploadCompletedSubTab, setBulkUploadSortConfig, clearBulkUpload, searchTransactionsForManualMatch, searchTransactionsForManualMatchSuccess, searchTransactionsForManualMatchFailure, clearManualSearchResults, acknowledgeBulkUploadConfirmMatchComplete, fetchCompletedTransactions, fetchCompletedTransactionsSuccess, fetchCompletedTransactionsFailure, fetchFluxAnalysisView, clearExpenseAutomationFluxAnalysisView, updateOperatingExpensesIdsForReview as updateFluxOperatingExpensesIdsForReview, updateSelectedSectionIdsForReview as updateFluxAnalysisSelectedSectionIdsForReview, reviewFluxAnalysisView, updateExpenseAutomationMissingReceiptUploadState, updateExpenseAutomationMissingReceiptsUIState, updateTransactionCategorizationUploadReceiptState, uploadTransactionCategorizationReceiptSuccess, FluxAnalysisOperatingExpenseView, FluxAnalysisSectionType, getExpenseAutomationFluxAnalysisView, FluxAnalysisSortKey, FluxAnalysisActionType, FluxBalancesByMonth, updateCurrentSelectedView, updateCurrentSelectedPeriod, getExpenseAutomationTransactionView, ReconReconcileSortKey, ReconciliationReconcileTabLocalData, FluxAnalysisReviewStatus, updateFluxAnalysisViewUIState, FluxAnalysisViewUIState, updateFluxAnalysisViewPageMetaData, MAX_SELECTION_LIMIT, checkIfAllLineItemsAreCategoryClassFilled, getLineItemsByTransactionIdsFromLocalData, isAnyItemWithUncategorizedExpenseAccount, SaveExpenseAutomationReconciliationActionType, saveExpenseAutomationReconciliationDetail, updateExpenseAutomationReconcileTabListScrollState, updateExpenseAutomationReconReviewTabListSortState, updateExpenseAutomationReconcileTabListSortState, updateExpenseAutomationReconcileTabLocalData, updateExpenseAutomationAccountReconciliationSelectedTab, updateExpenseAutomationAccountReconciliationSelectedAccountId, ExpenseAutomationReconciliationViewSelector, getExpenseAutomationReconciliationView, AccountReconciliationBySection, fetchReconciliationView, uploadAccountStatementIntoDocumentAI, UploadStatementDocumentAIResponse, updateExpenseAutomationReconListScrollPosition, setConnectionInProgressForAccountReconciliation, AccountReconciliationByAccount, AccountReconciliationEntity, getAccountReconByAccountIdAndSelectedPeriod, ExpenseAutomationReconciliationViewTab, toReconciliationTabsType, isAccountReconReport, ReconReviewSortKey, AccountReconSectionID, ReconciliationReviewTabLocalData, TransactionsToReview, RecommendedActionCodeType, ReconciliationStatusCodeType, BalanceDataStatusCodeType, updateExpenseAutomationReconReviewTabLocalData, updateExpenseAutomationSelectedDrawerAccountId, saveExpenseAutomationReconciliationReview, updateExpenseAutomationAccountReconciliationLocalData, BankStatusCodeType, ReconciliationAccountSourceType, toReconciliationAccountSource, StatementStatusCodeType, AccountReconciliationLocalData, StatementDataStatusCodeType, deleteAccountStatement, uploadAccountStatement, UploadStatementDocumentAIPayload, updateStatementUploadChosen, isReviewTransactionBankTransferType, isReviewTransactionBillPaymentType, isReviewTransactionCreditCardPaymentType, isReviewTransactionDepositType, isReviewTransactionExpenseType, isReviewTransactionCreditCardCreditType, setStatementParseInProgress, };
627
627
  export { JEScheduleLocalData };
628
628
  export { ExpenseAutomationJESchedulesViewSelector, JEAccountSettingsView, JEScheduledTransactionWithFailedEntries, };
629
629
  export { fetchTransactionCategorization, fetchTransactionCategorizationView, updateTransactionCategorizationUIState, updateSelectedCheckboxTransactionIds, setEntityRecommendationForLineIdsForCategorization, initializeTransactionCategorizationViewLocalData, setAllItemsToCategoryClassInLocalDataForCategorization, saveTransactionCategorizationLocalData, fetchTransactionCategorizationFailure, saveTransactionCategorization, updateTransactionCategorization, updateTransactionCategorizationSaveStatus, markTransactionAsNotMiscategorized, updateSelectedVendorForTransaction, updateSelectedCustomerForTransaction, updateSelectedTransactionId, syncTransactionCategorizationFromDetailSave, backgroundRefetchReviewTab, clearExpenseAutomationTransactionsView, TransactionsSortKey, toTransactionsSortKey, TransactionsTab, TransactionCategorizationLineItemData, TransactionReviewLocalData, SupportedTransactionCategorization, ExpenseAutomationTransactionsViewState, ExpenseAutomationTransactionsViewUIState, ExpenseAutomationTransactionViewSelector, TransactionReviewLocalDataSelectorView, };
@@ -870,5 +870,6 @@ export { fetchTreasuryTaxLetterList } from './view/spendManagement/treasury/trea
870
870
  export { TreasuryTaxLettersSelectorView, getTreasuryTaxLetters, } from './view/spendManagement/treasury/treasuryTaxLetterList/treasuryTaxLetterListSelector';
871
871
  export { TreasuryTransactionStatus } from './view/spendManagement/treasury/treasuryList/treasuryDetailPayload';
872
872
  export type { TransactionActivityLog } from './entity/transactionActivityLog/transactionActivityLogState';
873
+ export { BULK_UPLOAD_BAR_COMPLETE_HOLD_MS } from './view/expenseAutomationView/bulkUploadTiming';
873
874
  export { fetchTransactionActivityLog } from './view/transactionActivityLogView/transactionActivityLogViewReducer';
874
875
  export { TransactionActivityLogViewSelectorView, getTransactionActivityLogView, } from './view/transactionActivityLogView/transactionActivityLogViewSelector';