@zeniai/client-epic-state 4.19.84-betaVR9 → 4.19.85

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 (74) hide show
  1. package/lib/entity/account/accountPayload.d.ts +0 -2
  2. package/lib/entity/account/accountPayload.js +0 -2
  3. package/lib/entity/account/accountState.d.ts +0 -2
  4. package/lib/entity/snackbar/snackbarTypes.d.ts +1 -1
  5. package/lib/entity/snackbar/snackbarTypes.js +0 -1
  6. package/lib/epic.d.ts +1 -12
  7. package/lib/epic.js +1 -12
  8. package/lib/esm/entity/account/accountPayload.js +0 -2
  9. package/lib/esm/entity/snackbar/snackbarTypes.js +0 -1
  10. package/lib/esm/epic.js +1 -12
  11. package/lib/esm/index.js +3 -5
  12. package/lib/esm/view/expenseAutomationView/epics/missingReceipts/uploadMissingReceiptSuccessEpic.js +5 -7
  13. package/lib/esm/view/expenseAutomationView/payload/missingReceiptsPayload.js +1 -177
  14. package/lib/esm/view/expenseAutomationView/reducers/missingReceiptsViewReducer.js +1 -412
  15. package/lib/esm/view/expenseAutomationView/reducers/transactionsViewReducer.js +1 -20
  16. package/lib/esm/view/expenseAutomationView/selectors/missingReceiptsSelector.js +1 -224
  17. package/lib/esm/view/expenseAutomationView/selectors/transactionCategorizationSelector.js +1 -2
  18. package/lib/esm/view/expenseAutomationView/types/missingReceiptsViewState.js +0 -6
  19. package/lib/esm/view/expenseAutomationView/types/transactionsViewState.js +1 -2
  20. package/lib/esm/view/taskManager/taskDetailView/taskDetailSelector.js +1 -1
  21. package/lib/esm/zeniAPI.js +2 -0
  22. package/lib/index.d.ts +4 -6
  23. package/lib/index.js +31 -66
  24. package/lib/tsconfig.typecheck.tsbuildinfo +1 -1
  25. package/lib/view/expenseAutomationView/epics/missingReceipts/uploadMissingReceiptSuccessEpic.js +5 -7
  26. package/lib/view/expenseAutomationView/helpers/transactionCategorizationLocalDataHelper.d.ts +1 -1
  27. package/lib/view/expenseAutomationView/payload/missingReceiptsPayload.d.ts +0 -118
  28. package/lib/view/expenseAutomationView/payload/missingReceiptsPayload.js +0 -189
  29. package/lib/view/expenseAutomationView/reducers/missingReceiptsViewReducer.d.ts +3 -70
  30. package/lib/view/expenseAutomationView/reducers/missingReceiptsViewReducer.js +2 -414
  31. package/lib/view/expenseAutomationView/reducers/transactionsViewReducer.d.ts +3 -11
  32. package/lib/view/expenseAutomationView/reducers/transactionsViewReducer.js +2 -21
  33. package/lib/view/expenseAutomationView/selectorTypes/missingReceiptsSelectorTypes.d.ts +1 -69
  34. package/lib/view/expenseAutomationView/selectorTypes/transactionsViewSelectorTypes.d.ts +0 -1
  35. package/lib/view/expenseAutomationView/selectors/missingReceiptsSelector.d.ts +1 -1
  36. package/lib/view/expenseAutomationView/selectors/missingReceiptsSelector.js +0 -223
  37. package/lib/view/expenseAutomationView/selectors/transactionCategorizationSelector.js +1 -2
  38. package/lib/view/expenseAutomationView/types/missingReceiptsViewState.d.ts +0 -129
  39. package/lib/view/expenseAutomationView/types/missingReceiptsViewState.js +1 -7
  40. package/lib/view/expenseAutomationView/types/transactionsViewState.d.ts +1 -2
  41. package/lib/view/expenseAutomationView/types/transactionsViewState.js +1 -2
  42. package/lib/view/taskManager/taskDetailView/taskDetailSelector.js +1 -1
  43. package/lib/zeniAPI.js +2 -0
  44. package/package.json +1 -1
  45. package/lib/esm/view/expenseAutomationView/epics/missingReceipts/bulkUploadReceiptsEpic.js +0 -28
  46. package/lib/esm/view/expenseAutomationView/epics/missingReceipts/confirmBulkUploadMatchEpic.js +0 -49
  47. package/lib/esm/view/expenseAutomationView/epics/missingReceipts/fetchBulkUploadBatchDetailsEpic.js +0 -40
  48. package/lib/esm/view/expenseAutomationView/epics/missingReceipts/fetchBulkUploadBatchesEpic.js +0 -47
  49. package/lib/esm/view/expenseAutomationView/epics/missingReceipts/fetchCompletedTransactionsEpic.js +0 -61
  50. package/lib/esm/view/expenseAutomationView/epics/missingReceipts/fetchMoreBatchDetailsEpic.js +0 -34
  51. package/lib/esm/view/expenseAutomationView/epics/missingReceipts/fetchMultipleBatchDetailsEpic.js +0 -57
  52. package/lib/esm/view/expenseAutomationView/epics/missingReceipts/searchTransactionsForManualMatchEpic.js +0 -78
  53. package/lib/esm/view/expenseAutomationView/epics/missingReceipts/watchBulkUploadBatchStatusEpic.js +0 -59
  54. package/lib/esm/view/expenseAutomationView/epics/transactionCategorization/uploadTransactionReceiptSuccessEpic.js +0 -24
  55. package/lib/view/expenseAutomationView/epics/missingReceipts/bulkUploadReceiptsEpic.d.ts +0 -15
  56. package/lib/view/expenseAutomationView/epics/missingReceipts/bulkUploadReceiptsEpic.js +0 -32
  57. package/lib/view/expenseAutomationView/epics/missingReceipts/confirmBulkUploadMatchEpic.d.ts +0 -7
  58. package/lib/view/expenseAutomationView/epics/missingReceipts/confirmBulkUploadMatchEpic.js +0 -53
  59. package/lib/view/expenseAutomationView/epics/missingReceipts/fetchBulkUploadBatchDetailsEpic.d.ts +0 -8
  60. package/lib/view/expenseAutomationView/epics/missingReceipts/fetchBulkUploadBatchDetailsEpic.js +0 -44
  61. package/lib/view/expenseAutomationView/epics/missingReceipts/fetchBulkUploadBatchesEpic.d.ts +0 -7
  62. package/lib/view/expenseAutomationView/epics/missingReceipts/fetchBulkUploadBatchesEpic.js +0 -51
  63. package/lib/view/expenseAutomationView/epics/missingReceipts/fetchCompletedTransactionsEpic.d.ts +0 -8
  64. package/lib/view/expenseAutomationView/epics/missingReceipts/fetchCompletedTransactionsEpic.js +0 -65
  65. package/lib/view/expenseAutomationView/epics/missingReceipts/fetchMoreBatchDetailsEpic.d.ts +0 -8
  66. package/lib/view/expenseAutomationView/epics/missingReceipts/fetchMoreBatchDetailsEpic.js +0 -38
  67. package/lib/view/expenseAutomationView/epics/missingReceipts/fetchMultipleBatchDetailsEpic.d.ts +0 -9
  68. package/lib/view/expenseAutomationView/epics/missingReceipts/fetchMultipleBatchDetailsEpic.js +0 -62
  69. package/lib/view/expenseAutomationView/epics/missingReceipts/searchTransactionsForManualMatchEpic.d.ts +0 -14
  70. package/lib/view/expenseAutomationView/epics/missingReceipts/searchTransactionsForManualMatchEpic.js +0 -82
  71. package/lib/view/expenseAutomationView/epics/missingReceipts/watchBulkUploadBatchStatusEpic.d.ts +0 -19
  72. package/lib/view/expenseAutomationView/epics/missingReceipts/watchBulkUploadBatchStatusEpic.js +0 -64
  73. package/lib/view/expenseAutomationView/epics/transactionCategorization/uploadTransactionReceiptSuccessEpic.d.ts +0 -7
  74. package/lib/view/expenseAutomationView/epics/transactionCategorization/uploadTransactionReceiptSuccessEpic.js +0 -28
