@zeniai/client-epic-state 5.0.73 → 5.0.75
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/commonStateTypes/filterPrimitives.d.ts +23 -0
- package/lib/commonStateTypes/filterPrimitives.js +21 -0
- package/lib/entity/account/accountSelector.d.ts +26 -0
- package/lib/entity/account/accountSelector.js +47 -1
- package/lib/entity/account/accountState.d.ts +5 -0
- package/lib/entity/account/accountState.js +11 -4
- package/lib/entity/class/classSelector.d.ts +35 -0
- package/lib/entity/class/classSelector.js +50 -0
- package/lib/epic.d.ts +2 -1
- package/lib/epic.js +2 -1
- package/lib/esm/commonStateTypes/filterPrimitives.js +20 -0
- package/lib/esm/entity/account/accountSelector.js +46 -1
- package/lib/esm/entity/account/accountState.js +7 -1
- package/lib/esm/entity/class/classSelector.js +48 -0
- package/lib/esm/epic.js +2 -1
- package/lib/esm/index.js +14 -8
- package/lib/esm/view/companyHealthMetricView/companyHealthMetricViewSelector.js +1 -1
- package/lib/esm/view/companyView/helpers/cockpitHelpers.js +1 -1
- package/lib/esm/view/companyView/selector/companyManagementViewSelector.js +1 -1
- package/lib/esm/view/companyView/selector/companyPortfolioViewSelector.js +1 -1
- package/lib/esm/view/expenseAutomationView/helpers/transactionCategorizationLocalDataHelper.js +21 -1
- package/lib/esm/view/expenseAutomationView/reducers/transactionsViewReducer.js +127 -14
- package/lib/esm/view/expenseAutomationView/selectors/transactionCategorizationSelector.js +127 -12
- package/lib/esm/view/expenseAutomationView/transactionFilterHelpers.js +258 -0
- package/lib/esm/view/recommendation/fetchEntityRecommendationsForLineUpdateEpic.js +87 -0
- package/lib/esm/view/recommendation/recommendationHelper.js +29 -0
- package/lib/esm/view/recommendation/recommendationReducer.js +26 -1
- package/lib/esm/view/spendManagement/spendManagementFilterHelpers.js +4 -2
- package/lib/esm/view/subscriptionView/subscriptionViewSelector.js +1 -1
- package/lib/esm/view/taskManager/taskListView/taskListReducer.js +1 -1
- package/lib/esm/view/transactionDetail/transactionDetailReducer.js +121 -6
- package/lib/esm/view/transactionDetail/transactionDetailSelector.js +22 -0
- package/lib/index.d.ts +12 -9
- package/lib/index.js +44 -32
- package/lib/view/companyHealthMetricView/companyHealthMetricViewSelector.js +1 -1
- package/lib/view/companyView/helpers/cockpitHelpers.js +1 -1
- package/lib/view/companyView/selector/companyManagementViewSelector.js +1 -1
- package/lib/view/companyView/selector/companyPortfolioViewSelector.js +1 -1
- package/lib/view/companyView/types/cockpitTypes.d.ts +1 -1
- package/lib/view/expenseAutomationView/helpers/transactionCategorizationLocalDataHelper.d.ts +1 -0
- package/lib/view/expenseAutomationView/helpers/transactionCategorizationLocalDataHelper.js +23 -2
- package/lib/view/expenseAutomationView/reducers/transactionsViewReducer.d.ts +19 -2
- package/lib/view/expenseAutomationView/reducers/transactionsViewReducer.js +127 -14
- package/lib/view/expenseAutomationView/selectorTypes/transactionsViewSelectorTypes.d.ts +2 -0
- package/lib/view/expenseAutomationView/selectors/transactionCategorizationSelector.d.ts +7 -1
- package/lib/view/expenseAutomationView/selectors/transactionCategorizationSelector.js +130 -12
- package/lib/view/expenseAutomationView/transactionFilterHelpers.d.ts +66 -0
- package/lib/view/expenseAutomationView/transactionFilterHelpers.js +262 -0
- package/lib/view/expenseAutomationView/types/transactionsViewState.d.ts +3 -0
- package/lib/view/recommendation/fetchEntityRecommendationsForLineUpdateEpic.d.ts +9 -0
- package/lib/view/recommendation/fetchEntityRecommendationsForLineUpdateEpic.js +91 -0
- package/lib/view/recommendation/recommendationHelper.d.ts +9 -0
- package/lib/view/recommendation/recommendationHelper.js +31 -1
- package/lib/view/recommendation/recommendationReducer.d.ts +20 -1
- package/lib/view/recommendation/recommendationReducer.js +27 -2
- package/lib/view/spendManagement/billPay/billList/billListState.d.ts +1 -1
- package/lib/view/spendManagement/chargeCards/chargeCardPaymentHistory/chargeCardPaymentHistory.d.ts +1 -1
- package/lib/view/spendManagement/reimbursement/remiListView/remiListState.d.ts +1 -1
- package/lib/view/spendManagement/spendManagementFilterHelpers.d.ts +12 -3
- package/lib/view/spendManagement/spendManagementFilterHelpers.js +4 -2
- package/lib/view/subscriptionView/subscriptionViewSelector.js +1 -1
- package/lib/view/taskManager/taskListView/taskList.d.ts +1 -1
- package/lib/view/taskManager/taskListView/taskListReducer.js +1 -1
- package/lib/view/transactionDetail/transactionDetailReducer.d.ts +11 -1
- package/lib/view/transactionDetail/transactionDetailReducer.js +122 -7
- package/lib/view/transactionDetail/transactionDetailSelector.d.ts +2 -0
- package/lib/view/transactionDetail/transactionDetailSelector.js +24 -1
- package/lib/view/transactionDetail/transactionDetailTypes.d.ts +1 -0
- package/package.json +1 -1
|
@@ -14,6 +14,7 @@ import { ZeniAPIStatus } from '../../../responsePayload';
|
|
|
14
14
|
import { UncategorizedAccounts } from '../../accountList/accountListSelector';
|
|
15
15
|
import { UpdateTransactionCategorizationResponsePayload } from '../payload/transactionCategorizationPayload';
|
|
16
16
|
import { SupportedTransactionCategorization, TransactionSaveUpdates, TransactionsTab, TransactionsTabViewState, TransactionsViewState, TransactionsViewUIState } from '../types/transactionsViewState';
|
|
17
|
+
import { TransactionFilters } from '../transactionFilterHelpers';
|
|
17
18
|
export declare const initialTransactionTabViewState: TransactionsTabViewState;
|
|
18
19
|
export declare const initialState: TransactionsViewState;
|
|
19
20
|
export declare const fetchTransactionCategorization: import("@reduxjs/toolkit").ActionCreatorWithPreparedPayload<[selectedTab: "review" | "autoCategorized", period: TimePeriod, cacheOverride?: any, keepExistingListItems?: any, searchString?: string | undefined, pageToken?: PageToken | undefined, refreshViewInBackground?: any, resetListItems?: boolean | undefined, isUncategorizedExpenseCategoryEnabled?: boolean | undefined], {
|
|
@@ -29,7 +30,10 @@ export declare const fetchTransactionCategorization: import("@reduxjs/toolkit").
|
|
|
29
30
|
}, "expenseAutomationTransactionsView/fetchTransactionCategorization", never, never>, updateTransactionCategorizationUIState: import("@reduxjs/toolkit").ActionCreatorWithPayload<{
|
|
30
31
|
selectedTab: TransactionsTab;
|
|
31
32
|
uiState: Partial<TransactionsViewUIState>;
|
|
32
|
-
}, "expenseAutomationTransactionsView/updateTransactionCategorizationUIState">,
|
|
33
|
+
}, "expenseAutomationTransactionsView/updateTransactionCategorizationUIState">, updateTransactionFilters: import("@reduxjs/toolkit").ActionCreatorWithPayload<{
|
|
34
|
+
filters: TransactionFilters;
|
|
35
|
+
selectedTab: TransactionsTab;
|
|
36
|
+
}, "expenseAutomationTransactionsView/updateTransactionFilters">, initializeTransactionCategorizationViewLocalData: import("@reduxjs/toolkit").ActionCreatorWithPreparedPayload<[selectedTab: "review" | "autoCategorized", transactionIds: string[], selectedPeriod: MonthYearPeriod, keepExistingListItems: any, pageToken: PageToken, totalCount: number, lineItemsByTransactionIds: Record<string, string[]>, refreshViewInBackground?: any, isUncategorizedExpenseCategoryEnabled?: boolean | undefined], {
|
|
33
37
|
selectedTab: "review" | "autoCategorized";
|
|
34
38
|
transactionIds: string[];
|
|
35
39
|
selectedPeriod: MonthYearPeriod;
|
|
@@ -157,7 +161,20 @@ export declare const fetchTransactionCategorization: import("@reduxjs/toolkit").
|
|
|
157
161
|
uncategorizedAccounts: UncategorizedAccounts;
|
|
158
162
|
isAccountingClassesEnabled: boolean | undefined;
|
|
159
163
|
isUncategorizedExpenseCategoryEnabled: boolean | undefined;
|
|
160
|
-
}, "expenseAutomationTransactionsView/setEntityRecommendationForLineIdsForCategorization", never, never>,
|
|
164
|
+
}, "expenseAutomationTransactionsView/setEntityRecommendationForLineIdsForCategorization", never, never>, markCategoryClassRecommendationsInProgressForCategorization: import("@reduxjs/toolkit").ActionCreatorWithPreparedPayload<[selectedTab: "review" | "autoCategorized", transactionId: TransactionID, lineIds: string[]], {
|
|
165
|
+
selectedTab: "review" | "autoCategorized";
|
|
166
|
+
transactionId: TransactionID;
|
|
167
|
+
lineIds: string[];
|
|
168
|
+
}, "expenseAutomationTransactionsView/markCategoryClassRecommendationsInProgressForCategorization", never, never>, markCategoryClassRecommendationsCompletedForCategorization: import("@reduxjs/toolkit").ActionCreatorWithPreparedPayload<[selectedTab: "review" | "autoCategorized", transactionId: TransactionID, lineIds: string[]], {
|
|
169
|
+
selectedTab: "review" | "autoCategorized";
|
|
170
|
+
transactionId: TransactionID;
|
|
171
|
+
lineIds: string[];
|
|
172
|
+
}, "expenseAutomationTransactionsView/markCategoryClassRecommendationsCompletedForCategorization", never, never>, markCategoryClassRecommendationsFailureForCategorization: import("@reduxjs/toolkit").ActionCreatorWithPreparedPayload<[selectedTab: "review" | "autoCategorized", transactionId: TransactionID, lineIds: string[], error: ZeniAPIStatus<Record<string, unknown>>], {
|
|
173
|
+
selectedTab: "review" | "autoCategorized";
|
|
174
|
+
transactionId: TransactionID;
|
|
175
|
+
lineIds: string[];
|
|
176
|
+
error: ZeniAPIStatus<Record<string, unknown>>;
|
|
177
|
+
}, "expenseAutomationTransactionsView/markCategoryClassRecommendationsFailureForCategorization", never, never>, updateSelectedTransactionId: import("@reduxjs/toolkit").ActionCreatorWithPayload<{
|
|
161
178
|
lineId: ID;
|
|
162
179
|
selectedTab: TransactionsTab;
|
|
163
180
|
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.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;
|
|
7
|
+
exports.uploadTransactionCategorizationReceiptSuccess = exports.updateTransactionCategorizationUploadReceiptState = exports.backgroundRefetchReviewTab = exports.syncTransactionCategorizationFromDetailSave = exports.updateSelectedTransactionId = exports.markCategoryClassRecommendationsFailureForCategorization = exports.markCategoryClassRecommendationsCompletedForCategorization = exports.markCategoryClassRecommendationsInProgressForCategorization = 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.updateTransactionFilters = 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"));
|
|
@@ -35,6 +35,10 @@ exports.initialTransactionTabViewState = {
|
|
|
35
35
|
totalCount: {},
|
|
36
36
|
limit: 10,
|
|
37
37
|
},
|
|
38
|
+
filters: {
|
|
39
|
+
categoryCombinationOperator: 'AND',
|
|
40
|
+
categories: [],
|
|
41
|
+
},
|
|
38
42
|
fetchState: 'Not-Started',
|
|
39
43
|
error: undefined,
|
|
40
44
|
hasValidState() {
|
|
@@ -306,6 +310,12 @@ const expenseAutomationTransactionsView = (0, toolkit_1.createSlice)({
|
|
|
306
310
|
uiState.totalCount;
|
|
307
311
|
}
|
|
308
312
|
},
|
|
313
|
+
updateTransactionFilters(draft, action) {
|
|
314
|
+
const { selectedTab, filters } = action.payload;
|
|
315
|
+
// `filters` is non-nullable per the payload type, so no runtime
|
|
316
|
+
// null-check is needed — dropping it removes a dead defensive branch.
|
|
317
|
+
draft.transactionCategorizationView[selectedTab].filters = filters;
|
|
318
|
+
},
|
|
309
319
|
saveTransactionCategorization: {
|
|
310
320
|
prepare(selectedTab, transactionIds, cotTrackingByTransactionId, isUncategorizedExpenseCategoryEnabled) {
|
|
311
321
|
return {
|
|
@@ -427,12 +437,9 @@ const expenseAutomationTransactionsView = (0, toolkit_1.createSlice)({
|
|
|
427
437
|
const selectedCheckBoxTransactionIds = draft.transactionCategorizationView[selectedTab]
|
|
428
438
|
.selectedCheckBoxTransactionIds;
|
|
429
439
|
if (selectedTransaction != null &&
|
|
430
|
-
(0, transactionCategorizationLocalDataHelper_1.
|
|
431
|
-
selectedCheckBoxTransactionIds.length < transactionCategorizationLocalDataHelper_1.MAX_SELECTION_LIMIT &&
|
|
432
|
-
selectedCheckBoxTransactionIds.includes(transactionId) === false) {
|
|
440
|
+
(0, transactionCategorizationLocalDataHelper_1.shouldAutoSelectAndAdd)(selectedTransaction, newTransactionLocalData, selectedCheckBoxTransactionIds, uncategorizedAccounts, isUncategorizedExpenseCategoryEnabled, isAccountingClassesEnabled)) {
|
|
433
441
|
draft.transactionCategorizationView[selectedTab].selectedCheckBoxTransactionIds = [
|
|
434
|
-
...
|
|
435
|
-
.selectedCheckBoxTransactionIds,
|
|
442
|
+
...selectedCheckBoxTransactionIds,
|
|
436
443
|
transactionId,
|
|
437
444
|
];
|
|
438
445
|
}
|
|
@@ -515,9 +522,26 @@ const expenseAutomationTransactionsView = (0, toolkit_1.createSlice)({
|
|
|
515
522
|
const transactionLocalData = (0, get_1.default)(draft.transactionCategorizationView[selectedTab]
|
|
516
523
|
.transactionReviewLocalDataById, transactionId.id, undefined);
|
|
517
524
|
if (transactionLocalData != null) {
|
|
525
|
+
const newLocalData = (0, transactionCategorizationLocalDataHelper_1.setEntityRecommendationForLineIdInLocalData)(draft.transactionCategorizationView[selectedTab], transaction, transactionLocalData.transactionReviewLocalData, entity, lineIds, uncategorizedAccounts, action.payload.recommendationWithCOTByLineId, isUncategorizedExpenseCategoryEnabled, isAccountingClassesEnabled);
|
|
526
|
+
// Release the per-line fetch flag for every line this fetch
|
|
527
|
+
// covered. Done in-place on the freshly returned local data
|
|
528
|
+
// (the helper produces a new mutable object), before we write
|
|
529
|
+
// it back to the draft.
|
|
530
|
+
lineIds.forEach((lineId) => {
|
|
531
|
+
const lineItem = newLocalData.lineItemById[lineId];
|
|
532
|
+
if (lineItem != null) {
|
|
533
|
+
newLocalData.lineItemById[lineId] = {
|
|
534
|
+
...lineItem,
|
|
535
|
+
categoryClassRecommendationsFetchState: {
|
|
536
|
+
fetchState: 'Completed',
|
|
537
|
+
error: undefined,
|
|
538
|
+
},
|
|
539
|
+
};
|
|
540
|
+
}
|
|
541
|
+
});
|
|
518
542
|
draft.transactionCategorizationView[selectedTab].transactionReviewLocalDataById[transaction.id] = {
|
|
519
543
|
transactionId: transaction.id,
|
|
520
|
-
transactionReviewLocalData:
|
|
544
|
+
transactionReviewLocalData: newLocalData,
|
|
521
545
|
};
|
|
522
546
|
// Mark transaction as dirty (autofill happened)
|
|
523
547
|
if (!draft.transactionCategorizationView[selectedTab].transactionIdsWithUnsavedData.includes(transaction.id)) {
|
|
@@ -530,6 +554,99 @@ const expenseAutomationTransactionsView = (0, toolkit_1.createSlice)({
|
|
|
530
554
|
}
|
|
531
555
|
},
|
|
532
556
|
},
|
|
557
|
+
// Start arm of the line-update recommendations fetch. Flips covered
|
|
558
|
+
// lines to In-Progress AND removes the transaction from
|
|
559
|
+
// selectedCheckBoxTransactionIds — the row is unchecked + disabled
|
|
560
|
+
// until either the success arm (recheck if limit allows) or the
|
|
561
|
+
// failure arm releases the per-line flag.
|
|
562
|
+
markCategoryClassRecommendationsInProgressForCategorization: {
|
|
563
|
+
reducer(draft, action) {
|
|
564
|
+
const { selectedTab, transactionId, lineIds } = action.payload;
|
|
565
|
+
const tab = draft.transactionCategorizationView[selectedTab];
|
|
566
|
+
const transactionLocalData = (0, get_1.default)(tab.transactionReviewLocalDataById, transactionId.id, undefined);
|
|
567
|
+
if (transactionLocalData != null) {
|
|
568
|
+
lineIds.forEach((lineId) => {
|
|
569
|
+
const lineItem = transactionLocalData.transactionReviewLocalData.lineItemById[lineId];
|
|
570
|
+
if (lineItem != null) {
|
|
571
|
+
transactionLocalData.transactionReviewLocalData.lineItemById[lineId] = {
|
|
572
|
+
...lineItem,
|
|
573
|
+
categoryClassRecommendationsFetchState: {
|
|
574
|
+
fetchState: 'In-Progress',
|
|
575
|
+
error: undefined,
|
|
576
|
+
},
|
|
577
|
+
};
|
|
578
|
+
}
|
|
579
|
+
});
|
|
580
|
+
}
|
|
581
|
+
// Uncheck on fetch start: the row's existing category/class are
|
|
582
|
+
// stale after a payee change, so we drop the auto-selection until
|
|
583
|
+
// fresh recommendations land.
|
|
584
|
+
if (tab.selectedCheckBoxTransactionIds.includes(transactionId.id)) {
|
|
585
|
+
tab.selectedCheckBoxTransactionIds =
|
|
586
|
+
tab.selectedCheckBoxTransactionIds.filter((id) => id !== transactionId.id);
|
|
587
|
+
}
|
|
588
|
+
},
|
|
589
|
+
prepare(selectedTab, transactionId, lineIds) {
|
|
590
|
+
return { payload: { selectedTab, transactionId, lineIds } };
|
|
591
|
+
},
|
|
592
|
+
},
|
|
593
|
+
// Completed arm. Used by the epic when the HTTP call succeeds but the
|
|
594
|
+
// server returned no per-line recommendations — we still need to
|
|
595
|
+
// release the In-Progress flag so the skeleton resolves. Successful
|
|
596
|
+
// responses with recommendations go through
|
|
597
|
+
// setEntityRecommendationForLineIdsForCategorization instead (which
|
|
598
|
+
// also flips the lines to Completed).
|
|
599
|
+
markCategoryClassRecommendationsCompletedForCategorization: {
|
|
600
|
+
reducer(draft, action) {
|
|
601
|
+
const { selectedTab, transactionId, lineIds } = action.payload;
|
|
602
|
+
const transactionLocalData = (0, get_1.default)(draft.transactionCategorizationView[selectedTab]
|
|
603
|
+
.transactionReviewLocalDataById, transactionId.id, undefined);
|
|
604
|
+
if (transactionLocalData != null) {
|
|
605
|
+
lineIds.forEach((lineId) => {
|
|
606
|
+
const lineItem = transactionLocalData.transactionReviewLocalData.lineItemById[lineId];
|
|
607
|
+
if (lineItem != null) {
|
|
608
|
+
transactionLocalData.transactionReviewLocalData.lineItemById[lineId] = {
|
|
609
|
+
...lineItem,
|
|
610
|
+
categoryClassRecommendationsFetchState: {
|
|
611
|
+
fetchState: 'Completed',
|
|
612
|
+
error: undefined,
|
|
613
|
+
},
|
|
614
|
+
};
|
|
615
|
+
}
|
|
616
|
+
});
|
|
617
|
+
}
|
|
618
|
+
},
|
|
619
|
+
prepare(selectedTab, transactionId, lineIds) {
|
|
620
|
+
return { payload: { selectedTab, transactionId, lineIds } };
|
|
621
|
+
},
|
|
622
|
+
},
|
|
623
|
+
// Failure arm. Flips covered lines to Error so the skeleton resolves
|
|
624
|
+
// and downstream UI can react to the failure. The transaction stays
|
|
625
|
+
// unchecked from the start-arm action.
|
|
626
|
+
markCategoryClassRecommendationsFailureForCategorization: {
|
|
627
|
+
reducer(draft, action) {
|
|
628
|
+
const { selectedTab, transactionId, lineIds, error } = action.payload;
|
|
629
|
+
const transactionLocalData = (0, get_1.default)(draft.transactionCategorizationView[selectedTab]
|
|
630
|
+
.transactionReviewLocalDataById, transactionId.id, undefined);
|
|
631
|
+
if (transactionLocalData != null) {
|
|
632
|
+
lineIds.forEach((lineId) => {
|
|
633
|
+
const lineItem = transactionLocalData.transactionReviewLocalData.lineItemById[lineId];
|
|
634
|
+
if (lineItem != null) {
|
|
635
|
+
transactionLocalData.transactionReviewLocalData.lineItemById[lineId] = {
|
|
636
|
+
...lineItem,
|
|
637
|
+
categoryClassRecommendationsFetchState: {
|
|
638
|
+
fetchState: 'Error',
|
|
639
|
+
error,
|
|
640
|
+
},
|
|
641
|
+
};
|
|
642
|
+
}
|
|
643
|
+
});
|
|
644
|
+
}
|
|
645
|
+
},
|
|
646
|
+
prepare(selectedTab, transactionId, lineIds, error) {
|
|
647
|
+
return { payload: { selectedTab, transactionId, lineIds, error } };
|
|
648
|
+
},
|
|
649
|
+
},
|
|
533
650
|
fetchTransactionCategorizationSuccess(draft, action) {
|
|
534
651
|
const { selectedTab, refreshViewInBackground } = action.payload;
|
|
535
652
|
if (draft.transactionCategorizationView[selectedTab].fetchState ===
|
|
@@ -625,9 +742,7 @@ const expenseAutomationTransactionsView = (0, toolkit_1.createSlice)({
|
|
|
625
742
|
.selectedCheckBoxTransactionIds;
|
|
626
743
|
if (newTransactionLocalData.customer != null &&
|
|
627
744
|
newTransactionLocalData.customer.id != null &&
|
|
628
|
-
(0, transactionCategorizationLocalDataHelper_1.
|
|
629
|
-
selectedCheckBoxTransactionIds.length < transactionCategorizationLocalDataHelper_1.MAX_SELECTION_LIMIT &&
|
|
630
|
-
selectedCheckBoxTransactionIds.includes(transactionId) === false) {
|
|
745
|
+
(0, transactionCategorizationLocalDataHelper_1.shouldAutoSelectAndAdd)(selectedTransaction, newTransactionLocalData, selectedCheckBoxTransactionIds, uncategorizedAccounts, isUncategorizedExpenseCategoryEnabled, isAccountingClassesEnabled)) {
|
|
631
746
|
draft.transactionCategorizationView[selectedTab].selectedCheckBoxTransactionIds = [
|
|
632
747
|
...selectedCheckBoxTransactionIds,
|
|
633
748
|
transactionId,
|
|
@@ -701,9 +816,7 @@ const expenseAutomationTransactionsView = (0, toolkit_1.createSlice)({
|
|
|
701
816
|
.selectedCheckBoxTransactionIds;
|
|
702
817
|
if (newTransactionLocalData.vendor != null &&
|
|
703
818
|
newTransactionLocalData.vendor.id != null &&
|
|
704
|
-
(0, transactionCategorizationLocalDataHelper_1.
|
|
705
|
-
selectedCheckBoxTransactionIds.length < transactionCategorizationLocalDataHelper_1.MAX_SELECTION_LIMIT &&
|
|
706
|
-
selectedCheckBoxTransactionIds.includes(transactionId) === false) {
|
|
819
|
+
(0, transactionCategorizationLocalDataHelper_1.shouldAutoSelectAndAdd)(selectedTransaction, newTransactionLocalData, selectedCheckBoxTransactionIds, uncategorizedAccounts, isUncategorizedExpenseCategoryEnabled, isAccountingClassesEnabled)) {
|
|
707
820
|
draft.transactionCategorizationView[selectedTab].selectedCheckBoxTransactionIds = [
|
|
708
821
|
...selectedCheckBoxTransactionIds,
|
|
709
822
|
transactionId,
|
|
@@ -936,5 +1049,5 @@ const expenseAutomationTransactionsView = (0, toolkit_1.createSlice)({
|
|
|
936
1049
|
},
|
|
937
1050
|
},
|
|
938
1051
|
});
|
|
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;
|
|
1052
|
+
_a = expenseAutomationTransactionsView.actions, exports.fetchTransactionCategorization = _a.fetchTransactionCategorization, exports.updateTransactionCategorizationUIState = _a.updateTransactionCategorizationUIState, exports.updateTransactionFilters = _a.updateTransactionFilters, 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.markCategoryClassRecommendationsInProgressForCategorization = _a.markCategoryClassRecommendationsInProgressForCategorization, exports.markCategoryClassRecommendationsCompletedForCategorization = _a.markCategoryClassRecommendationsCompletedForCategorization, exports.markCategoryClassRecommendationsFailureForCategorization = _a.markCategoryClassRecommendationsFailureForCategorization, exports.updateSelectedTransactionId = _a.updateSelectedTransactionId, exports.syncTransactionCategorizationFromDetailSave = _a.syncTransactionCategorizationFromDetailSave, exports.backgroundRefetchReviewTab = _a.backgroundRefetchReviewTab, exports.updateTransactionCategorizationUploadReceiptState = _a.updateTransactionCategorizationUploadReceiptState, exports.uploadTransactionCategorizationReceiptSuccess = _a.uploadTransactionCategorizationReceiptSuccess;
|
|
940
1053
|
exports.default = expenseAutomationTransactionsView.reducer;
|
|
@@ -20,6 +20,8 @@ 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>;
|
|
23
25
|
isAccountingProjectsEnabled: boolean;
|
|
24
26
|
markAsNotMiscategorizedStatus: FetchStateAndError;
|
|
25
27
|
/**
|
|
@@ -1,3 +1,9 @@
|
|
|
1
|
+
import { ID } from '../../../commonStateTypes/common';
|
|
2
|
+
import { TransactionWithCOT } from '../../../entity/transaction/stateTypes/transaction';
|
|
1
3
|
import { RootState } from '../../../reducer';
|
|
2
|
-
import {
|
|
4
|
+
import { TransactionView } from '../transactionFilterHelpers';
|
|
5
|
+
import { ExpenseAutomationTransactionViewSelector, TransactionReviewLocalDataSelectorView } from '../selectorTypes/transactionsViewSelectorTypes';
|
|
6
|
+
export declare const getCategorizationInFlightRecommendationsByTransactionId: (state: RootState) => Record<ID, boolean>;
|
|
7
|
+
export declare const getCategorizationHasInFlightRecommendations: (state: RootState) => boolean;
|
|
8
|
+
export declare const toTransactionView: (transaction: TransactionWithCOT, transactionLocalData?: TransactionReviewLocalDataSelectorView) => TransactionView;
|
|
3
9
|
export declare function getExpenseAutomationTransactionView(state: RootState): ExpenseAutomationTransactionViewSelector;
|
|
@@ -3,21 +3,97 @@ 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.toTransactionView = exports.getCategorizationHasInFlightRecommendations = exports.getCategorizationInFlightRecommendationsByTransactionId = void 0;
|
|
6
7
|
exports.getExpenseAutomationTransactionView = getExpenseAutomationTransactionView;
|
|
8
|
+
const toolkit_1 = require("@reduxjs/toolkit");
|
|
7
9
|
const omit_1 = __importDefault(require("lodash/omit"));
|
|
8
10
|
const reduceFetchState_1 = require("../../../commonStateTypes/reduceFetchState");
|
|
9
11
|
const timePeriod_1 = require("../../../commonStateTypes/timePeriod");
|
|
10
12
|
const tenantSelector_1 = require("../../../entity/tenant/tenantSelector");
|
|
11
13
|
const transactionHelper_1 = require("../../../entity/transaction/transactionHelper");
|
|
12
14
|
const transactionSelector_1 = require("../../../entity/transaction/transactionSelector");
|
|
15
|
+
const transactionFilterHelpers_1 = require("../transactionFilterHelpers");
|
|
13
16
|
const accountListSelector_1 = require("../../accountList/accountListSelector");
|
|
14
17
|
const classListSelector_1 = require("../../classList/classListSelector");
|
|
15
18
|
const projectListSelector_1 = require("../../projectList/projectListSelector");
|
|
16
19
|
const expenseAutomationViewSelectorTypes_1 = require("../selectorTypes/expenseAutomationViewSelectorTypes");
|
|
20
|
+
// Walks the tab's transactionReviewLocalDataById map and returns
|
|
21
|
+
// `{ [transactionId]: true }` for every transaction that has at least
|
|
22
|
+
// one line whose targeted-fetch is In-Progress. Pulled out as a plain
|
|
23
|
+
// function so each tab's createSelector can share it.
|
|
24
|
+
const computeCategorizationInFlightRecommendations = (transactionReviewLocalDataById) => {
|
|
25
|
+
const result = {};
|
|
26
|
+
if (transactionReviewLocalDataById == null) {
|
|
27
|
+
return result;
|
|
28
|
+
}
|
|
29
|
+
for (const [transactionId, data] of Object.entries(transactionReviewLocalDataById)) {
|
|
30
|
+
const lineItems = Object.values(data.transactionReviewLocalData.lineItemById);
|
|
31
|
+
if (lineItems.some((lineItem) => lineItem.categoryClassRecommendationsFetchState?.fetchState ===
|
|
32
|
+
'In-Progress')) {
|
|
33
|
+
result[transactionId] = true;
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
return result;
|
|
37
|
+
};
|
|
38
|
+
// Per-tab createSelector instances. Each one is memoized on its OWN tab's
|
|
39
|
+
// transactionReviewLocalDataById reference. Switching tabs A->B->A no
|
|
40
|
+
// longer busts the memo for tab A — the dispatcher below just returns
|
|
41
|
+
// whichever per-tab selector matches the active tab, and reselect keeps
|
|
42
|
+
// the prior result alive as long as the underlying slice ref is stable.
|
|
43
|
+
const getReviewInFlightRecommendationsByTransactionId = (0, toolkit_1.createSelector)((state) => state.expenseAutomationTransactionsViewState.transactionCategorizationView
|
|
44
|
+
.review.transactionReviewLocalDataById, computeCategorizationInFlightRecommendations);
|
|
45
|
+
const getAutoCategorizedInFlightRecommendationsByTransactionId = (0, toolkit_1.createSelector)((state) => state.expenseAutomationTransactionsViewState.transactionCategorizationView
|
|
46
|
+
.autoCategorized.transactionReviewLocalDataById, computeCategorizationInFlightRecommendations);
|
|
47
|
+
// Per-transaction "any line is fetching category/class recommendations?"
|
|
48
|
+
// map for the active categorization tab. Dispatches to the per-tab
|
|
49
|
+
// memoized selector above so steady state (no fetches in flight)
|
|
50
|
+
// recomputes only when the active tab's local data changes; tab switches
|
|
51
|
+
// are O(1) cache lookups.
|
|
52
|
+
//
|
|
53
|
+
// `default` guards against the union "lying" at runtime: `TransactionsTab`
|
|
54
|
+
// is produced via `stringToUnion`, which falls back to `s as StringUnion`
|
|
55
|
+
// for unrecognized strings, so an unexpected value can land in state. The
|
|
56
|
+
// downstream `getCategorizationHasInFlightRecommendations` calls
|
|
57
|
+
// `Object.keys` on this result, so we must always return an object.
|
|
58
|
+
const getCategorizationInFlightRecommendationsByTransactionId = (state) => {
|
|
59
|
+
const tab = state.expenseAutomationTransactionsViewState
|
|
60
|
+
.selectedTransactionCategorizationTab;
|
|
61
|
+
switch (tab) {
|
|
62
|
+
case 'review':
|
|
63
|
+
return getReviewInFlightRecommendationsByTransactionId(state);
|
|
64
|
+
case 'autoCategorized':
|
|
65
|
+
return getAutoCategorizedInFlightRecommendationsByTransactionId(state);
|
|
66
|
+
default:
|
|
67
|
+
return {};
|
|
68
|
+
}
|
|
69
|
+
};
|
|
70
|
+
exports.getCategorizationInFlightRecommendationsByTransactionId = getCategorizationInFlightRecommendationsByTransactionId;
|
|
71
|
+
// Page-level "any line on the active tab is in flight?" flag. Drives the
|
|
72
|
+
// list-page Save disable.
|
|
73
|
+
exports.getCategorizationHasInFlightRecommendations = (0, toolkit_1.createSelector)(exports.getCategorizationInFlightRecommendationsByTransactionId, (inFlightByTransactionId) => Object.keys(inFlightByTransactionId).length > 0);
|
|
74
|
+
const toTransactionView = (transaction, transactionLocalData) => {
|
|
75
|
+
return {
|
|
76
|
+
id: transaction.id,
|
|
77
|
+
date: transaction.date,
|
|
78
|
+
amount: transaction.amount,
|
|
79
|
+
vendorName: transaction.vendorName,
|
|
80
|
+
customerName: transaction.customerName,
|
|
81
|
+
vendorId: transaction.vendorId,
|
|
82
|
+
customerId: transaction.customerId,
|
|
83
|
+
description: transaction.description,
|
|
84
|
+
memo: transaction.memo,
|
|
85
|
+
type: transaction.type,
|
|
86
|
+
typeName: transaction.typeName,
|
|
87
|
+
createTime: transaction.createTime,
|
|
88
|
+
transaction: transaction,
|
|
89
|
+
transactionLocalData,
|
|
90
|
+
};
|
|
91
|
+
};
|
|
92
|
+
exports.toTransactionView = toTransactionView;
|
|
17
93
|
function getExpenseAutomationTransactionView(state) {
|
|
18
94
|
const { accountState, classState, classListState, accountListState, expenseAutomationTransactionsViewState, expenseAutomationViewState, projectState, projectListState, transactionState, monthEndCloseChecksState, monthEndCloseChecksViewState, } = state;
|
|
19
95
|
const { selectedTransactionCategorizationCompletedSubTab, selectedTransactionCategorizationTab, } = expenseAutomationTransactionsViewState;
|
|
20
|
-
const { uiState, refreshStatus, saveStatus, markAsNotMiscategorizedStatus, transactionIdsBySelectedPeriod, transactionReviewLocalDataById, selectedCheckBoxTransactionIds, transactionIdsWithUnsavedData, uploadReceiptStatusById, selectedTransactionId, selectedTransactionLineId, } = expenseAutomationTransactionsViewState.transactionCategorizationView[selectedTransactionCategorizationTab];
|
|
96
|
+
const { uiState, refreshStatus, saveStatus, markAsNotMiscategorizedStatus, transactionIdsBySelectedPeriod, transactionReviewLocalDataById, selectedCheckBoxTransactionIds, transactionIdsWithUnsavedData, uploadReceiptStatusById, selectedTransactionId, selectedTransactionLineId, filters, } = expenseAutomationTransactionsViewState.transactionCategorizationView[selectedTransactionCategorizationTab];
|
|
21
97
|
const uncategorizedIncomeExpense = (0, accountListSelector_1.getUncategorizedAccounts)(accountState, accountListState, 'accountList');
|
|
22
98
|
const accountList = (0, accountListSelector_1.getAccountList)(accountState, accountListState, 'accountList');
|
|
23
99
|
const classList = (0, classListSelector_1.getClassList)(classState, classListState);
|
|
@@ -36,20 +112,58 @@ function getExpenseAutomationTransactionView(state) {
|
|
|
36
112
|
? transactionIdsBySelectedPeriod[monthYearPeriodId]
|
|
37
113
|
: null;
|
|
38
114
|
const transactionIds = transactionIdsForSelectedPeriod ?? [];
|
|
39
|
-
const
|
|
40
|
-
|
|
115
|
+
const transactions = (0, transactionSelector_1.getSupportedTransactionsByIds)(transactionState, transactionIds);
|
|
116
|
+
const transactionsWithCOT = transactions.map((transaction) => (0, transactionHelper_1.getTransactionWithCOT)(transaction));
|
|
117
|
+
const transactionLocalDataMap = new Map();
|
|
118
|
+
transactionIds.forEach((transactionId) => {
|
|
41
119
|
const transactionData = transactionReviewLocalDataById[transactionId];
|
|
42
120
|
if (transactionData != null) {
|
|
43
|
-
|
|
121
|
+
transactionLocalDataMap.set(transactionId, {
|
|
44
122
|
transactionId,
|
|
45
123
|
transactionReviewLocalData: transactionData.transactionReviewLocalData,
|
|
46
|
-
};
|
|
124
|
+
});
|
|
47
125
|
}
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
126
|
+
});
|
|
127
|
+
// Step 2: Convert to TransactionView and apply advanced filters
|
|
128
|
+
const transactionViews = transactionsWithCOT.map((transaction) => {
|
|
129
|
+
const localData = transactionLocalDataMap.get(transaction.id);
|
|
130
|
+
return (0, exports.toTransactionView)(transaction, localData);
|
|
131
|
+
});
|
|
132
|
+
// Apply TC-specific filters (lives under expenseAutomationView, independent
|
|
133
|
+
// of the Spend Management filter pipeline).
|
|
134
|
+
const filteredTransactionViews = (0, transactionFilterHelpers_1.applyTransactionFilters)(transactionViews, filters);
|
|
135
|
+
// Convert back to TransactionWithCOT for return
|
|
136
|
+
const filteredTransactionsWithCOT = filteredTransactionViews.map((view) => view.transaction);
|
|
137
|
+
// Get transactionLocalData for filtered transactions
|
|
138
|
+
// Also include transactionLocalData for transactions that don't exist in transactionState
|
|
139
|
+
// but have local data (to match original behavior)
|
|
140
|
+
const filteredTransactionIds = new Set(filteredTransactionViews.map((view) => view.id));
|
|
141
|
+
// Pre-compute the membership set once. The previous implementation called
|
|
142
|
+
// `transactions.some(t => t.id === transactionId)` inside the per-id loop,
|
|
143
|
+
// turning the pipeline into O(n × m) — measurable on tenants with large
|
|
144
|
+
// transaction lists since this selector runs on every Redux dispatch.
|
|
145
|
+
const transactionExistsById = new Set(transactions.map((t) => t.id));
|
|
146
|
+
// `.flatMap` returns `X[]` directly when the callback returns `[]` for the
|
|
147
|
+
// skip case, so we don't need the trailing `.filter((d): d is X => …)` type
|
|
148
|
+
// predicate that the previous `map → filter` pipeline required.
|
|
149
|
+
const filteredTransactionLocalData = transactionIds.flatMap((transactionId) => {
|
|
150
|
+
const transactionData = transactionReviewLocalDataById[transactionId];
|
|
151
|
+
if (transactionData == null) {
|
|
152
|
+
return [];
|
|
153
|
+
}
|
|
154
|
+
// Include if transaction is in filtered results, or if transaction doesn't exist in state
|
|
155
|
+
// (to maintain backward compatibility with tests)
|
|
156
|
+
const transactionExists = transactionExistsById.has(transactionId);
|
|
157
|
+
if (filteredTransactionIds.has(transactionId) || !transactionExists) {
|
|
158
|
+
return [
|
|
159
|
+
{
|
|
160
|
+
transactionId,
|
|
161
|
+
transactionReviewLocalData: transactionData.transactionReviewLocalData,
|
|
162
|
+
},
|
|
163
|
+
];
|
|
164
|
+
}
|
|
165
|
+
return [];
|
|
166
|
+
});
|
|
53
167
|
const monthEndFetchState = monthYearPeriodId != null
|
|
54
168
|
? (monthEndCloseChecksViewState.monthEndCloseChecksViewByTenantId[currentTenant.tenantId]?.[monthYearPeriodId] ?? { fetchState: 'Not-Started', error: undefined })
|
|
55
169
|
: { fetchState: 'Not-Started', error: undefined };
|
|
@@ -109,11 +223,13 @@ function getExpenseAutomationTransactionView(state) {
|
|
|
109
223
|
: [];
|
|
110
224
|
const transactionCompletionStatus = allSteps.find((step) => step.step === 'transaction_categorization')?.completionStatus;
|
|
111
225
|
const completionStatus = transactionCompletionStatus ?? 'incomplete';
|
|
226
|
+
const inFlightCategoryClassRecommendationsByTransactionId = (0, exports.getCategorizationInFlightRecommendationsByTransactionId)(state);
|
|
227
|
+
const hasInFlightCategoryClassRecommendations = (0, exports.getCategorizationHasInFlightRecommendations)(state);
|
|
112
228
|
return {
|
|
113
229
|
version: 0,
|
|
114
230
|
fetchState: fetchStatus.fetchState,
|
|
115
231
|
error: fetchStatus.error,
|
|
116
|
-
transactions:
|
|
232
|
+
transactions: filteredTransactionsWithCOT,
|
|
117
233
|
selectedCheckBoxTransactionIds,
|
|
118
234
|
transactionIdsWithUnsavedData,
|
|
119
235
|
uncategorizedAccounts: uncategorizedIncomeExpense,
|
|
@@ -122,9 +238,11 @@ function getExpenseAutomationTransactionView(state) {
|
|
|
122
238
|
classList: allClasses,
|
|
123
239
|
accountsHierarchyList,
|
|
124
240
|
classHierarchyList,
|
|
241
|
+
hasInFlightCategoryClassRecommendations,
|
|
242
|
+
inFlightCategoryClassRecommendationsByTransactionId,
|
|
125
243
|
isAccountingProjectsEnabled,
|
|
126
244
|
projectList,
|
|
127
|
-
transactionLocalData,
|
|
245
|
+
transactionLocalData: filteredTransactionLocalData,
|
|
128
246
|
uiState,
|
|
129
247
|
refreshStatus,
|
|
130
248
|
saveStatus,
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Filter machinery for the Transaction Categorization feature inside
|
|
3
|
+
* Expense Automation. Intentionally self-contained — does NOT import anything
|
|
4
|
+
* from `view/spendManagement/*`, because Transaction Categorization is not a
|
|
5
|
+
* Spend Management product. Shared primitives
|
|
6
|
+
* (`CategoryCombinationOperator`, `FilterCategoryType`) come from
|
|
7
|
+
* `commonStateTypes/filterPrimitives`, which both feature groups consume.
|
|
8
|
+
*/
|
|
9
|
+
import { Amount } from '../../commonStateTypes/amount';
|
|
10
|
+
import { ID } from '../../commonStateTypes/common';
|
|
11
|
+
import { CategoryCombinationOperator, FilterCategoryType } from '../../commonStateTypes/filterPrimitives';
|
|
12
|
+
import { TransactionType } from '../../entity/transaction/stateTypes/transactionType';
|
|
13
|
+
import { SupportedTransactionWithCOT } from '../../entity/transaction/transactionState';
|
|
14
|
+
import { ZeniDate } from '../../zeniDayJS';
|
|
15
|
+
import { TransactionReviewLocalDataSelectorView } from './selectorTypes/transactionsViewSelectorTypes';
|
|
16
|
+
/**
|
|
17
|
+
* Re-exported here so the CES barrel can pull TC's primitives from the
|
|
18
|
+
* Expense Automation surface without reaching into `commonStateTypes`
|
|
19
|
+
* directly — keeps the barrel's existing import topology stable.
|
|
20
|
+
*/
|
|
21
|
+
export type { CategoryCombinationOperator, FilterCategoryType };
|
|
22
|
+
export type TransactionFilterEntityType = 'transaction_categorization' | 'customer' | 'vendor' | 'merchant';
|
|
23
|
+
export type TransactionFilterCategoryField = 'payment_account_name' | 'payment_account_type' | 'payee' | 'category' | 'class' | 'amount';
|
|
24
|
+
export interface TransactionFilterCategoryDropdownOption {
|
|
25
|
+
value: TransactionFilterCategoryField;
|
|
26
|
+
multiple?: boolean;
|
|
27
|
+
type?: FilterCategoryType;
|
|
28
|
+
}
|
|
29
|
+
export declare const TRANSACTION_FILTER_CATEGORIES: TransactionFilterCategoryDropdownOption[];
|
|
30
|
+
/** Amount filter operators for transaction_categorization. */
|
|
31
|
+
export type TransactionFilterAmountMatchingOperator = 'equal' | 'not_equal' | 'less_than' | 'greater_than' | 'in_between';
|
|
32
|
+
export interface TransactionFilterCategory {
|
|
33
|
+
field: TransactionFilterCategoryField;
|
|
34
|
+
matchingOperator: TransactionFilterAmountMatchingOperator;
|
|
35
|
+
values: (string | number)[];
|
|
36
|
+
valuesCombinationOperator: 'ANY';
|
|
37
|
+
}
|
|
38
|
+
export interface TransactionFilters {
|
|
39
|
+
categories: TransactionFilterCategory[];
|
|
40
|
+
categoryCombinationOperator: CategoryCombinationOperator;
|
|
41
|
+
}
|
|
42
|
+
export interface TransactionView {
|
|
43
|
+
amount: Amount;
|
|
44
|
+
createTime: ZeniDate;
|
|
45
|
+
date: ZeniDate;
|
|
46
|
+
description: string;
|
|
47
|
+
id: ID;
|
|
48
|
+
memo: string;
|
|
49
|
+
transaction: SupportedTransactionWithCOT;
|
|
50
|
+
type: TransactionType;
|
|
51
|
+
customerId?: ID;
|
|
52
|
+
customerName?: string;
|
|
53
|
+
transactionLocalData?: TransactionReviewLocalDataSelectorView;
|
|
54
|
+
typeName?: string;
|
|
55
|
+
vendorId?: ID;
|
|
56
|
+
vendorName?: string;
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* TC-only equivalent of `applyAdvancedFiltersOnList`. Filters a list of
|
|
60
|
+
* `TransactionView` items against a `TransactionFilters` object using the
|
|
61
|
+
* AND/OR combination semantics from `categoryCombinationOperator`.
|
|
62
|
+
*
|
|
63
|
+
* Independent of `view/spendManagement` — keeps the TC filter pipeline cleanly
|
|
64
|
+
* inside the Expense Automation feature group.
|
|
65
|
+
*/
|
|
66
|
+
export declare const applyTransactionFilters: (transactions: TransactionView[], filters?: TransactionFilters) => TransactionView[];
|