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

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 (20) hide show
  1. package/lib/esm/index.js +4 -2
  2. package/lib/esm/view/expenseAutomationView/epics/missingReceipts/searchTransactionsForManualMatchEpic.js +5 -5
  3. package/lib/esm/view/expenseAutomationView/epics/missingReceipts/watchBulkUploadBatchStatusEpic.js +1 -1
  4. package/lib/esm/view/expenseAutomationView/payload/missingReceiptsPayload.js +13 -10
  5. package/lib/esm/view/expenseAutomationView/reducers/missingReceiptsViewReducer.js +4 -4
  6. package/lib/esm/view/expenseAutomationView/selectors/missingReceiptsSelector.js +30 -30
  7. package/lib/esm/view/expenseAutomationView/types/missingReceiptsViewState.js +30 -1
  8. package/lib/index.d.ts +2 -2
  9. package/lib/index.js +41 -32
  10. package/lib/tsconfig.typecheck.tsbuildinfo +1 -1
  11. package/lib/view/expenseAutomationView/epics/missingReceipts/searchTransactionsForManualMatchEpic.js +5 -5
  12. package/lib/view/expenseAutomationView/epics/missingReceipts/watchBulkUploadBatchStatusEpic.js +1 -1
  13. package/lib/view/expenseAutomationView/payload/missingReceiptsPayload.d.ts +1 -1
  14. package/lib/view/expenseAutomationView/payload/missingReceiptsPayload.js +13 -10
  15. package/lib/view/expenseAutomationView/reducers/missingReceiptsViewReducer.d.ts +1 -1
  16. package/lib/view/expenseAutomationView/reducers/missingReceiptsViewReducer.js +4 -4
  17. package/lib/view/expenseAutomationView/selectors/missingReceiptsSelector.js +30 -30
  18. package/lib/view/expenseAutomationView/types/missingReceiptsViewState.d.ts +20 -9
  19. package/lib/view/expenseAutomationView/types/missingReceiptsViewState.js +39 -2
  20. 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, };
@@ -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 { 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,7 +41,9 @@ 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
48
  status: parseBatchFileStatus(payload.status),
46
49
  };
@@ -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
  }
@@ -286,11 +286,11 @@ const expenseAutomationMissingReceiptsView = createSlice({
286
286
  };
287
287
  },
288
288
  prepare(input) {
289
- const o = input ?? {};
289
+ const fetchOptions = input ?? {};
290
290
  return {
291
291
  payload: {
292
- cacheOverride: o.cacheOverride === true,
293
- invalidateBatchDetailsCache: o.invalidateBatchDetailsCache === true,
292
+ cacheOverride: fetchOptions.cacheOverride === true,
293
+ invalidateBatchDetailsCache: fetchOptions.invalidateBatchDetailsCache === true,
294
294
  },
295
295
  };
296
296
  },