@@ -9,8 +9,6 @@ const timePeriod_1 = require("../../../commonStateTypes/timePeriod");
9
9
  const tenantSelector_1 = require("../../../entity/tenant/tenantSelector");
10
10
  const transactionSelector_1 = require("../../../entity/transaction/transactionSelector");
11
11
  const expenseAutomationViewSelectorTypes_1 = require("../selectorTypes/expenseAutomationViewSelectorTypes");
12
- const missingReceiptsPayload_1 = require("../payload/missingReceiptsPayload");
13
- const missingReceiptsViewReducer_1 = require("../reducers/missingReceiptsViewReducer");
14
12
  function getExpenseAutomationMissingReceiptsView(state) {
15
13
  const { expenseAutomationMissingReceiptsViewState, expenseAutomationViewState, transactionState, monthEndCloseChecksState, } = state;
16
14
  const currentTenant = (0, tenantSelector_1.getCurrentTenant)(state);
@@ -55,110 +53,6 @@ function getExpenseAutomationMissingReceiptsView(state) {
55
53
  const completionStatus = missingReceiptsCompletionStatus != null
56
54
  ? missingReceiptsCompletionStatus
57
55
  : 'incomplete';
58
- const { bulkUpload, pendingMissingReceiptsTabNavigation, } = expenseAutomationMissingReceiptsViewState;
59
- const currentBatchStatus = bulkUpload.currentBatchId != null
60
- ? bulkUpload.batchStatusById[bulkUpload.currentBatchId]
61
- : undefined;
62
- const batchList = monthYearPeriodId != null
63
- ? bulkUpload.batchListByPeriod[monthYearPeriodId] ?? []
64
- : [];
65
- /**
66
- * Primary "Unmatched" batch = first completed batch in platform list order, preferring the
67
- * first batch that still has un_matched/no_match work when any completed batch has such work.
68
- * Batches without details yet: wait if the list row still reports unmatched work; otherwise skip
69
- * so we do not block the whole tab while other rows are not fetched yet.
70
- */
71
- const primaryBatchIdFromDetailsOrder = getPrimaryBatchIdFromBatchListOrder(batchList, bulkUpload.batchDetailsById, bulkUpload.failedBatchDetailIds);
72
- /** During upload/matching, the in-flight batch may not appear in batchList yet — prefer currentBatchId. */
73
- const unmatchedSectionBatchId = bulkUpload.phase === 'matching' || bulkUpload.phase === 'uploading'
74
- ? bulkUpload.currentBatchId ?? primaryBatchIdFromDetailsOrder
75
- : primaryBatchIdFromDetailsOrder;
76
- const completedBatchesInApiOrder = batchList.filter((b) => (0, missingReceiptsPayload_1.isBatchListStatusCompleted)(b.status));
77
- const currentBatchDetails = unmatchedSectionBatchId != null
78
- ? bulkUpload.batchDetailsById[unmatchedSectionBatchId]
79
- : undefined;
80
- const resolvedFiles = currentBatchDetails?.files.map((file) => resolveBatchFile(file, currentBatchDetails.batchId, transactionState));
81
- const failedIds = new Set(bulkUpload.failedBatchDetailIds);
82
- const hasMoreBatchDetails = completedBatchesInApiOrder.some((b) => bulkUpload.batchDetailsById[b.batchId] == null &&
83
- !failedIds.has(b.batchId));
84
- const getSortValue = (file) => {
85
- const t = file.matchedTransaction;
86
- if (t == null) {
87
- return null;
88
- }
89
- switch (bulkUpload.sortKey) {
90
- case 'vendor':
91
- return (t.vendorName ?? t.description)?.toLowerCase() ?? null;
92
- case 'category': {
93
- const line = t.lines?.[0];
94
- return line?.account?.accountName?.toLowerCase() ?? null;
95
- }
96
- case 'class': {
97
- const line = t.lines?.[0];
98
- return line?.class?.className?.toLowerCase() ?? null;
99
- }
100
- case 'date':
101
- return t.date.valueOf();
102
- case 'amount':
103
- return t.amount.amount;
104
- default:
105
- return null;
106
- }
107
- };
108
- const bulkUploadSortDirection = bulkUpload.sortOrder === 'ascending' ? 'asc' : 'desc';
109
- const matchedFiles = (0, orderBy_1.default)(resolvedFiles?.filter((f) => f.status === 'matched') ?? [], getSortValue, bulkUploadSortDirection);
110
- const unmatchedFiles = (0, orderBy_1.default)(resolvedFiles?.filter((f) => f.status === 'un_matched' || f.status === 'no_match') ?? [], getSortValue, bulkUploadSortDirection);
111
- const progress = currentBatchStatus != null
112
- ? {
113
- ...currentBatchStatus.progress,
114
- percentage: currentBatchStatus.progress.total > 0
115
- ? Math.round((currentBatchStatus.progress.processed /
116
- currentBatchStatus.progress.total) *
117
- 100)
118
- : 0,
119
- }
120
- : { total: 0, processed: 0, percentage: 0 };
121
- const batchListFetchState = bulkUpload.batchListFetchState;
122
- /**
123
- * When primary batch is not resolved yet, still aggregate unmatched files from every batch
124
- * that has details loaded (otherwise past is empty and receipts vanish from the UI).
125
- */
126
- const pastBatches = unmatchedSectionBatchId != null
127
- ? batchList.filter((b) => b.batchId !== unmatchedSectionBatchId)
128
- : batchList;
129
- const pastUnmatchedFiles = pastBatches.flatMap((b) => {
130
- const details = bulkUpload.batchDetailsById[b.batchId];
131
- if (details == null) {
132
- return [];
133
- }
134
- return details.files
135
- .filter((f) => f.status === 'un_matched' || f.status === 'no_match')
136
- .map((f) => resolveBatchFile(f, b.batchId, transactionState));
137
- });
138
- const completedTransactionsCacheKey = monthYearPeriodId != null
139
- ? (0, missingReceiptsViewReducer_1.getCompletedTransactionsCacheKey)(monthYearPeriodId, bulkUpload.sortKey, bulkUpload.sortOrder, bulkUpload.completedSubTab)
140
- : undefined;
141
- const completedTransactionsForPeriod = completedTransactionsCacheKey != null
142
- ? bulkUpload.completedTransactionsByPeriod[completedTransactionsCacheKey]
143
- : undefined;
144
- const completedTransactionIds = completedTransactionsForPeriod?.transactionIds ?? [];
145
- const resolvedCompletedTransactions = (0, transactionSelector_1.getSupportedTransactionsByIds)(transactionState, completedTransactionIds);
146
- const resolvedBatchDetails = currentBatchDetails != null && resolvedFiles != null
147
- ? {
148
- batchId: currentBatchDetails.batchId,
149
- createdAt: currentBatchDetails.createdAt,
150
- files: resolvedFiles,
151
- status: currentBatchDetails.status,
152
- summary: currentBatchDetails.summary,
153
- }
154
- : undefined;
155
- const manualSearchResults = bulkUpload.manualSearch.results.map((r) => {
156
- const t = (0, transactionSelector_1.getSupportedTransactionById)(transactionState, r.transactionId);
157
- return {
158
- ...r,
159
- vendorLogo: r.vendorLogo ?? t?.logo?.href,
160
- };
161
- });
162
56
  return {
163
57
  fetchState,
164
58
  error,
@@ -167,122 +61,5 @@ function getExpenseAutomationMissingReceiptsView(state) {
167
61
  refreshStatus,
168
62
  transactions: sortedTransactions,
169
63
  completionStatus,
170
- pendingMissingReceiptsTabNavigation: pendingMissingReceiptsTabNavigation ?? null,
171
- bulkUpload: {
172
- phase: bulkUpload.phase,
173
- uploadStatus: bulkUpload.uploadStatus,
174
- batchStatus: currentBatchStatus,
175
- batchDetails: resolvedBatchDetails,
176
- completedSubTab: bulkUpload.completedSubTab,
177
- completedTransactions: {
178
- fetchState: completedTransactionsForPeriod?.fetchState ?? {
179
- fetchState: 'Not-Started',
180
- error: undefined,
181
- },
182
- nextPageToken: completedTransactionsForPeriod?.nextPageToken ?? null,
183
- totalCount: completedTransactionsForPeriod?.totalCount ?? 0,
184
- transactions: resolvedCompletedTransactions,
185
- },
186
- matchedFiles,
187
- unmatchedFiles,
188
- progress,
189
- currentResultsTab: bulkUpload.currentResultsTab,
190
- sortKey: bulkUpload.sortKey,
191
- sortOrder: bulkUpload.sortOrder,
192
- batchList,
193
- batchListFetchState,
194
- pastBatches,
195
- pastUnmatchedFiles,
196
- confirmMatchStatus: bulkUpload.confirmMatchStatus,
197
- manualSearchUiResetKey: bulkUpload.manualSearchUiResetKey,
198
- hasMoreBatchDetails,
199
- batchDetailsPaginationState: bulkUpload.batchDetailsPaginationState,
200
- manualSearch: {
201
- ...bulkUpload.manualSearch,
202
- results: manualSearchResults,
203
- },
204
- uploadProgress: bulkUpload.uploadProgress,
205
- },
206
- };
207
- }
208
- function batchDetailsHasUnmatchedWork(details) {
209
- return details.files.some((f) => f.status === 'un_matched' || f.status === 'no_match');
210
- }
211
- /** List row summary before batch details load — aligns with unmatched / possible-match work. */
212
- function batchListItemHasUnmatchedWork(batch) {
213
- return batch.noMatchCount > 0 || batch.possibleMatchesCount > 0;
214
- }
215
- /**
216
- * `batchList` must match platform order (same sequence as the bulk-upload batches API). Picks the
217
- * primary batch for the top "Unmatched" section. Skips failed detail fetches.
218
- *
219
- * If details are not loaded for an earlier list row but that row reports no unmatched work, we
220
- * skip it so later rows with loaded details can be primary (avoids an empty tab when the first
221
- * fetch page only loaded later batches). If the list reports unmatched work but details are still
222
- * loading, we wait (undefined) so primary order stays correct once details arrive.
223
- */
224
- function getPrimaryBatchIdFromBatchListOrder(batchListInPlatformOrder, batchDetailsById, failedBatchDetailIds) {
225
- const failedIds = new Set(failedBatchDetailIds);
226
- const anyCompletedBatchHasUnmatchedWork = batchListInPlatformOrder.some((b) => {
227
- if (failedIds.has(b.batchId)) {
228
- return false;
229
- }
230
- const d = batchDetailsById[b.batchId];
231
- if (d != null &&
232
- d.status === 'completed' &&
233
- batchDetailsHasUnmatchedWork(d)) {
234
- return true;
235
- }
236
- return d == null && batchListItemHasUnmatchedWork(b);
237
- });
238
- for (const batch of batchListInPlatformOrder) {
239
- if (failedIds.has(batch.batchId)) {
240
- continue;
241
- }
242
- const details = batchDetailsById[batch.batchId];
243
- if (details == null) {
244
- if (batchListItemHasUnmatchedWork(batch)) {
245
- return undefined;
246
- }
247
- continue;
248
- }
249
- if (details.status !== 'completed') {
250
- continue;
251
- }
252
- if (anyCompletedBatchHasUnmatchedWork) {
253
- if (batchDetailsHasUnmatchedWork(details)) {
254
- return batch.batchId;
255
- }
256
- continue;
257
- }
258
- return batch.batchId;
259
- }
260
- return undefined;
261
- }
262
- function resolveBatchFile(file, batchId, transactionState) {
263
- const matchedTransaction = file.matchedTransactionId != null
264
- ? (0, transactionSelector_1.getSupportedTransactionById)(transactionState, file.matchedTransactionId)
265
- : undefined;
266
- const candidates = file.candidates
267
- ?.map((ref) => {
268
- const transaction = (0, transactionSelector_1.getSupportedTransactionById)(transactionState, ref.transactionId);
269
- return transaction != null
270
- ? { transaction, matchScore: ref.matchScore }
271
- : undefined;
272
- })
273
- .filter((c) => c != null);
274
- return {
275
- attachmentId: file.attachmentId,
276
- batchId,
277
- fileDownloadUrl: file.fileDownloadUrl,
278
- fileId: file.fileId,
279
- filename: file.filename,
280
- filePreviewUrl: file.filePreviewUrl,
281
- status: file.status,
282
- matchedTransaction,
283
- candidates: candidates != null && candidates.length > 0
284
- ? candidates
285
- : undefined,
286
- matchSource: file.matchSource,
287
64
  };
288
65
  }
@@ -16,7 +16,7 @@ const expenseAutomationViewSelectorTypes_1 = require("../selectorTypes/expenseAu
16
16
  function getExpenseAutomationTransactionView(state) {
17
17
  const { accountState, classState, classListState, accountListState, expenseAutomationTransactionsViewState, expenseAutomationViewState, transactionState, monthEndCloseChecksState, } = state;
18
18
  const { selectedTransactionCategorizationTab } = expenseAutomationTransactionsViewState;
19
- const { uiState, refreshStatus, saveStatus, markAsNotMiscategorizedStatus, transactionIdsBySelectedPeriod, transactionReviewLocalDataById, selectedCheckBoxTransactionIds, transactionIdsWithUnsavedData, uploadReceiptStatusById, selectedTransactionId, selectedTransactionLineId, } = expenseAutomationTransactionsViewState.transactionCategorizationView[selectedTransactionCategorizationTab];
19
+ const { uiState, refreshStatus, saveStatus, markAsNotMiscategorizedStatus, transactionIdsBySelectedPeriod, transactionReviewLocalDataById, selectedCheckBoxTransactionIds, transactionIdsWithUnsavedData, selectedTransactionId, selectedTransactionLineId, } = expenseAutomationTransactionsViewState.transactionCategorizationView[selectedTransactionCategorizationTab];
20
20
  const uncategorizedIncomeExpense = (0, accountListSelector_1.getUncategorizedAccounts)(accountState, accountListState, 'accountList');
21
21
  const accountList = (0, accountListSelector_1.getAccountList)(accountState, accountListState, 'accountList');
22
22
  const classList = (0, classListSelector_1.getClassList)(classState, classListState);
@@ -100,7 +100,6 @@ function getExpenseAutomationTransactionView(state) {
100
100
  completionStatus,
101
101
  totalCountByTab,
102
102
  fetchStateByTransactionTabs: fetchStateByTab,
103
- uploadReceiptStatusById,
104
103
  selectedTransactionId,
105
104
  selectedTransactionLineId,
106
105
  };
@@ -3,7 +3,6 @@ import { SortOrder } from '../../../commonStateTypes/selectorTypes/sortOrderType
3
3
  import { MonthYearPeriodId } from '../../../commonStateTypes/timePeriod';
4
4
  export declare const toMissingReceiptsSortKey: (v: string) => "date" | "amount" | "vendor" | "category" | "class";
5
5
  export type MissingReceiptsSortKey = ReturnType<typeof toMissingReceiptsSortKey>;
6
- export type BulkUploadSortKey = 'amount' | 'category' | 'class' | 'date' | 'vendor';
7
6
  export interface MissingReceiptsViewUIState {
8
7
  scrollPosition: {
9
8
  scrollTop: number;
@@ -13,135 +12,7 @@ export interface MissingReceiptsViewUIState {
13
12
  sortKey: MissingReceiptsSortKey;
14
13
  sortOrder: SortOrder;
15
14
  }
16
- /**
17
- * Minimum trimmed query length before manual-match search calls the expense-automation API.
18
- * Kept in sync with `ManualSearchInput` in web-components (fires search only when length ≥ this).
19
- */
20
- export declare const MIN_MANUAL_TRANSACTION_SEARCH_LENGTH = 2;
21
- export type BatchStatusValue = 'pending' | 'processing' | 'completed';
22
- export type BatchFileStatus = 'matched' | 'un_matched' | 'no_match' | 'failed';
23
- export type BulkUploadPhase = 'idle' | 'uploading' | 'matching' | 'completed';
24
- export type BulkUploadResultsTab = 'completed' | 'unmatched';
25
- export type MissingReceiptsTab = 'missing' | BulkUploadResultsTab;
26
- export type CompletedSubTab = 'all' | 'ai_accountant' | 'manual';
27
- export type MatchSource = 'ai' | 'manual';
28
- export interface CandidateRef {
29
- matchScore: number;
30
- transactionId: ID;
31
- }
32
- export interface MatchCandidate {
33
- amount: number;
34
- currencyCode: string;
35
- matchScore: number;
36
- transactionDate: string;
37
- transactionId: ID;
38
- transactionType: string;
39
- vendorName: string;
40
- vendorLogo?: string;
41
- }
42
- export interface BatchFile {
43
- attachmentId: ID;
44
- fileDownloadUrl: string | null;
45
- fileId: ID;
46
- filename: string;
47
- filePreviewUrl: string | null;
48
- status: BatchFileStatus;
49
- candidates?: CandidateRef[];
50
- matchedTransactionId?: ID;
51
- matchSource?: MatchSource;
52
- }
53
- export interface BatchSummary {
54
- failed: number;
55
- matched: number;
56
- noMatch: number;
57
- possibleMatches: number;
58
- total: number;
59
- }
60
- export interface BatchStatus {
61
- batchId: ID;
62
- progress: {
63
- processed: number;
64
- total: number;
65
- };
66
- status: BatchStatusValue;
67
- }
68
- export interface BatchDetails {
69
- batchId: ID;
70
- createdAt: string;
71
- files: BatchFile[];
72
- status: BatchStatusValue;
73
- summary: BatchSummary;
74
- }
75
- export interface BatchListItem {
76
- batchId: ID;
77
- createdAt: string;
78
- failedCount: number;
79
- matchedCount: number;
80
- noMatchCount: number;
81
- possibleMatchesCount: number;
82
- status: string;
83
- totalFiles: number;
84
- }
85
- export interface ManualSearchResult {
86
- amount: number;
87
- currencyCode: string;
88
- entityId: string;
89
- memo: string;
90
- transactionDate: string;
91
- transactionId: ID;
92
- transactionType: string;
93
- vendorName: string;
94
- /** Present when API/merged transaction state supplies a logo URL. */
95
- vendorLogo?: string;
96
- }
97
- export interface ManualSearchState {
98
- fetchState: FetchStateAndError;
99
- /** True while appending the next page (initial search uses fetchState only). */
100
- isLoadingMore: boolean;
101
- nextPageToken: string | null;
102
- pageSize: number;
103
- results: ManualSearchResult[];
104
- searchQuery: string;
105
- totalCount: number;
106
- }
107
- export type CompletedTransactionsMatchType = 'all' | 'ai_accountant' | 'manual';
108
- export interface CompletedTransactionsState {
109
- fetchState: FetchStateAndError;
110
- nextPageToken: string | null;
111
- totalCount: number;
112
- transactionIds: ID[];
113
- }
114
- export interface BulkUploadState {
115
- batchDetailsById: Record<ID, BatchDetails>;
116
- batchDetailsPaginationState: FetchStateAndError;
117
- batchListByPeriod: Record<MonthYearPeriodId, BatchListItem[]>;
118
- batchListFetchState: FetchStateAndError;
119
- batchStatusById: Record<ID, BatchStatus>;
120
- completedSubTab: CompletedSubTab;
121
- completedTransactionsByPeriod: Record<string, CompletedTransactionsState>;
122
- confirmMatchStatus: FetchStateAndError;
123
- currentResultsTab: BulkUploadResultsTab;
124
- failedBatchDetailIds: ID[];
125
- /**
126
- * Incremented when manual search Redux state is cleared so Unmatched `ManualSearchInput`
127
- * instances remount and drop local query text.
128
- */
129
- manualSearch: ManualSearchState;
130
- manualSearchUiResetKey: number;
131
- phase: BulkUploadPhase;
132
- sortKey: BulkUploadSortKey;
133
- sortOrder: SortOrder;
134
- uploadProgress: number;
135
- uploadStatus: FetchStateAndError;
136
- currentBatchId?: ID;
137
- }
138
15
  export interface MissingReceiptsViewState extends FetchedState {
139
- bulkUpload: BulkUploadState;
140
- /**
141
- * When set, the app shell should switch the Missing Receipts sub-tab (e.g. to Unmatched)
142
- * once, then clear via `clearMissingReceiptsTabNavigation`.
143
- */
144
- pendingMissingReceiptsTabNavigation: BulkUploadResultsTab | null;
145
16
  refreshStatus: FetchStateAndError;
146
17
  transactionIdsBySelectedPeriod: Record<MonthYearPeriodId, ID[]>;
147
18
  uiState: MissingReceiptsViewUIState;
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.MIN_MANUAL_TRANSACTION_SEARCH_LENGTH = exports.toMissingReceiptsSortKey = void 0;
3
+ exports.toMissingReceiptsSortKey = void 0;
4
4
  const stringToUnion_1 = require("../../../commonStateTypes/stringToUnion");
5
5
  const MISSING_RECEIPTS_SORT_KEYS = [
6
6
  'vendor',
@@ -11,9 +11,3 @@ const MISSING_RECEIPTS_SORT_KEYS = [
11
11
  ];
12
12
  const toMissingReceiptsSortKey = (v) => (0, stringToUnion_1.stringToUnion)(v, MISSING_RECEIPTS_SORT_KEYS);
13
13
  exports.toMissingReceiptsSortKey = toMissingReceiptsSortKey;
14
- // -- Bulk Receipt Upload Types --
15
- /**
16
- * Minimum trimmed query length before manual-match search calls the expense-automation API.
17
- * Kept in sync with `ManualSearchInput` in web-components (fires search only when length ≥ this).
18
- */
19
- exports.MIN_MANUAL_TRANSACTION_SEARCH_LENGTH = 2;
@@ -15,7 +15,7 @@ import { VendorBase } from '../../../entity/vendor/vendorState';
15
15
  import { ZeniDate } from '../../../zeniDayJS';
16
16
  import { EntityRecommendationKey } from '../../recommendation/recommendationState';
17
17
  import { TransactionDetailKey } from '../../transactionDetail/transactionDetailState';
18
- export declare const toTransactionsSortKey: (v: string) => "date" | "amount" | "vendor" | "category" | "class" | "payment_account" | "transaction_type" | "memo_and_receipt";
18
+ export declare const toTransactionsSortKey: (v: string) => "date" | "amount" | "vendor" | "category" | "class" | "memo" | "transaction_type";
19
19
  export type TransactionsSortKey = ReturnType<typeof toTransactionsSortKey>;
20
20
  export declare const TRANSACTIONS_TABS: readonly ["review", "autoCategorized"];
21
21
  export declare const toTransactionsTabKey: (v: string) => "review" | "autoCategorized";
@@ -97,7 +97,6 @@ export interface TransactionsTabViewState extends FetchedState {
97
97
  transactionIdsWithUnsavedData: ID[];
98
98
  transactionReviewLocalDataById: Record<ID | TransactionDetailKey, SupportedTransactionCategorization>;
99
99
  uiState: TransactionsViewUIState;
100
- uploadReceiptStatusById: Record<ID, FetchStateAndError>;
101
100
  selectedTransactionId?: ID;
102
101
  selectedTransactionLineId?: ID;
103
102
  }
@@ -7,11 +7,10 @@ const TRANSACTIONS_SORT_KEYS = [
7
7
  'vendor',
8
8
  'amount',
9
9
  'transaction_type',
10
- 'payment_account',
11
10
  'date',
12
11
  'category',
13
12
  'class',
14
- 'memo_and_receipt',
13
+ 'memo',
15
14
  ];
16
15
  const toTransactionsSortKey = (v) => (0, stringToUnion_1.stringToUnion)(v, TRANSACTIONS_SORT_KEYS);
17
16
  exports.toTransactionsSortKey = toTransactionsSortKey;
@@ -116,7 +116,7 @@ exports.allTaskPriority = [
116
116
  },
117
117
  {
118
118
  code: 'medium',
119
- name: 'Medium',
119
+ name: 'Normal',
120
120
  },
121
121
  {
122
122
  code: 'low',
package/lib/zeniAPI.js CHANGED
@@ -82,6 +82,8 @@ class ZeniAPIClient {
82
82
  return (0, rxjs_1.from)(promise);
83
83
  }
84
84
  postFormData(restEndPoint, formData, signal) {
85
+ // Use apiHeaders for auth headers, then remove Content-Type
86
+ // so the browser sets multipart/form-data with the correct boundary
85
87
  // eslint-disable-next-line @typescript-eslint/no-unused-vars
86
88
  const { 'Content-Type': _contentType, ...headers } = this.apiHeaders();
87
89
  const promise = (0, cross_fetch_1.fetch)(restEndPoint, {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zeniai/client-epic-state",
3
- "version": "4.19.84-betaVR9",
3
+ "version": "4.19.85",
4
4
  "description": "Shared module between Web & Mobile containing required abstractions for state management, async network communication. ",
5
5
  "main": "lib/index.js",
6
6
  "module": "lib/esm/index.js",
@@ -1,28 +0,0 @@
1
- import { of } from 'rxjs';
2
- import { catchError, filter, mergeMap } from 'rxjs/operators';
3
- import { createZeniAPIStatus, isSuccessResponse, } from '../../../../responsePayload';
4
- import { bulkUploadReceipts, bulkUploadReceiptsFailure, bulkUploadReceiptsSuccess, } from '../../reducers/missingReceiptsViewReducer';
5
- export const bulkUploadReceiptsEpic = (actions$, _state$, zeniAPI) => actions$.pipe(filter(bulkUploadReceipts.match), mergeMap((action) => {
6
- const { files } = action.payload;
7
- const formData = new FormData();
8
- for (const file of files) {
9
- formData.append('files', file, file.name);
10
- }
11
- return zeniAPI
12
- .postFormData(`${zeniAPI.apiEndPoints.communicationAgentMicroServiceBaseUrl}/1.0/receipts/bulk-upload`, formData)
13
- .pipe(mergeMap((response) => {
14
- if (isSuccessResponse(response) && response.data != null) {
15
- const batchId = String(response.data.batch_id ?? '').trim();
16
- if (batchId === '') {
17
- return of(bulkUploadReceiptsFailure({
18
- error: createZeniAPIStatus('Unexpected Error', 'Bulk upload succeeded but batch_id was missing or empty.'),
19
- }));
20
- }
21
- return of(bulkUploadReceiptsSuccess({ batchId }));
22
- }
23
- return of(bulkUploadReceiptsFailure({ error: response.status }));
24
- }), catchError((error) => of(bulkUploadReceiptsFailure({
25
- error: createZeniAPIStatus('Unexpected Error', 'Bulk upload receipts API call errored out: ' +
26
- JSON.stringify(error)),
27
- }))));
28
- }));
@@ -1,49 +0,0 @@
1
- import { from } from 'rxjs';
2
- import { catchError, exhaustMap, filter, mergeMap } from 'rxjs/operators';
3
- import { openSnackbar } from '../../../../entity/snackbar/snackbarReducer';
4
- import { createZeniAPIStatus, isSuccessResponse, } from '../../../../responsePayload';
5
- import { confirmBulkUploadMatch, confirmBulkUploadMatchFailure, confirmBulkUploadMatchSuccess, } from '../../reducers/missingReceiptsViewReducer';
6
- export const confirmBulkUploadMatchEpic = (actions$, _state$, zeniAPI) => actions$.pipe(filter(confirmBulkUploadMatch.match), exhaustMap((action) => {
7
- const { batchId, attachmentId, transactionId, transactionType, fileName } = action.payload;
8
- return zeniAPI
9
- .postAndGetJSON(`${zeniAPI.apiEndPoints.communicationAgentMicroServiceBaseUrl}/1.0/receipts/manual-match`, {
10
- attachment_id: attachmentId,
11
- transaction_id: transactionId,
12
- transaction_type: transactionType,
13
- file_name: fileName,
14
- })
15
- .pipe(mergeMap((response) => {
16
- if (isSuccessResponse(response)) {
17
- return from([
18
- confirmBulkUploadMatchSuccess({
19
- batchId,
20
- attachmentId,
21
- transactionId,
22
- }),
23
- openSnackbar({
24
- messageSection: 'receipt_match',
25
- messageText: 'success',
26
- type: 'success',
27
- }),
28
- ]);
29
- }
30
- return from([
31
- confirmBulkUploadMatchFailure({ error: response.status }),
32
- openSnackbar({
33
- messageSection: 'receipt_match',
34
- messageText: 'failed',
35
- type: 'error',
36
- }),
37
- ]);
38
- }), catchError((error) => from([
39
- confirmBulkUploadMatchFailure({
40
- error: createZeniAPIStatus('Unexpected Error', 'Confirm bulk upload match errored out: ' +
41
- JSON.stringify(error)),
42
- }),
43
- openSnackbar({
44
- messageSection: 'receipt_match',
45
- messageText: 'failed',
46
- type: 'error',
47
- }),
48
- ])));
49
- }));
@@ -1,40 +0,0 @@
1
- import { EMPTY, from, of } from 'rxjs';
2
- import { catchError, filter, mergeMap } from 'rxjs/operators';
3
- import { updateTransactions } from '../../../../entity/transaction/transactionReducer';
4
- import { createZeniAPIStatus, isSuccessResponse, } from '../../../../responsePayload';
5
- import { extractTransactionPayloadsFromBatchFiles, isBatchDetailsApiStatusCompleted, shouldFetchBatchDetailsForBatchId, toBatchDetails, } from '../../payload/missingReceiptsPayload';
6
- import { fetchBulkUploadBatchDetails, fetchBulkUploadBatchDetailsFailure, fetchBulkUploadBatchDetailsSuccess, fetchBulkUploadBatches, } from '../../reducers/missingReceiptsViewReducer';
7
- export const fetchBulkUploadBatchDetailsEpic = (actions$, state$, zeniAPI) => actions$.pipe(filter(fetchBulkUploadBatchDetails.match), mergeMap(() => {
8
- const bulkUpload = state$.value.expenseAutomationMissingReceiptsViewState.bulkUpload;
9
- const { currentBatchId } = bulkUpload;
10
- if (currentBatchId == null) {
11
- return of(fetchBulkUploadBatchDetailsFailure({
12
- error: createZeniAPIStatus('Unexpected Error', 'No current batch ID available'),
13
- }));
14
- }
15
- if (!shouldFetchBatchDetailsForBatchId(bulkUpload.batchStatusById, bulkUpload.batchListByPeriod, currentBatchId)) {
16
- return EMPTY;
17
- }
18
- return zeniAPI
19
- .getJSON(`${zeniAPI.apiEndPoints.communicationAgentMicroServiceBaseUrl}/1.0/batches/${currentBatchId}`)
20
- .pipe(mergeMap((response) => {
21
- if (!isSuccessResponse(response) ||
22
- response.data == null ||
23
- !isBatchDetailsApiStatusCompleted(response.data.status)) {
24
- if (isSuccessResponse(response) && response.data != null) {
25
- return EMPTY;
26
- }
27
- return of(fetchBulkUploadBatchDetailsFailure({ error: response.status }));
28
- }
29
- const actions = [];
30
- const transactionPayloads = extractTransactionPayloadsFromBatchFiles(response.data.files);
31
- if (transactionPayloads.length > 0) {
32
- actions.push(updateTransactions(transactionPayloads, (value) => value.transaction_id));
33
- }
34
- actions.push(fetchBulkUploadBatchDetailsSuccess(toBatchDetails(response.data, zeniAPI.apiEndPoints.fileMicroServiceBaseUrl)));
35
- actions.push(fetchBulkUploadBatches({ cacheOverride: true }));
36
- return from(actions);
37
- }), catchError((error) => of(fetchBulkUploadBatchDetailsFailure({
38
- error: createZeniAPIStatus('Unexpected Error', 'Fetch batch details errored out: ' + JSON.stringify(error)),
39
- }))));
40
- }));
@@ -1,47 +0,0 @@
1
- import { of } from 'rxjs';
2
- import { catchError, filter, mergeMap, switchMap } from 'rxjs/operators';
3
- import { convertToPeriod, toMonthYearPeriodId, } from '../../../../commonStateTypes/timePeriod';
4
- import { getCurrentTenant } from '../../../../entity/tenant/tenantSelector';
5
- import { createZeniAPIStatus, isSuccessResponse, } from '../../../../responsePayload';
6
- import { toBatchListItem, } from '../../payload/missingReceiptsPayload';
7
- import { fetchBulkUploadBatches, fetchBulkUploadBatchesFailure, fetchBulkUploadBatchesSuccess, } from '../../reducers/missingReceiptsViewReducer';
8
- export const fetchBulkUploadBatchesEpic = (actions$, state$, zeniAPI) => actions$.pipe(filter(fetchBulkUploadBatches.match), switchMap((action) => {
9
- const { cacheOverride } = action.payload;
10
- const state = state$.value;
11
- const { expenseAutomationViewState: { selectedPeriodByTenantId }, expenseAutomationMissingReceiptsViewState: { bulkUpload }, } = state;
12
- const currentTenant = getCurrentTenant(state);
13
- const selectedPeriod = selectedPeriodByTenantId[currentTenant.tenantId];
14
- const periodId = toMonthYearPeriodId(selectedPeriod);
15
- const existingBatches = bulkUpload.batchListByPeriod[periodId] ?? [];
16
- if (cacheOverride !== true && existingBatches.length > 0) {
17
- return of(fetchBulkUploadBatchesSuccess({
18
- batchList: existingBatches,
19
- selectedPeriod,
20
- }));
21
- }
22
- const period = convertToPeriod(selectedPeriod);
23
- const queryParam = {
24
- start_date: period.start,
25
- end_date: period.end,
26
- sort_order: 'desc',
27
- };
28
- return zeniAPI
29
- .getJSON(`${zeniAPI.apiEndPoints.communicationAgentMicroServiceBaseUrl}/1.0/batches?query=${encodeURIComponent(JSON.stringify(queryParam))}`)
30
- .pipe(mergeMap((response) => {
31
- if (isSuccessResponse(response) && response.data != null) {
32
- /** Full list (all statuses) for UI; batch-details epics filter to `completed` only. */
33
- return of(fetchBulkUploadBatchesSuccess({
34
- batchList: response.data.batches.map(toBatchListItem),
35
- selectedPeriod,
36
- }));
37
- }
38
- return of(fetchBulkUploadBatchesFailure({
39
- error: response.status,
40
- selectedPeriod,
41
- }));
42
- }), catchError((error) => of(fetchBulkUploadBatchesFailure({
43
- error: createZeniAPIStatus('Unexpected Error', 'Fetch bulk upload batches errored out: ' +
44
- JSON.stringify(error)),
45
- selectedPeriod,
46
- }))));
47
- }));