@zeniai/client-epic-state 5.0.71-betaML41 → 5.0.71-betaVR2
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.
- package/lib/epic.d.ts +3 -2
- package/lib/epic.js +3 -2
- package/lib/esm/epic.js +3 -2
- package/lib/esm/index.js +8 -8
- package/lib/esm/view/expenseAutomationView/epics/missingReceipts/fetchMultipleBatchDetailsEpic.js +21 -5
- package/lib/esm/view/expenseAutomationView/epics/missingReceipts/refreshBatchDetailsForBatchIdEpic.js +52 -0
- package/lib/esm/view/expenseAutomationView/epics/missingReceipts/syncTabsAfterAutomatchEpic.js +53 -0
- package/lib/esm/view/expenseAutomationView/epics/missingReceipts/watchBulkUploadBatchStatusEpic.js +13 -9
- package/lib/esm/view/expenseAutomationView/helpers/transactionCategorizationLocalDataHelper.js +1 -21
- package/lib/esm/view/expenseAutomationView/reducers/missingReceiptsViewReducer.js +78 -3
- package/lib/esm/view/expenseAutomationView/reducers/transactionsViewReducer.js +14 -117
- package/lib/esm/view/expenseAutomationView/selectors/missingReceiptsSelector.js +2 -0
- package/lib/esm/view/expenseAutomationView/selectors/transactionCategorizationSelector.js +0 -58
- package/lib/esm/view/recommendation/recommendationHelper.js +0 -29
- package/lib/esm/view/recommendation/recommendationReducer.js +1 -26
- package/lib/esm/view/transactionDetail/transactionDetailReducer.js +6 -121
- package/lib/esm/view/transactionDetail/transactionDetailSelector.js +0 -22
- package/lib/index.d.ts +8 -9
- package/lib/index.js +25 -25
- package/lib/view/expenseAutomationView/epics/missingReceipts/fetchMultipleBatchDetailsEpic.js +21 -5
- package/lib/view/expenseAutomationView/epics/missingReceipts/refreshBatchDetailsForBatchIdEpic.d.ts +18 -0
- package/lib/view/expenseAutomationView/epics/missingReceipts/refreshBatchDetailsForBatchIdEpic.js +56 -0
- package/lib/view/expenseAutomationView/epics/missingReceipts/syncTabsAfterAutomatchEpic.d.ts +28 -0
- package/lib/view/expenseAutomationView/epics/missingReceipts/syncTabsAfterAutomatchEpic.js +57 -0
- package/lib/view/expenseAutomationView/epics/missingReceipts/watchBulkUploadBatchStatusEpic.d.ts +11 -5
- package/lib/view/expenseAutomationView/epics/missingReceipts/watchBulkUploadBatchStatusEpic.js +12 -8
- package/lib/view/expenseAutomationView/helpers/transactionCategorizationLocalDataHelper.d.ts +0 -1
- package/lib/view/expenseAutomationView/helpers/transactionCategorizationLocalDataHelper.js +2 -23
- package/lib/view/expenseAutomationView/reducers/missingReceiptsViewReducer.d.ts +13 -1
- package/lib/view/expenseAutomationView/reducers/missingReceiptsViewReducer.js +80 -4
- package/lib/view/expenseAutomationView/reducers/transactionsViewReducer.d.ts +1 -14
- package/lib/view/expenseAutomationView/reducers/transactionsViewReducer.js +14 -117
- package/lib/view/expenseAutomationView/selectorTypes/missingReceiptsSelectorTypes.d.ts +12 -0
- package/lib/view/expenseAutomationView/selectorTypes/transactionsViewSelectorTypes.d.ts +0 -2
- package/lib/view/expenseAutomationView/selectors/missingReceiptsSelector.js +2 -0
- package/lib/view/expenseAutomationView/selectors/transactionCategorizationSelector.d.ts +0 -3
- package/lib/view/expenseAutomationView/selectors/transactionCategorizationSelector.js +0 -60
- package/lib/view/expenseAutomationView/types/missingReceiptsViewState.d.ts +19 -0
- package/lib/view/expenseAutomationView/types/transactionsViewState.d.ts +0 -1
- package/lib/view/recommendation/recommendationHelper.d.ts +0 -9
- package/lib/view/recommendation/recommendationHelper.js +1 -31
- package/lib/view/recommendation/recommendationReducer.d.ts +1 -20
- package/lib/view/recommendation/recommendationReducer.js +2 -27
- package/lib/view/transactionDetail/transactionDetailReducer.d.ts +1 -11
- package/lib/view/transactionDetail/transactionDetailReducer.js +7 -122
- package/lib/view/transactionDetail/transactionDetailSelector.d.ts +0 -2
- package/lib/view/transactionDetail/transactionDetailSelector.js +1 -24
- package/lib/view/transactionDetail/transactionDetailTypes.d.ts +0 -1
- package/package.json +2 -2
- package/lib/esm/view/recommendation/fetchEntityRecommendationsForLineUpdateEpic.js +0 -87
- package/lib/view/recommendation/fetchEntityRecommendationsForLineUpdateEpic.d.ts +0 -9
- package/lib/view/recommendation/fetchEntityRecommendationsForLineUpdateEpic.js +0 -91
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.hasTransactionLocalDataChanges = exports.isAnyItemWithUncategorizedExpenseAccount = exports.getSnackbarMessageForTransactionReview = exports.mergeTabSpecificLineItems = exports.getLineItemsByTransactionIdsFromLocalData = exports.getLineItemsByTransactionsIdsFromResponse = exports.checkIfAllLineItemsAreCategoryClassFilled = exports.setEntityRecommendationForLineIdInLocalData = exports.toSetAllLineItemsToCategoryClass = exports.toTransactionDetailLocalData = exports.
|
|
3
|
+
exports.hasTransactionLocalDataChanges = exports.isAnyItemWithUncategorizedExpenseAccount = exports.getSnackbarMessageForTransactionReview = exports.mergeTabSpecificLineItems = exports.getLineItemsByTransactionIdsFromLocalData = exports.getLineItemsByTransactionsIdsFromResponse = exports.checkIfAllLineItemsAreCategoryClassFilled = exports.setEntityRecommendationForLineIdInLocalData = exports.toSetAllLineItemsToCategoryClass = exports.toTransactionDetailLocalData = exports.MAX_SELECTION_LIMIT = exports.filterAutoTabLineItems = exports.removeTransactionFromTabView = exports.getPendingReviewLineIdsFromTransaction = void 0;
|
|
4
4
|
const vendorTransaction_1 = require("../../../entity/transaction/stateTypes/vendorTransaction");
|
|
5
5
|
const transactionDetailLocalDataHelper_1 = require("../../transactionDetail/transactionDetailLocalDataHelper");
|
|
6
6
|
const transactionDetailLocalDataHelper_2 = require("../../transactionDetail/transactionDetailLocalDataHelper");
|
|
@@ -65,23 +65,6 @@ const filterAutoTabLineItems = (tabView, transactionId, updatedTransaction) => {
|
|
|
65
65
|
};
|
|
66
66
|
exports.filterAutoTabLineItems = filterAutoTabLineItems;
|
|
67
67
|
exports.MAX_SELECTION_LIMIT = 5;
|
|
68
|
-
// Returns true when the transaction should be auto-added to the
|
|
69
|
-
// selectedCheckBoxTransactionIds list after a categorization-related
|
|
70
|
-
// state mutation: all line items are filled, the selection limit has
|
|
71
|
-
// not been hit, and the id isn't already in the list. Consolidates the
|
|
72
|
-
// triplet that was inlined at four sites (updateSelectedCustomer/Vendor,
|
|
73
|
-
// setAllItemsToCategoryClassInLocalDataForCategorization, and
|
|
74
|
-
// setEntityRecommendationForLineIdInLocalData below).
|
|
75
|
-
const shouldAutoSelectAndAdd = (transaction, localData, selectedCheckBoxTransactionIds, uncategorizedAccounts, isUncategorizedExpenseCategoryEnabled, isAccountingClassesEnabled) => {
|
|
76
|
-
if (selectedCheckBoxTransactionIds.includes(transaction.id)) {
|
|
77
|
-
return false;
|
|
78
|
-
}
|
|
79
|
-
if (selectedCheckBoxTransactionIds.length >= exports.MAX_SELECTION_LIMIT) {
|
|
80
|
-
return false;
|
|
81
|
-
}
|
|
82
|
-
return (0, exports.checkIfAllLineItemsAreCategoryClassFilled)(transaction, localData, uncategorizedAccounts, isUncategorizedExpenseCategoryEnabled, isAccountingClassesEnabled);
|
|
83
|
-
};
|
|
84
|
-
exports.shouldAutoSelectAndAdd = shouldAutoSelectAndAdd;
|
|
85
68
|
const toTransactionDetailLocalData = (transaction, selectedTab, lineItemsByTransactionIds, uncategorizedIncomeExpense, isUncategorizedExpenseCategoryEnabled) => {
|
|
86
69
|
const transactionLocal = {
|
|
87
70
|
...transactionsViewState_1.initialSupportedTransactionCategorization.transactionReviewLocalData,
|
|
@@ -569,14 +552,10 @@ const setEntityRecommendationForLineIdInLocalData = (draft, transaction, transac
|
|
|
569
552
|
selectedEntity: transactionDetailLocalData.selectedEntity,
|
|
570
553
|
tabSpecificLineItems: transactionDetailLocalData.tabSpecificLineItems,
|
|
571
554
|
};
|
|
572
|
-
// Auto-uncheck if not all line items are filled (the row's
|
|
573
|
-
// category/class became stale after the entity update). Otherwise
|
|
574
|
-
// route through shouldAutoSelectAndAdd so the MAX_SELECTION_LIMIT
|
|
575
|
-
// gate is consistently applied across all auto-add sites.
|
|
576
555
|
if (!(0, exports.checkIfAllLineItemsAreCategoryClassFilled)(transaction, newLocalData, uncategorizedAccounts, isUncategorizedExpenseCategoryEnabled, isAccountingClassesEnabled)) {
|
|
577
556
|
selectedCheckBoxTransactionIds = selectedCheckBoxTransactionIds.filter((id) => id !== transaction.id);
|
|
578
557
|
}
|
|
579
|
-
else if ((
|
|
558
|
+
else if (selectedCheckBoxTransactionIds.includes(transaction.id) === false) {
|
|
580
559
|
selectedCheckBoxTransactionIds.push(transaction.id);
|
|
581
560
|
}
|
|
582
561
|
draft.selectedCheckBoxTransactionIds = selectedCheckBoxTransactionIds;
|
|
@@ -19,6 +19,15 @@ export declare const fetchBulkUploadBatchDetails: import("@reduxjs/toolkit").Act
|
|
|
19
19
|
* after a hard refresh. The epic owns the list + details API calls end-to-end.
|
|
20
20
|
*/
|
|
21
21
|
export declare const restoreBulkUploadAutomatchingOnMount: import("@reduxjs/toolkit").ActionCreatorWithoutPayload<"expenseAutomationMissingReceiptsView/restoreBulkUploadAutomatchingOnMount">;
|
|
22
|
+
/**
|
|
23
|
+
* Epic trigger only. Targeted stale-while-revalidate refresh for a single batch's details — used
|
|
24
|
+
* by `pusherBatchStatusCompletionEpic` so a Pusher 'completed' event re-fetches only that one
|
|
25
|
+
* batch instead of wiping the entire `batchDetailsById` cache. The epic dedupes via
|
|
26
|
+
* `lastBatchDetailRefreshAtById` so resend storms don't trigger waves of API calls.
|
|
27
|
+
*/
|
|
28
|
+
export declare const refreshBatchDetailsForBatchId: import("@reduxjs/toolkit").ActionCreatorWithPayload<{
|
|
29
|
+
batchId: ID;
|
|
30
|
+
}, string>;
|
|
22
31
|
export declare const fetchMissingReceipts: import("@reduxjs/toolkit").ActionCreatorWithPreparedPayload<[period: TimePeriod, minimumTransactionAmount: Amount, cacheOverride?: any, refreshViewInBackground?: any], {
|
|
23
32
|
period: TimePeriod;
|
|
24
33
|
minimumTransactionAmount: Amount;
|
|
@@ -73,7 +82,10 @@ export declare const fetchMissingReceipts: import("@reduxjs/toolkit").ActionCrea
|
|
|
73
82
|
}, "expenseAutomationMissingReceiptsView/fetchBulkUploadBatchesSuccess">, fetchBulkUploadBatchesFailure: import("@reduxjs/toolkit").ActionCreatorWithPayload<{
|
|
74
83
|
error: ZeniAPIStatus;
|
|
75
84
|
selectedPeriod: MonthYearPeriod;
|
|
76
|
-
}, "expenseAutomationMissingReceiptsView/fetchBulkUploadBatchesFailure">,
|
|
85
|
+
}, "expenseAutomationMissingReceiptsView/fetchBulkUploadBatchesFailure">, clearBulkUploadBatchDetailsForScopeChange: import("@reduxjs/toolkit").ActionCreatorWithoutPayload<"expenseAutomationMissingReceiptsView/clearBulkUploadBatchDetailsForScopeChange">, markBatchDetailRefreshAttempted: import("@reduxjs/toolkit").ActionCreatorWithPayload<{
|
|
86
|
+
batchId: ID;
|
|
87
|
+
timestamp: number;
|
|
88
|
+
}, "expenseAutomationMissingReceiptsView/markBatchDetailRefreshAttempted">, confirmBulkUploadMatch: import("@reduxjs/toolkit").ActionCreatorWithPreparedPayload<[batchId: string, attachmentId: string, transactionId: string, transactionType: string, fileName: string], {
|
|
77
89
|
batchId: string;
|
|
78
90
|
attachmentId: string;
|
|
79
91
|
transactionId: string;
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
var _a;
|
|
3
3
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
4
|
-
exports.
|
|
4
|
+
exports.fetchCompletedTransactions = exports.acknowledgeBulkUploadConfirmMatchComplete = exports.clearManualSearchResults = exports.searchTransactionsForManualMatchFailure = exports.searchTransactionsForManualMatchSuccess = exports.searchTransactionsForManualMatch = exports.clearBulkUpload = exports.setBulkUploadSortConfig = exports.setBulkUploadCompletedSubTab = exports.setBulkUploadResultsTab = exports.confirmBulkUploadMatchFailure = exports.confirmBulkUploadMatchSuccess = exports.confirmBulkUploadMatch = exports.markBatchDetailRefreshAttempted = exports.clearBulkUploadBatchDetailsForScopeChange = exports.fetchBulkUploadBatchesFailure = exports.fetchBulkUploadBatchesSuccess = exports.fetchBulkUploadBatches = exports.fetchMoreBatchDetailsFailure = exports.fetchMoreBatchDetailsComplete = exports.fetchMoreBatchDetails = exports.setInitialBatchDetailsLoading = exports.batchDetailFetchFailed = exports.storeBatchDetails = exports.fetchBulkUploadBatchDetailsFailure = exports.fetchBulkUploadBatchDetailsSuccess = exports.clearMissingReceiptsTabNavigation = exports.requestMissingReceiptsTabNavigation = exports.pusherBatchStatusUpdate = exports.bulkUploadAutomatchingTimedOut = exports.restoreBulkUploadMatchingState = exports.bulkUploadReceiptsFailure = exports.bulkUploadReceiptsSuccess = exports.setBulkUploadUploadedFileCount = exports.updateBulkUploadProgress = exports.bulkUploadReceipts = exports.clearExpenseAutomationMissingReceiptsView = exports.markMissingReceiptAsDone = exports.updateMissingReceiptsUIState = exports.updateMissingReceiptUploadState = exports.uploadMissingReceiptSuccess = exports.fetchMissingReceiptsFailure = exports.fetchMissingReceiptsSuccess = exports.fetchMissingReceipts = exports.refreshBatchDetailsForBatchId = exports.restoreBulkUploadAutomatchingOnMount = exports.fetchBulkUploadBatchDetails = exports.initialState = exports.initialBulkUploadState = exports.getCompletedTransactionsCacheKey = void 0;
|
|
5
|
+
exports.fetchCompletedTransactionsFailure = exports.fetchCompletedTransactionsSuccess = void 0;
|
|
5
6
|
const toolkit_1 = require("@reduxjs/toolkit");
|
|
6
7
|
const timePeriod_1 = require("../../../commonStateTypes/timePeriod");
|
|
7
8
|
const completedSubTab_1 = require("../types/completedSubTab");
|
|
@@ -15,6 +16,7 @@ exports.getCompletedTransactionsCacheKey = getCompletedTransactionsCacheKey;
|
|
|
15
16
|
exports.initialBulkUploadState = {
|
|
16
17
|
batchDetailsById: {},
|
|
17
18
|
batchDetailsPaginationState: { fetchState: 'Not-Started', error: undefined },
|
|
19
|
+
batchDetailsRevalidating: false,
|
|
18
20
|
batchListByPeriod: {},
|
|
19
21
|
batchListFetchState: { fetchState: 'Not-Started', error: undefined },
|
|
20
22
|
batchStatusById: {},
|
|
@@ -24,6 +26,8 @@ exports.initialBulkUploadState = {
|
|
|
24
26
|
currentBatchId: undefined,
|
|
25
27
|
currentResultsTab: 'unmatched',
|
|
26
28
|
failedBatchDetailIds: [],
|
|
29
|
+
initialBatchDetailsLoaded: false,
|
|
30
|
+
lastBatchDetailRefreshAtById: {},
|
|
27
31
|
manualSearchUiResetKey: 0,
|
|
28
32
|
manualSearch: {
|
|
29
33
|
fetchState: { fetchState: 'Not-Started', error: undefined },
|
|
@@ -70,6 +74,13 @@ exports.fetchBulkUploadBatchDetails = (0, toolkit_1.createAction)('expenseAutoma
|
|
|
70
74
|
* after a hard refresh. The epic owns the list + details API calls end-to-end.
|
|
71
75
|
*/
|
|
72
76
|
exports.restoreBulkUploadAutomatchingOnMount = (0, toolkit_1.createAction)('expenseAutomationMissingReceiptsView/restoreBulkUploadAutomatchingOnMount');
|
|
77
|
+
/**
|
|
78
|
+
* Epic trigger only. Targeted stale-while-revalidate refresh for a single batch's details — used
|
|
79
|
+
* by `pusherBatchStatusCompletionEpic` so a Pusher 'completed' event re-fetches only that one
|
|
80
|
+
* batch instead of wiping the entire `batchDetailsById` cache. The epic dedupes via
|
|
81
|
+
* `lastBatchDetailRefreshAtById` so resend storms don't trigger waves of API calls.
|
|
82
|
+
*/
|
|
83
|
+
exports.refreshBatchDetailsForBatchId = (0, toolkit_1.createAction)('expenseAutomationMissingReceiptsView/refreshBatchDetailsForBatchId');
|
|
73
84
|
const expenseAutomationMissingReceiptsView = (0, toolkit_1.createSlice)({
|
|
74
85
|
name: 'expenseAutomationMissingReceiptsView',
|
|
75
86
|
initialState: exports.initialState,
|
|
@@ -256,6 +267,16 @@ const expenseAutomationMissingReceiptsView = (0, toolkit_1.createSlice)({
|
|
|
256
267
|
const details = action.payload;
|
|
257
268
|
draft.bulkUpload.batchDetailsById[details.batchId] = details;
|
|
258
269
|
draft.bulkUpload.phase = 'completed';
|
|
270
|
+
draft.bulkUpload.initialBatchDetailsLoaded = true;
|
|
271
|
+
/**
|
|
272
|
+
* A successful detail load supersedes any previous failure for this batch — without this,
|
|
273
|
+
* `getPrimaryBatchIdFromBatchListOrder` (and pagination) would keep skipping the batch
|
|
274
|
+
* across the recovery, hiding now-valid Unmatched-tab work.
|
|
275
|
+
*/
|
|
276
|
+
const failedIndex = draft.bulkUpload.failedBatchDetailIds.indexOf(details.batchId);
|
|
277
|
+
if (failedIndex >= 0) {
|
|
278
|
+
draft.bulkUpload.failedBatchDetailIds.splice(failedIndex, 1);
|
|
279
|
+
}
|
|
259
280
|
},
|
|
260
281
|
fetchBulkUploadBatchDetailsFailure: {
|
|
261
282
|
reducer(draft) {
|
|
@@ -277,6 +298,19 @@ const expenseAutomationMissingReceiptsView = (0, toolkit_1.createSlice)({
|
|
|
277
298
|
draft.bulkUpload.currentBatchId === details.batchId) {
|
|
278
299
|
draft.bulkUpload.phase = 'completed';
|
|
279
300
|
}
|
|
301
|
+
/** Stale-while-revalidate: any successful detail load means we have rendered data. */
|
|
302
|
+
draft.bulkUpload.initialBatchDetailsLoaded = true;
|
|
303
|
+
/**
|
|
304
|
+
* Stale-while-revalidate recovery: if this batch had previously failed, a successful
|
|
305
|
+
* targeted refresh (Pusher `completed` → `refreshBatchDetailsForBatchIdEpic`) or
|
|
306
|
+
* multi-batch revalidation (manual refresh) supersedes the failure. Selectors that gate
|
|
307
|
+
* on `failedBatchDetailIds` (primary-batch resolution, `hasMoreBatchDetails`) must see the
|
|
308
|
+
* batch as recovered so it can show fresh Unmatched work.
|
|
309
|
+
*/
|
|
310
|
+
const failedIndex = draft.bulkUpload.failedBatchDetailIds.indexOf(details.batchId);
|
|
311
|
+
if (failedIndex >= 0) {
|
|
312
|
+
draft.bulkUpload.failedBatchDetailIds.splice(failedIndex, 1);
|
|
313
|
+
}
|
|
280
314
|
},
|
|
281
315
|
batchDetailFetchFailed(draft, action) {
|
|
282
316
|
const { batchId } = action.payload;
|
|
@@ -305,6 +339,14 @@ const expenseAutomationMissingReceiptsView = (0, toolkit_1.createSlice)({
|
|
|
305
339
|
fetchState: 'Completed',
|
|
306
340
|
error: undefined,
|
|
307
341
|
};
|
|
342
|
+
/**
|
|
343
|
+
* Stale-while-revalidate: a completed pagination round means the initial page (or a
|
|
344
|
+
* subsequent revalidation) has fully resolved. Once `initialBatchDetailsLoaded` flips to
|
|
345
|
+
* `true` it stays `true` for the session — only `clearBulkUpload` /
|
|
346
|
+
* `clearBulkUploadBatchDetailsForScopeChange` can reset it.
|
|
347
|
+
*/
|
|
348
|
+
draft.bulkUpload.initialBatchDetailsLoaded = true;
|
|
349
|
+
draft.bulkUpload.batchDetailsRevalidating = false;
|
|
308
350
|
const currentId = draft.bulkUpload.currentBatchId;
|
|
309
351
|
const currentDetails = currentId != null
|
|
310
352
|
? draft.bulkUpload.batchDetailsById[currentId]
|
|
@@ -320,12 +362,21 @@ const expenseAutomationMissingReceiptsView = (0, toolkit_1.createSlice)({
|
|
|
320
362
|
fetchState: 'Error',
|
|
321
363
|
error: action.payload.error,
|
|
322
364
|
};
|
|
365
|
+
draft.bulkUpload.batchDetailsRevalidating = false;
|
|
323
366
|
},
|
|
324
367
|
fetchBulkUploadBatches: {
|
|
325
368
|
reducer(draft, action) {
|
|
369
|
+
/**
|
|
370
|
+
* Stale-while-revalidate: when caller asks for a full details refresh (manual refresh
|
|
371
|
+
* button), we keep `batchDetailsById` and `failedBatchDetailIds` intact so the existing
|
|
372
|
+
* UI stays rendered, and flip `batchDetailsRevalidating: true`. The post-success epic
|
|
373
|
+
* (`fetchMultipleBatchDetailsEpic`) sees this flag and re-fetches every completed list
|
|
374
|
+
* row, replacing entries via `storeBatchDetails` as each response arrives. This avoids
|
|
375
|
+
* the previous "wipe to empty → render skeleton" flash. To genuinely drop details (e.g.
|
|
376
|
+
* tenant/period scope change), use `clearBulkUploadBatchDetailsForScopeChange` instead.
|
|
377
|
+
*/
|
|
326
378
|
if (action.payload.invalidateBatchDetailsCache === true) {
|
|
327
|
-
draft.bulkUpload.
|
|
328
|
-
draft.bulkUpload.failedBatchDetailIds = [];
|
|
379
|
+
draft.bulkUpload.batchDetailsRevalidating = true;
|
|
329
380
|
}
|
|
330
381
|
draft.bulkUpload.batchListFetchState = {
|
|
331
382
|
fetchState: 'In-Progress',
|
|
@@ -342,6 +393,31 @@ const expenseAutomationMissingReceiptsView = (0, toolkit_1.createSlice)({
|
|
|
342
393
|
};
|
|
343
394
|
},
|
|
344
395
|
},
|
|
396
|
+
/**
|
|
397
|
+
* Tenant/period scope change — the new scope's data is genuinely unknown so the existing
|
|
398
|
+
* details cache and `initialBatchDetailsLoaded` flag must be reset (the Unmatched skeleton
|
|
399
|
+
* is acceptable on scope change). Distinct from a stale-while-revalidate refresh.
|
|
400
|
+
*/
|
|
401
|
+
clearBulkUploadBatchDetailsForScopeChange(draft) {
|
|
402
|
+
draft.bulkUpload.batchDetailsById = {};
|
|
403
|
+
draft.bulkUpload.failedBatchDetailIds = [];
|
|
404
|
+
draft.bulkUpload.batchDetailsPaginationState = {
|
|
405
|
+
fetchState: 'Not-Started',
|
|
406
|
+
error: undefined,
|
|
407
|
+
};
|
|
408
|
+
draft.bulkUpload.batchDetailsRevalidating = false;
|
|
409
|
+
draft.bulkUpload.initialBatchDetailsLoaded = false;
|
|
410
|
+
draft.bulkUpload.lastBatchDetailRefreshAtById = {};
|
|
411
|
+
},
|
|
412
|
+
/**
|
|
413
|
+
* Records the last time we issued a targeted refresh for `batchId`. Set by
|
|
414
|
+
* `refreshBatchDetailsForBatchIdEpic` before each API call so subsequent Pusher resends in the
|
|
415
|
+
* dedupe window are skipped.
|
|
416
|
+
*/
|
|
417
|
+
markBatchDetailRefreshAttempted(draft, action) {
|
|
418
|
+
draft.bulkUpload.lastBatchDetailRefreshAtById[action.payload.batchId] =
|
|
419
|
+
action.payload.timestamp;
|
|
420
|
+
},
|
|
345
421
|
fetchBulkUploadBatchesSuccess(draft, action) {
|
|
346
422
|
const periodId = (0, timePeriod_1.toMonthYearPeriodId)(action.payload.selectedPeriod);
|
|
347
423
|
draft.bulkUpload.batchListByPeriod[periodId] = action.payload.batchList;
|
|
@@ -584,7 +660,7 @@ const expenseAutomationMissingReceiptsView = (0, toolkit_1.createSlice)({
|
|
|
584
660
|
});
|
|
585
661
|
_a = expenseAutomationMissingReceiptsView.actions, exports.fetchMissingReceipts = _a.fetchMissingReceipts, exports.fetchMissingReceiptsSuccess = _a.fetchMissingReceiptsSuccess, exports.fetchMissingReceiptsFailure = _a.fetchMissingReceiptsFailure, exports.uploadMissingReceiptSuccess = _a.uploadMissingReceiptSuccess, exports.updateMissingReceiptUploadState = _a.updateMissingReceiptUploadState, exports.updateMissingReceiptsUIState = _a.updateMissingReceiptsUIState, exports.markMissingReceiptAsDone = _a.markMissingReceiptAsDone, exports.clearExpenseAutomationMissingReceiptsView = _a.clearExpenseAutomationMissingReceiptsView,
|
|
586
662
|
// Bulk Upload
|
|
587
|
-
exports.bulkUploadReceipts = _a.bulkUploadReceipts, exports.updateBulkUploadProgress = _a.updateBulkUploadProgress, exports.setBulkUploadUploadedFileCount = _a.setBulkUploadUploadedFileCount, exports.bulkUploadReceiptsSuccess = _a.bulkUploadReceiptsSuccess, exports.bulkUploadReceiptsFailure = _a.bulkUploadReceiptsFailure, exports.restoreBulkUploadMatchingState = _a.restoreBulkUploadMatchingState, exports.bulkUploadAutomatchingTimedOut = _a.bulkUploadAutomatchingTimedOut, exports.pusherBatchStatusUpdate = _a.pusherBatchStatusUpdate, exports.requestMissingReceiptsTabNavigation = _a.requestMissingReceiptsTabNavigation, exports.clearMissingReceiptsTabNavigation = _a.clearMissingReceiptsTabNavigation, exports.fetchBulkUploadBatchDetailsSuccess = _a.fetchBulkUploadBatchDetailsSuccess, exports.fetchBulkUploadBatchDetailsFailure = _a.fetchBulkUploadBatchDetailsFailure, exports.storeBatchDetails = _a.storeBatchDetails, exports.batchDetailFetchFailed = _a.batchDetailFetchFailed, exports.setInitialBatchDetailsLoading = _a.setInitialBatchDetailsLoading, exports.fetchMoreBatchDetails = _a.fetchMoreBatchDetails, exports.fetchMoreBatchDetailsComplete = _a.fetchMoreBatchDetailsComplete, exports.fetchMoreBatchDetailsFailure = _a.fetchMoreBatchDetailsFailure, exports.fetchBulkUploadBatches = _a.fetchBulkUploadBatches, exports.fetchBulkUploadBatchesSuccess = _a.fetchBulkUploadBatchesSuccess, exports.fetchBulkUploadBatchesFailure = _a.fetchBulkUploadBatchesFailure, exports.confirmBulkUploadMatch = _a.confirmBulkUploadMatch, exports.confirmBulkUploadMatchSuccess = _a.confirmBulkUploadMatchSuccess, exports.confirmBulkUploadMatchFailure = _a.confirmBulkUploadMatchFailure, exports.setBulkUploadResultsTab = _a.setBulkUploadResultsTab, exports.setBulkUploadCompletedSubTab = _a.setBulkUploadCompletedSubTab, exports.setBulkUploadSortConfig = _a.setBulkUploadSortConfig, exports.clearBulkUpload = _a.clearBulkUpload, exports.searchTransactionsForManualMatch = _a.searchTransactionsForManualMatch, exports.searchTransactionsForManualMatchSuccess = _a.searchTransactionsForManualMatchSuccess, exports.searchTransactionsForManualMatchFailure = _a.searchTransactionsForManualMatchFailure, exports.clearManualSearchResults = _a.clearManualSearchResults, exports.acknowledgeBulkUploadConfirmMatchComplete = _a.acknowledgeBulkUploadConfirmMatchComplete,
|
|
663
|
+
exports.bulkUploadReceipts = _a.bulkUploadReceipts, exports.updateBulkUploadProgress = _a.updateBulkUploadProgress, exports.setBulkUploadUploadedFileCount = _a.setBulkUploadUploadedFileCount, exports.bulkUploadReceiptsSuccess = _a.bulkUploadReceiptsSuccess, exports.bulkUploadReceiptsFailure = _a.bulkUploadReceiptsFailure, exports.restoreBulkUploadMatchingState = _a.restoreBulkUploadMatchingState, exports.bulkUploadAutomatchingTimedOut = _a.bulkUploadAutomatchingTimedOut, exports.pusherBatchStatusUpdate = _a.pusherBatchStatusUpdate, exports.requestMissingReceiptsTabNavigation = _a.requestMissingReceiptsTabNavigation, exports.clearMissingReceiptsTabNavigation = _a.clearMissingReceiptsTabNavigation, exports.fetchBulkUploadBatchDetailsSuccess = _a.fetchBulkUploadBatchDetailsSuccess, exports.fetchBulkUploadBatchDetailsFailure = _a.fetchBulkUploadBatchDetailsFailure, exports.storeBatchDetails = _a.storeBatchDetails, exports.batchDetailFetchFailed = _a.batchDetailFetchFailed, exports.setInitialBatchDetailsLoading = _a.setInitialBatchDetailsLoading, exports.fetchMoreBatchDetails = _a.fetchMoreBatchDetails, exports.fetchMoreBatchDetailsComplete = _a.fetchMoreBatchDetailsComplete, exports.fetchMoreBatchDetailsFailure = _a.fetchMoreBatchDetailsFailure, exports.fetchBulkUploadBatches = _a.fetchBulkUploadBatches, exports.fetchBulkUploadBatchesSuccess = _a.fetchBulkUploadBatchesSuccess, exports.fetchBulkUploadBatchesFailure = _a.fetchBulkUploadBatchesFailure, exports.clearBulkUploadBatchDetailsForScopeChange = _a.clearBulkUploadBatchDetailsForScopeChange, exports.markBatchDetailRefreshAttempted = _a.markBatchDetailRefreshAttempted, exports.confirmBulkUploadMatch = _a.confirmBulkUploadMatch, exports.confirmBulkUploadMatchSuccess = _a.confirmBulkUploadMatchSuccess, exports.confirmBulkUploadMatchFailure = _a.confirmBulkUploadMatchFailure, exports.setBulkUploadResultsTab = _a.setBulkUploadResultsTab, exports.setBulkUploadCompletedSubTab = _a.setBulkUploadCompletedSubTab, exports.setBulkUploadSortConfig = _a.setBulkUploadSortConfig, exports.clearBulkUpload = _a.clearBulkUpload, exports.searchTransactionsForManualMatch = _a.searchTransactionsForManualMatch, exports.searchTransactionsForManualMatchSuccess = _a.searchTransactionsForManualMatchSuccess, exports.searchTransactionsForManualMatchFailure = _a.searchTransactionsForManualMatchFailure, exports.clearManualSearchResults = _a.clearManualSearchResults, exports.acknowledgeBulkUploadConfirmMatchComplete = _a.acknowledgeBulkUploadConfirmMatchComplete,
|
|
588
664
|
// Completed Transactions
|
|
589
665
|
exports.fetchCompletedTransactions = _a.fetchCompletedTransactions, exports.fetchCompletedTransactionsSuccess = _a.fetchCompletedTransactionsSuccess, exports.fetchCompletedTransactionsFailure = _a.fetchCompletedTransactionsFailure;
|
|
590
666
|
exports.default = expenseAutomationMissingReceiptsView.reducer;
|
|
@@ -157,20 +157,7 @@ export declare const fetchTransactionCategorization: import("@reduxjs/toolkit").
|
|
|
157
157
|
uncategorizedAccounts: UncategorizedAccounts;
|
|
158
158
|
isAccountingClassesEnabled: boolean | undefined;
|
|
159
159
|
isUncategorizedExpenseCategoryEnabled: boolean | undefined;
|
|
160
|
-
}, "expenseAutomationTransactionsView/setEntityRecommendationForLineIdsForCategorization", never, never>,
|
|
161
|
-
selectedTab: "review" | "autoCategorized";
|
|
162
|
-
transactionId: TransactionID;
|
|
163
|
-
lineIds: string[];
|
|
164
|
-
}, "expenseAutomationTransactionsView/markCategoryClassRecommendationsInProgressForCategorization", never, never>, markCategoryClassRecommendationsCompletedForCategorization: import("@reduxjs/toolkit").ActionCreatorWithPreparedPayload<[selectedTab: "review" | "autoCategorized", transactionId: TransactionID, lineIds: string[]], {
|
|
165
|
-
selectedTab: "review" | "autoCategorized";
|
|
166
|
-
transactionId: TransactionID;
|
|
167
|
-
lineIds: string[];
|
|
168
|
-
}, "expenseAutomationTransactionsView/markCategoryClassRecommendationsCompletedForCategorization", never, never>, markCategoryClassRecommendationsFailureForCategorization: import("@reduxjs/toolkit").ActionCreatorWithPreparedPayload<[selectedTab: "review" | "autoCategorized", transactionId: TransactionID, lineIds: string[], error: ZeniAPIStatus<Record<string, unknown>>], {
|
|
169
|
-
selectedTab: "review" | "autoCategorized";
|
|
170
|
-
transactionId: TransactionID;
|
|
171
|
-
lineIds: string[];
|
|
172
|
-
error: ZeniAPIStatus<Record<string, unknown>>;
|
|
173
|
-
}, "expenseAutomationTransactionsView/markCategoryClassRecommendationsFailureForCategorization", never, never>, updateSelectedTransactionId: import("@reduxjs/toolkit").ActionCreatorWithPayload<{
|
|
160
|
+
}, "expenseAutomationTransactionsView/setEntityRecommendationForLineIdsForCategorization", never, never>, updateSelectedTransactionId: import("@reduxjs/toolkit").ActionCreatorWithPayload<{
|
|
174
161
|
lineId: ID;
|
|
175
162
|
selectedTab: TransactionsTab;
|
|
176
163
|
transactionId: ID;
|
|
@@ -4,7 +4,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
4
4
|
};
|
|
5
5
|
var _a;
|
|
6
6
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
7
|
-
exports.uploadTransactionCategorizationReceiptSuccess = exports.updateTransactionCategorizationUploadReceiptState = exports.backgroundRefetchReviewTab = exports.syncTransactionCategorizationFromDetailSave = exports.updateSelectedTransactionId = exports.
|
|
7
|
+
exports.uploadTransactionCategorizationReceiptSuccess = exports.updateTransactionCategorizationUploadReceiptState = exports.backgroundRefetchReviewTab = exports.syncTransactionCategorizationFromDetailSave = exports.updateSelectedTransactionId = exports.setEntityRecommendationForLineIdsForCategorization = exports.clearExpenseAutomationTransactionsView = exports.clearExpenseAutomationTransactionsViewPerTabView = exports.updateSelectedCheckboxTransactionIds = exports.fetchTransactionCategorizationView = exports.resetOtherTabsFetchState = exports.fetchTransactionCategorizationSuccess = exports.updateParentTotalCountForTab = exports.updateTotalCountForTransactionCategorization = exports.setAllItemsToCategoryClassInLocalDataForCategorization = exports.updateSelectedCustomerForTransaction = exports.updateSelectedVendorForTransaction = exports.updateStatusForTransactionNotMiscategorizedUpdateForCategorization = exports.markTransactionAsNotMiscategorized = exports.updateTransactionCategorizationSaveStatus = exports.updateTransactionCategorizationCompletedSubTab = exports.updateCurrentSelectedTransactionCategorizationTab = exports.updateTransactionCategorization = exports.saveTransactionCategorization = exports.fetchTransactionCategorizationFailure = exports.saveTransactionCategorizationLocalData = exports.initializeTransactionCategorizationViewLocalData = exports.updateTransactionCategorizationUIState = exports.fetchTransactionCategorization = exports.initialState = exports.initialTransactionTabViewState = void 0;
|
|
8
8
|
const toolkit_1 = require("@reduxjs/toolkit");
|
|
9
9
|
const get_1 = __importDefault(require("lodash/get"));
|
|
10
10
|
const uniq_1 = __importDefault(require("lodash/uniq"));
|
|
@@ -427,9 +427,12 @@ const expenseAutomationTransactionsView = (0, toolkit_1.createSlice)({
|
|
|
427
427
|
const selectedCheckBoxTransactionIds = draft.transactionCategorizationView[selectedTab]
|
|
428
428
|
.selectedCheckBoxTransactionIds;
|
|
429
429
|
if (selectedTransaction != null &&
|
|
430
|
-
(0, transactionCategorizationLocalDataHelper_1.
|
|
430
|
+
(0, transactionCategorizationLocalDataHelper_1.checkIfAllLineItemsAreCategoryClassFilled)(selectedTransaction, newTransactionLocalData, uncategorizedAccounts, isUncategorizedExpenseCategoryEnabled, isAccountingClassesEnabled) === true && // check if all line items are filled
|
|
431
|
+
selectedCheckBoxTransactionIds.length < transactionCategorizationLocalDataHelper_1.MAX_SELECTION_LIMIT &&
|
|
432
|
+
selectedCheckBoxTransactionIds.includes(transactionId) === false) {
|
|
431
433
|
draft.transactionCategorizationView[selectedTab].selectedCheckBoxTransactionIds = [
|
|
432
|
-
...
|
|
434
|
+
...draft.transactionCategorizationView[selectedTab]
|
|
435
|
+
.selectedCheckBoxTransactionIds,
|
|
433
436
|
transactionId,
|
|
434
437
|
];
|
|
435
438
|
}
|
|
@@ -512,26 +515,9 @@ const expenseAutomationTransactionsView = (0, toolkit_1.createSlice)({
|
|
|
512
515
|
const transactionLocalData = (0, get_1.default)(draft.transactionCategorizationView[selectedTab]
|
|
513
516
|
.transactionReviewLocalDataById, transactionId.id, undefined);
|
|
514
517
|
if (transactionLocalData != null) {
|
|
515
|
-
const newLocalData = (0, transactionCategorizationLocalDataHelper_1.setEntityRecommendationForLineIdInLocalData)(draft.transactionCategorizationView[selectedTab], transaction, transactionLocalData.transactionReviewLocalData, entity, lineIds, uncategorizedAccounts, action.payload.recommendationWithCOTByLineId, isUncategorizedExpenseCategoryEnabled, isAccountingClassesEnabled);
|
|
516
|
-
// Release the per-line fetch flag for every line this fetch
|
|
517
|
-
// covered. Done in-place on the freshly returned local data
|
|
518
|
-
// (the helper produces a new mutable object), before we write
|
|
519
|
-
// it back to the draft.
|
|
520
|
-
lineIds.forEach((lineId) => {
|
|
521
|
-
const lineItem = newLocalData.lineItemById[lineId];
|
|
522
|
-
if (lineItem != null) {
|
|
523
|
-
newLocalData.lineItemById[lineId] = {
|
|
524
|
-
...lineItem,
|
|
525
|
-
categoryClassRecommendationsFetchState: {
|
|
526
|
-
fetchState: 'Completed',
|
|
527
|
-
error: undefined,
|
|
528
|
-
},
|
|
529
|
-
};
|
|
530
|
-
}
|
|
531
|
-
});
|
|
532
518
|
draft.transactionCategorizationView[selectedTab].transactionReviewLocalDataById[transaction.id] = {
|
|
533
519
|
transactionId: transaction.id,
|
|
534
|
-
transactionReviewLocalData:
|
|
520
|
+
transactionReviewLocalData: (0, transactionCategorizationLocalDataHelper_1.setEntityRecommendationForLineIdInLocalData)(draft.transactionCategorizationView[selectedTab], transaction, transactionLocalData.transactionReviewLocalData, entity, lineIds, uncategorizedAccounts, action.payload.recommendationWithCOTByLineId, isUncategorizedExpenseCategoryEnabled, isAccountingClassesEnabled),
|
|
535
521
|
};
|
|
536
522
|
// Mark transaction as dirty (autofill happened)
|
|
537
523
|
if (!draft.transactionCategorizationView[selectedTab].transactionIdsWithUnsavedData.includes(transaction.id)) {
|
|
@@ -544,99 +530,6 @@ const expenseAutomationTransactionsView = (0, toolkit_1.createSlice)({
|
|
|
544
530
|
}
|
|
545
531
|
},
|
|
546
532
|
},
|
|
547
|
-
// Start arm of the line-update recommendations fetch. Flips covered
|
|
548
|
-
// lines to In-Progress AND removes the transaction from
|
|
549
|
-
// selectedCheckBoxTransactionIds — the row is unchecked + disabled
|
|
550
|
-
// until either the success arm (recheck if limit allows) or the
|
|
551
|
-
// failure arm releases the per-line flag.
|
|
552
|
-
markCategoryClassRecommendationsInProgressForCategorization: {
|
|
553
|
-
reducer(draft, action) {
|
|
554
|
-
const { selectedTab, transactionId, lineIds } = action.payload;
|
|
555
|
-
const tab = draft.transactionCategorizationView[selectedTab];
|
|
556
|
-
const transactionLocalData = (0, get_1.default)(tab.transactionReviewLocalDataById, transactionId.id, undefined);
|
|
557
|
-
if (transactionLocalData != null) {
|
|
558
|
-
lineIds.forEach((lineId) => {
|
|
559
|
-
const lineItem = transactionLocalData.transactionReviewLocalData.lineItemById[lineId];
|
|
560
|
-
if (lineItem != null) {
|
|
561
|
-
transactionLocalData.transactionReviewLocalData.lineItemById[lineId] = {
|
|
562
|
-
...lineItem,
|
|
563
|
-
categoryClassRecommendationsFetchState: {
|
|
564
|
-
fetchState: 'In-Progress',
|
|
565
|
-
error: undefined,
|
|
566
|
-
},
|
|
567
|
-
};
|
|
568
|
-
}
|
|
569
|
-
});
|
|
570
|
-
}
|
|
571
|
-
// Uncheck on fetch start: the row's existing category/class are
|
|
572
|
-
// stale after a payee change, so we drop the auto-selection until
|
|
573
|
-
// fresh recommendations land.
|
|
574
|
-
if (tab.selectedCheckBoxTransactionIds.includes(transactionId.id)) {
|
|
575
|
-
tab.selectedCheckBoxTransactionIds =
|
|
576
|
-
tab.selectedCheckBoxTransactionIds.filter((id) => id !== transactionId.id);
|
|
577
|
-
}
|
|
578
|
-
},
|
|
579
|
-
prepare(selectedTab, transactionId, lineIds) {
|
|
580
|
-
return { payload: { selectedTab, transactionId, lineIds } };
|
|
581
|
-
},
|
|
582
|
-
},
|
|
583
|
-
// Completed arm. Used by the epic when the HTTP call succeeds but the
|
|
584
|
-
// server returned no per-line recommendations — we still need to
|
|
585
|
-
// release the In-Progress flag so the skeleton resolves. Successful
|
|
586
|
-
// responses with recommendations go through
|
|
587
|
-
// setEntityRecommendationForLineIdsForCategorization instead (which
|
|
588
|
-
// also flips the lines to Completed).
|
|
589
|
-
markCategoryClassRecommendationsCompletedForCategorization: {
|
|
590
|
-
reducer(draft, action) {
|
|
591
|
-
const { selectedTab, transactionId, lineIds } = action.payload;
|
|
592
|
-
const transactionLocalData = (0, get_1.default)(draft.transactionCategorizationView[selectedTab]
|
|
593
|
-
.transactionReviewLocalDataById, transactionId.id, undefined);
|
|
594
|
-
if (transactionLocalData != null) {
|
|
595
|
-
lineIds.forEach((lineId) => {
|
|
596
|
-
const lineItem = transactionLocalData.transactionReviewLocalData.lineItemById[lineId];
|
|
597
|
-
if (lineItem != null) {
|
|
598
|
-
transactionLocalData.transactionReviewLocalData.lineItemById[lineId] = {
|
|
599
|
-
...lineItem,
|
|
600
|
-
categoryClassRecommendationsFetchState: {
|
|
601
|
-
fetchState: 'Completed',
|
|
602
|
-
error: undefined,
|
|
603
|
-
},
|
|
604
|
-
};
|
|
605
|
-
}
|
|
606
|
-
});
|
|
607
|
-
}
|
|
608
|
-
},
|
|
609
|
-
prepare(selectedTab, transactionId, lineIds) {
|
|
610
|
-
return { payload: { selectedTab, transactionId, lineIds } };
|
|
611
|
-
},
|
|
612
|
-
},
|
|
613
|
-
// Failure arm. Flips covered lines to Error so the skeleton resolves
|
|
614
|
-
// and downstream UI can react to the failure. The transaction stays
|
|
615
|
-
// unchecked from the start-arm action.
|
|
616
|
-
markCategoryClassRecommendationsFailureForCategorization: {
|
|
617
|
-
reducer(draft, action) {
|
|
618
|
-
const { selectedTab, transactionId, lineIds, error } = action.payload;
|
|
619
|
-
const transactionLocalData = (0, get_1.default)(draft.transactionCategorizationView[selectedTab]
|
|
620
|
-
.transactionReviewLocalDataById, transactionId.id, undefined);
|
|
621
|
-
if (transactionLocalData != null) {
|
|
622
|
-
lineIds.forEach((lineId) => {
|
|
623
|
-
const lineItem = transactionLocalData.transactionReviewLocalData.lineItemById[lineId];
|
|
624
|
-
if (lineItem != null) {
|
|
625
|
-
transactionLocalData.transactionReviewLocalData.lineItemById[lineId] = {
|
|
626
|
-
...lineItem,
|
|
627
|
-
categoryClassRecommendationsFetchState: {
|
|
628
|
-
fetchState: 'Error',
|
|
629
|
-
error,
|
|
630
|
-
},
|
|
631
|
-
};
|
|
632
|
-
}
|
|
633
|
-
});
|
|
634
|
-
}
|
|
635
|
-
},
|
|
636
|
-
prepare(selectedTab, transactionId, lineIds, error) {
|
|
637
|
-
return { payload: { selectedTab, transactionId, lineIds, error } };
|
|
638
|
-
},
|
|
639
|
-
},
|
|
640
533
|
fetchTransactionCategorizationSuccess(draft, action) {
|
|
641
534
|
const { selectedTab, refreshViewInBackground } = action.payload;
|
|
642
535
|
if (draft.transactionCategorizationView[selectedTab].fetchState ===
|
|
@@ -732,7 +625,9 @@ const expenseAutomationTransactionsView = (0, toolkit_1.createSlice)({
|
|
|
732
625
|
.selectedCheckBoxTransactionIds;
|
|
733
626
|
if (newTransactionLocalData.customer != null &&
|
|
734
627
|
newTransactionLocalData.customer.id != null &&
|
|
735
|
-
(0, transactionCategorizationLocalDataHelper_1.
|
|
628
|
+
(0, transactionCategorizationLocalDataHelper_1.checkIfAllLineItemsAreCategoryClassFilled)(selectedTransaction, newTransactionLocalData, uncategorizedAccounts, isUncategorizedExpenseCategoryEnabled, isAccountingClassesEnabled) === true && // check if all line items are filled
|
|
629
|
+
selectedCheckBoxTransactionIds.length < transactionCategorizationLocalDataHelper_1.MAX_SELECTION_LIMIT &&
|
|
630
|
+
selectedCheckBoxTransactionIds.includes(transactionId) === false) {
|
|
736
631
|
draft.transactionCategorizationView[selectedTab].selectedCheckBoxTransactionIds = [
|
|
737
632
|
...selectedCheckBoxTransactionIds,
|
|
738
633
|
transactionId,
|
|
@@ -806,7 +701,9 @@ const expenseAutomationTransactionsView = (0, toolkit_1.createSlice)({
|
|
|
806
701
|
.selectedCheckBoxTransactionIds;
|
|
807
702
|
if (newTransactionLocalData.vendor != null &&
|
|
808
703
|
newTransactionLocalData.vendor.id != null &&
|
|
809
|
-
(0, transactionCategorizationLocalDataHelper_1.
|
|
704
|
+
(0, transactionCategorizationLocalDataHelper_1.checkIfAllLineItemsAreCategoryClassFilled)(selectedTransaction, newTransactionLocalData, uncategorizedAccounts, isUncategorizedExpenseCategoryEnabled, isAccountingClassesEnabled) === true && // check if all line items are filled
|
|
705
|
+
selectedCheckBoxTransactionIds.length < transactionCategorizationLocalDataHelper_1.MAX_SELECTION_LIMIT &&
|
|
706
|
+
selectedCheckBoxTransactionIds.includes(transactionId) === false) {
|
|
810
707
|
draft.transactionCategorizationView[selectedTab].selectedCheckBoxTransactionIds = [
|
|
811
708
|
...selectedCheckBoxTransactionIds,
|
|
812
709
|
transactionId,
|
|
@@ -1039,5 +936,5 @@ const expenseAutomationTransactionsView = (0, toolkit_1.createSlice)({
|
|
|
1039
936
|
},
|
|
1040
937
|
},
|
|
1041
938
|
});
|
|
1042
|
-
_a = expenseAutomationTransactionsView.actions, exports.fetchTransactionCategorization = _a.fetchTransactionCategorization, exports.updateTransactionCategorizationUIState = _a.updateTransactionCategorizationUIState, exports.initializeTransactionCategorizationViewLocalData = _a.initializeTransactionCategorizationViewLocalData, exports.saveTransactionCategorizationLocalData = _a.saveTransactionCategorizationLocalData, exports.fetchTransactionCategorizationFailure = _a.fetchTransactionCategorizationFailure, exports.saveTransactionCategorization = _a.saveTransactionCategorization, exports.updateTransactionCategorization = _a.updateTransactionCategorization, exports.updateCurrentSelectedTransactionCategorizationTab = _a.updateCurrentSelectedTransactionCategorizationTab, exports.updateTransactionCategorizationCompletedSubTab = _a.updateTransactionCategorizationCompletedSubTab, exports.updateTransactionCategorizationSaveStatus = _a.updateTransactionCategorizationSaveStatus, exports.markTransactionAsNotMiscategorized = _a.markTransactionAsNotMiscategorized, exports.updateStatusForTransactionNotMiscategorizedUpdateForCategorization = _a.updateStatusForTransactionNotMiscategorizedUpdateForCategorization, exports.updateSelectedVendorForTransaction = _a.updateSelectedVendorForTransaction, exports.updateSelectedCustomerForTransaction = _a.updateSelectedCustomerForTransaction, exports.setAllItemsToCategoryClassInLocalDataForCategorization = _a.setAllItemsToCategoryClassInLocalDataForCategorization, exports.updateTotalCountForTransactionCategorization = _a.updateTotalCountForTransactionCategorization, exports.updateParentTotalCountForTab = _a.updateParentTotalCountForTab, exports.fetchTransactionCategorizationSuccess = _a.fetchTransactionCategorizationSuccess, exports.resetOtherTabsFetchState = _a.resetOtherTabsFetchState, exports.fetchTransactionCategorizationView = _a.fetchTransactionCategorizationView, exports.updateSelectedCheckboxTransactionIds = _a.updateSelectedCheckboxTransactionIds, exports.clearExpenseAutomationTransactionsViewPerTabView = _a.clearExpenseAutomationTransactionsViewPerTabView, exports.clearExpenseAutomationTransactionsView = _a.clearExpenseAutomationTransactionsView, exports.setEntityRecommendationForLineIdsForCategorization = _a.setEntityRecommendationForLineIdsForCategorization, exports.
|
|
939
|
+
_a = expenseAutomationTransactionsView.actions, exports.fetchTransactionCategorization = _a.fetchTransactionCategorization, exports.updateTransactionCategorizationUIState = _a.updateTransactionCategorizationUIState, exports.initializeTransactionCategorizationViewLocalData = _a.initializeTransactionCategorizationViewLocalData, exports.saveTransactionCategorizationLocalData = _a.saveTransactionCategorizationLocalData, exports.fetchTransactionCategorizationFailure = _a.fetchTransactionCategorizationFailure, exports.saveTransactionCategorization = _a.saveTransactionCategorization, exports.updateTransactionCategorization = _a.updateTransactionCategorization, exports.updateCurrentSelectedTransactionCategorizationTab = _a.updateCurrentSelectedTransactionCategorizationTab, exports.updateTransactionCategorizationCompletedSubTab = _a.updateTransactionCategorizationCompletedSubTab, exports.updateTransactionCategorizationSaveStatus = _a.updateTransactionCategorizationSaveStatus, exports.markTransactionAsNotMiscategorized = _a.markTransactionAsNotMiscategorized, exports.updateStatusForTransactionNotMiscategorizedUpdateForCategorization = _a.updateStatusForTransactionNotMiscategorizedUpdateForCategorization, exports.updateSelectedVendorForTransaction = _a.updateSelectedVendorForTransaction, exports.updateSelectedCustomerForTransaction = _a.updateSelectedCustomerForTransaction, exports.setAllItemsToCategoryClassInLocalDataForCategorization = _a.setAllItemsToCategoryClassInLocalDataForCategorization, exports.updateTotalCountForTransactionCategorization = _a.updateTotalCountForTransactionCategorization, exports.updateParentTotalCountForTab = _a.updateParentTotalCountForTab, exports.fetchTransactionCategorizationSuccess = _a.fetchTransactionCategorizationSuccess, exports.resetOtherTabsFetchState = _a.resetOtherTabsFetchState, exports.fetchTransactionCategorizationView = _a.fetchTransactionCategorizationView, exports.updateSelectedCheckboxTransactionIds = _a.updateSelectedCheckboxTransactionIds, exports.clearExpenseAutomationTransactionsViewPerTabView = _a.clearExpenseAutomationTransactionsViewPerTabView, exports.clearExpenseAutomationTransactionsView = _a.clearExpenseAutomationTransactionsView, exports.setEntityRecommendationForLineIdsForCategorization = _a.setEntityRecommendationForLineIdsForCategorization, exports.updateSelectedTransactionId = _a.updateSelectedTransactionId, exports.syncTransactionCategorizationFromDetailSave = _a.syncTransactionCategorizationFromDetailSave, exports.backgroundRefetchReviewTab = _a.backgroundRefetchReviewTab, exports.updateTransactionCategorizationUploadReceiptState = _a.updateTransactionCategorizationUploadReceiptState, exports.uploadTransactionCategorizationReceiptSuccess = _a.uploadTransactionCategorizationReceiptSuccess;
|
|
1043
940
|
exports.default = expenseAutomationTransactionsView.reducer;
|
|
@@ -29,6 +29,12 @@ export interface ResolvedBatchFile {
|
|
|
29
29
|
export interface BulkUploadSelectorData {
|
|
30
30
|
batchDetails: ResolvedBatchDetails | undefined;
|
|
31
31
|
batchDetailsPaginationState: FetchStateAndError;
|
|
32
|
+
/**
|
|
33
|
+
* True while a stale-while-revalidate refresh of `batchDetailsById` is in flight (e.g. manual
|
|
34
|
+
* refresh button). UI should keep rendering existing data and show only a lightweight refresh
|
|
35
|
+
* indicator — never the full skeleton.
|
|
36
|
+
*/
|
|
37
|
+
batchDetailsRevalidating: boolean;
|
|
32
38
|
batchList: BatchListItem[];
|
|
33
39
|
batchListFetchState: FetchStateAndError;
|
|
34
40
|
batchStatus: BatchStatus | undefined;
|
|
@@ -37,6 +43,12 @@ export interface BulkUploadSelectorData {
|
|
|
37
43
|
confirmMatchStatus: FetchStateAndError;
|
|
38
44
|
currentResultsTab: BulkUploadResultsTab;
|
|
39
45
|
hasMoreBatchDetails: boolean;
|
|
46
|
+
/**
|
|
47
|
+
* `true` once the first batch-details page has loaded for the current scope (period/tenant).
|
|
48
|
+
* Stays `true` across refreshes — flips back to `false` only on `clearBulkUpload` or on an
|
|
49
|
+
* explicit scope change. Used by the Unmatched tab to gate the initial-load skeleton.
|
|
50
|
+
*/
|
|
51
|
+
initialBatchDetailsLoaded: boolean;
|
|
40
52
|
manualSearch: ManualSearchState;
|
|
41
53
|
/** Bumps when manual search state is cleared — remount manual search inputs. */
|
|
42
54
|
manualSearchUiResetKey: number;
|
|
@@ -20,8 +20,6 @@ export interface ExpenseAutomationTransactionViewSelector extends SelectorView {
|
|
|
20
20
|
classList: ClassBase[];
|
|
21
21
|
completionStatus: CompletionStatusType;
|
|
22
22
|
fetchStateByTransactionTabs: Record<TransactionsTab, FetchStateAndError>;
|
|
23
|
-
hasInFlightCategoryClassRecommendations: boolean;
|
|
24
|
-
inFlightCategoryClassRecommendationsByTransactionId: Record<ID, boolean>;
|
|
25
23
|
isAccountingProjectsEnabled: boolean;
|
|
26
24
|
markAsNotMiscategorizedStatus: FetchStateAndError;
|
|
27
25
|
/**
|
|
@@ -230,6 +230,8 @@ function getExpenseAutomationMissingReceiptsView(state) {
|
|
|
230
230
|
manualSearchUiResetKey: bulkUpload.manualSearchUiResetKey,
|
|
231
231
|
hasMoreBatchDetails,
|
|
232
232
|
batchDetailsPaginationState: bulkUpload.batchDetailsPaginationState,
|
|
233
|
+
batchDetailsRevalidating: bulkUpload.batchDetailsRevalidating,
|
|
234
|
+
initialBatchDetailsLoaded: bulkUpload.initialBatchDetailsLoaded,
|
|
233
235
|
manualSearch: {
|
|
234
236
|
...bulkUpload.manualSearch,
|
|
235
237
|
results: manualSearchResults,
|
|
@@ -1,6 +1,3 @@
|
|
|
1
|
-
import { ID } from '../../../commonStateTypes/common';
|
|
2
1
|
import { RootState } from '../../../reducer';
|
|
3
2
|
import { ExpenseAutomationTransactionViewSelector } from '../selectorTypes/transactionsViewSelectorTypes';
|
|
4
|
-
export declare const getCategorizationInFlightRecommendationsByTransactionId: (state: RootState) => Record<ID, boolean>;
|
|
5
|
-
export declare const getCategorizationHasInFlightRecommendations: (state: RootState) => boolean;
|
|
6
3
|
export declare function getExpenseAutomationTransactionView(state: RootState): ExpenseAutomationTransactionViewSelector;
|
|
@@ -3,9 +3,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
3
3
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
4
|
};
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
-
exports.getCategorizationHasInFlightRecommendations = exports.getCategorizationInFlightRecommendationsByTransactionId = void 0;
|
|
7
6
|
exports.getExpenseAutomationTransactionView = getExpenseAutomationTransactionView;
|
|
8
|
-
const toolkit_1 = require("@reduxjs/toolkit");
|
|
9
7
|
const omit_1 = __importDefault(require("lodash/omit"));
|
|
10
8
|
const reduceFetchState_1 = require("../../../commonStateTypes/reduceFetchState");
|
|
11
9
|
const timePeriod_1 = require("../../../commonStateTypes/timePeriod");
|
|
@@ -16,60 +14,6 @@ const accountListSelector_1 = require("../../accountList/accountListSelector");
|
|
|
16
14
|
const classListSelector_1 = require("../../classList/classListSelector");
|
|
17
15
|
const projectListSelector_1 = require("../../projectList/projectListSelector");
|
|
18
16
|
const expenseAutomationViewSelectorTypes_1 = require("../selectorTypes/expenseAutomationViewSelectorTypes");
|
|
19
|
-
// Walks the tab's transactionReviewLocalDataById map and returns
|
|
20
|
-
// `{ [transactionId]: true }` for every transaction that has at least
|
|
21
|
-
// one line whose targeted-fetch is In-Progress. Pulled out as a plain
|
|
22
|
-
// function so each tab's createSelector can share it.
|
|
23
|
-
const computeCategorizationInFlightRecommendations = (transactionReviewLocalDataById) => {
|
|
24
|
-
const result = {};
|
|
25
|
-
if (transactionReviewLocalDataById == null) {
|
|
26
|
-
return result;
|
|
27
|
-
}
|
|
28
|
-
for (const [transactionId, data] of Object.entries(transactionReviewLocalDataById)) {
|
|
29
|
-
const lineItems = Object.values(data.transactionReviewLocalData.lineItemById);
|
|
30
|
-
if (lineItems.some((lineItem) => lineItem.categoryClassRecommendationsFetchState?.fetchState ===
|
|
31
|
-
'In-Progress')) {
|
|
32
|
-
result[transactionId] = true;
|
|
33
|
-
}
|
|
34
|
-
}
|
|
35
|
-
return result;
|
|
36
|
-
};
|
|
37
|
-
// Per-tab createSelector instances. Each one is memoized on its OWN tab's
|
|
38
|
-
// transactionReviewLocalDataById reference. Switching tabs A->B->A no
|
|
39
|
-
// longer busts the memo for tab A — the dispatcher below just returns
|
|
40
|
-
// whichever per-tab selector matches the active tab, and reselect keeps
|
|
41
|
-
// the prior result alive as long as the underlying slice ref is stable.
|
|
42
|
-
const getReviewInFlightRecommendationsByTransactionId = (0, toolkit_1.createSelector)((state) => state.expenseAutomationTransactionsViewState.transactionCategorizationView
|
|
43
|
-
.review.transactionReviewLocalDataById, computeCategorizationInFlightRecommendations);
|
|
44
|
-
const getAutoCategorizedInFlightRecommendationsByTransactionId = (0, toolkit_1.createSelector)((state) => state.expenseAutomationTransactionsViewState.transactionCategorizationView
|
|
45
|
-
.autoCategorized.transactionReviewLocalDataById, computeCategorizationInFlightRecommendations);
|
|
46
|
-
// Per-transaction "any line is fetching category/class recommendations?"
|
|
47
|
-
// map for the active categorization tab. Dispatches to the per-tab
|
|
48
|
-
// memoized selector above so steady state (no fetches in flight)
|
|
49
|
-
// recomputes only when the active tab's local data changes; tab switches
|
|
50
|
-
// are O(1) cache lookups.
|
|
51
|
-
//
|
|
52
|
-
// `default` guards against the union "lying" at runtime: `TransactionsTab`
|
|
53
|
-
// is produced via `stringToUnion`, which falls back to `s as StringUnion`
|
|
54
|
-
// for unrecognized strings, so an unexpected value can land in state. The
|
|
55
|
-
// downstream `getCategorizationHasInFlightRecommendations` calls
|
|
56
|
-
// `Object.keys` on this result, so we must always return an object.
|
|
57
|
-
const getCategorizationInFlightRecommendationsByTransactionId = (state) => {
|
|
58
|
-
const tab = state.expenseAutomationTransactionsViewState
|
|
59
|
-
.selectedTransactionCategorizationTab;
|
|
60
|
-
switch (tab) {
|
|
61
|
-
case 'review':
|
|
62
|
-
return getReviewInFlightRecommendationsByTransactionId(state);
|
|
63
|
-
case 'autoCategorized':
|
|
64
|
-
return getAutoCategorizedInFlightRecommendationsByTransactionId(state);
|
|
65
|
-
default:
|
|
66
|
-
return {};
|
|
67
|
-
}
|
|
68
|
-
};
|
|
69
|
-
exports.getCategorizationInFlightRecommendationsByTransactionId = getCategorizationInFlightRecommendationsByTransactionId;
|
|
70
|
-
// Page-level "any line on the active tab is in flight?" flag. Drives the
|
|
71
|
-
// list-page Save disable.
|
|
72
|
-
exports.getCategorizationHasInFlightRecommendations = (0, toolkit_1.createSelector)(exports.getCategorizationInFlightRecommendationsByTransactionId, (inFlightByTransactionId) => Object.keys(inFlightByTransactionId).length > 0);
|
|
73
17
|
function getExpenseAutomationTransactionView(state) {
|
|
74
18
|
const { accountState, classState, classListState, accountListState, expenseAutomationTransactionsViewState, expenseAutomationViewState, projectState, projectListState, transactionState, monthEndCloseChecksState, monthEndCloseChecksViewState, } = state;
|
|
75
19
|
const { selectedTransactionCategorizationCompletedSubTab, selectedTransactionCategorizationTab, } = expenseAutomationTransactionsViewState;
|
|
@@ -165,8 +109,6 @@ function getExpenseAutomationTransactionView(state) {
|
|
|
165
109
|
: [];
|
|
166
110
|
const transactionCompletionStatus = allSteps.find((step) => step.step === 'transaction_categorization')?.completionStatus;
|
|
167
111
|
const completionStatus = transactionCompletionStatus ?? 'incomplete';
|
|
168
|
-
const inFlightCategoryClassRecommendationsByTransactionId = (0, exports.getCategorizationInFlightRecommendationsByTransactionId)(state);
|
|
169
|
-
const hasInFlightCategoryClassRecommendations = (0, exports.getCategorizationHasInFlightRecommendations)(state);
|
|
170
112
|
return {
|
|
171
113
|
version: 0,
|
|
172
114
|
fetchState: fetchStatus.fetchState,
|
|
@@ -180,8 +122,6 @@ function getExpenseAutomationTransactionView(state) {
|
|
|
180
122
|
classList: allClasses,
|
|
181
123
|
accountsHierarchyList,
|
|
182
124
|
classHierarchyList,
|
|
183
|
-
hasInFlightCategoryClassRecommendations,
|
|
184
|
-
inFlightCategoryClassRecommendationsByTransactionId,
|
|
185
125
|
isAccountingProjectsEnabled,
|
|
186
126
|
projectList,
|
|
187
127
|
transactionLocalData,
|