@@ -343,7 +343,7 @@ const expenseAutomationMissingReceiptsView = createSlice({
343
343
  };
344
344
  const details = draft.bulkUpload.batchDetailsById[batchId];
345
345
  if (details != null) {
346
- const file = details.files.find((f) => f.attachmentId === attachmentId);
346
+ const file = details.files.find((batchFile) => batchFile.attachmentId === attachmentId);
347
347
  if (file != null) {
348
348
  const originalStatus = file.status;
349
349
  file.status = 'exact_match';
@@ -68,41 +68,41 @@ export function getExpenseAutomationMissingReceiptsView(state) {
68
68
  const unmatchedSectionBatchId = bulkUpload.phase === 'matching' || bulkUpload.phase === 'uploading'
69
69
  ? bulkUpload.currentBatchId ?? primaryBatchIdFromDetailsOrder
70
70
  : primaryBatchIdFromDetailsOrder;
71
- const completedBatchesInApiOrder = batchList.filter((b) => isBatchListStatusCompleted(b.status));
71
+ const completedBatchesInApiOrder = batchList.filter((batchListItem) => isBatchListStatusCompleted(batchListItem.status));
72
72
  const currentBatchDetails = unmatchedSectionBatchId != null
73
73
  ? bulkUpload.batchDetailsById[unmatchedSectionBatchId]
74
74
  : undefined;
75
75
  const resolvedFiles = currentBatchDetails?.files.map((file) => resolveBatchFile(file, currentBatchDetails.batchId, transactionState));
76
76
  const failedIds = new Set(bulkUpload.failedBatchDetailIds);
77
- const hasMoreBatchDetails = completedBatchesInApiOrder.some((b) => bulkUpload.batchDetailsById[b.batchId] == null &&
78
- !failedIds.has(b.batchId));
77
+ const hasMoreBatchDetails = completedBatchesInApiOrder.some((batchListItem) => bulkUpload.batchDetailsById[batchListItem.batchId] == null &&
78
+ !failedIds.has(batchListItem.batchId));
79
79
  const getSortValue = (file) => {
80
- const t = file.matchedTransaction;
81
- if (t == null) {
80
+ const matchedTransaction = file.matchedTransaction;
81
+ if (matchedTransaction == null) {
82
82
  return null;
83
83
  }
84
84
  switch (bulkUpload.sortKey) {
85
85
  case 'vendor':
86
- return (t.vendorName ?? t.description)?.toLowerCase() ?? null;
86
+ return (matchedTransaction.vendorName ?? matchedTransaction.description)?.toLowerCase() ?? null;
87
87
  case 'category': {
88
- const line = t.lines?.[0];
88
+ const line = matchedTransaction.lines?.[0];
89
89
  return line?.account?.accountName?.toLowerCase() ?? null;
90
90
  }
91
91
  case 'class': {
92
- const line = t.lines?.[0];
92
+ const line = matchedTransaction.lines?.[0];
93
93
  return line?.class?.className?.toLowerCase() ?? null;
94
94
  }
95
95
  case 'date':
96
- return t.date.valueOf();
96
+ return matchedTransaction.date.valueOf();
97
97
  case 'amount':
98
- return t.amount.amount;
98
+ return matchedTransaction.amount.amount;
99
99
  default:
100
100
  return null;
101
101
  }
102
102
  };
103
103
  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);
104
+ const matchedFiles = orderBy(resolvedFiles?.filter((resolvedFile) => resolvedFile.status === 'exact_match') ?? [], getSortValue, bulkUploadSortDirection);
105
+ const unmatchedFiles = orderBy(resolvedFiles?.filter((resolvedFile) => isUnmatchedTabFileStatus(resolvedFile.status)) ?? [], getSortValue, bulkUploadSortDirection);
106
106
  const progress = currentBatchStatus != null
107
107
  ? {
108
108
  ...currentBatchStatus.progress,
@@ -119,16 +119,16 @@ export function getExpenseAutomationMissingReceiptsView(state) {
119
119
  * that has details loaded (otherwise past is empty and receipts vanish from the UI).
120
120
  */
121
121
  const pastBatches = unmatchedSectionBatchId != null
122
- ? batchList.filter((b) => b.batchId !== unmatchedSectionBatchId)
122
+ ? batchList.filter((batchListItem) => batchListItem.batchId !== unmatchedSectionBatchId)
123
123
  : batchList;
124
- const pastUnmatchedFiles = pastBatches.flatMap((b) => {
125
- const details = bulkUpload.batchDetailsById[b.batchId];
124
+ const pastUnmatchedFiles = pastBatches.flatMap((pastBatch) => {
125
+ const details = bulkUpload.batchDetailsById[pastBatch.batchId];
126
126
  if (details == null) {
127
127
  return [];
128
128
  }
129
129
  return details.files
130
- .filter((f) => isUnmatchedTabFileStatus(f.status))
131
- .map((f) => resolveBatchFile(f, b.batchId, transactionState));
130
+ .filter((batchFile) => isUnmatchedTabFileStatus(batchFile.status))
131
+ .map((batchFile) => resolveBatchFile(batchFile, pastBatch.batchId, transactionState));
132
132
  });
133
133
  const completedTransactionsCacheKey = monthYearPeriodId != null
134
134
  ? getCompletedTransactionsCacheKey(monthYearPeriodId, bulkUpload.sortKey, bulkUpload.sortOrder, bulkUpload.completedSubTab)
@@ -147,11 +147,11 @@ export function getExpenseAutomationMissingReceiptsView(state) {
147
147
  summary: currentBatchDetails.summary,
148
148
  }
149
149
  : undefined;
150
- const manualSearchResults = bulkUpload.manualSearch.results.map((r) => {
151
- const t = getSupportedTransactionById(transactionState, r.transactionId);
150
+ const manualSearchResults = bulkUpload.manualSearch.results.map((result) => {
151
+ const transaction = getSupportedTransactionById(transactionState, result.transactionId);
152
152
  return {
153
- ...r,
154
- vendorLogo: r.vendorLogo ?? t?.logo?.href,
153
+ ...result,
154
+ vendorLogo: result.vendorLogo ?? transaction?.logo?.href,
155
155
  };
156
156
  });
157
157
  return {
@@ -201,7 +201,7 @@ export function getExpenseAutomationMissingReceiptsView(state) {
201
201
  };
202
202
  }
203
203
  function batchDetailsHasUnmatchedWork(details) {
204
- return details.files.some((f) => isUnmatchedTabFileStatus(f.status));
204
+ return details.files.some((file) => isUnmatchedTabFileStatus(file.status));
205
205
  }
206
206
  /** List row summary before batch details load — aligns with unmatched / possible-match work. */
207
207
  function batchListItemHasUnmatchedWork(batch) {
@@ -218,17 +218,17 @@ function batchListItemHasUnmatchedWork(batch) {
218
218
  */
219
219
  function getPrimaryBatchIdFromBatchListOrder(batchListInPlatformOrder, batchDetailsById, failedBatchDetailIds) {
220
220
  const failedIds = new Set(failedBatchDetailIds);
221
- const anyCompletedBatchHasUnmatchedWork = batchListInPlatformOrder.some((b) => {
222
- if (failedIds.has(b.batchId)) {
221
+ const anyCompletedBatchHasUnmatchedWork = batchListInPlatformOrder.some((batch) => {
222
+ if (failedIds.has(batch.batchId)) {
223
223
  return false;
224
224
  }
225
- const d = batchDetailsById[b.batchId];
226
- if (d != null &&
227
- d.status === 'completed' &&
228
- batchDetailsHasUnmatchedWork(d)) {
225
+ const details = batchDetailsById[batch.batchId];
226
+ if (details != null &&
227
+ details.status === 'completed' &&
228
+ batchDetailsHasUnmatchedWork(details)) {
229
229
  return true;
230
230
  }
231
- return d == null && batchListItemHasUnmatchedWork(b);
231
+ return details == null && batchListItemHasUnmatchedWork(batch);
232
232
  });
233
233
  for (const batch of batchListInPlatformOrder) {
234
234
  if (failedIds.has(batch.batchId)) {
@@ -265,7 +265,7 @@ function resolveBatchFile(file, batchId, transactionState) {
265
265
  ? { transaction, matchScore: ref.matchScore }
266
266
  : undefined;
267
267
  })
268
- .filter((c) => c != null);
268
+ .filter((candidate) => candidate != null);
269
269
  return {
270
270
  attachmentId: file.attachmentId,
271
271
  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, };