@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.
Files changed (69) hide show
  1. package/lib/commonStateTypes/filterPrimitives.d.ts +23 -0
  2. package/lib/commonStateTypes/filterPrimitives.js +21 -0
  3. package/lib/entity/account/accountSelector.d.ts +26 -0
  4. package/lib/entity/account/accountSelector.js +47 -1
  5. package/lib/entity/account/accountState.d.ts +5 -0
  6. package/lib/entity/account/accountState.js +11 -4
  7. package/lib/entity/class/classSelector.d.ts +35 -0
  8. package/lib/entity/class/classSelector.js +50 -0
  9. package/lib/epic.d.ts +2 -1
  10. package/lib/epic.js +2 -1
  11. package/lib/esm/commonStateTypes/filterPrimitives.js +20 -0
  12. package/lib/esm/entity/account/accountSelector.js +46 -1
  13. package/lib/esm/entity/account/accountState.js +7 -1
  14. package/lib/esm/entity/class/classSelector.js +48 -0
  15. package/lib/esm/epic.js +2 -1
  16. package/lib/esm/index.js +14 -8
  17. package/lib/esm/view/companyHealthMetricView/companyHealthMetricViewSelector.js +1 -1
  18. package/lib/esm/view/companyView/helpers/cockpitHelpers.js +1 -1
  19. package/lib/esm/view/companyView/selector/companyManagementViewSelector.js +1 -1
  20. package/lib/esm/view/companyView/selector/companyPortfolioViewSelector.js +1 -1
  21. package/lib/esm/view/expenseAutomationView/helpers/transactionCategorizationLocalDataHelper.js +21 -1
  22. package/lib/esm/view/expenseAutomationView/reducers/transactionsViewReducer.js +127 -14
  23. package/lib/esm/view/expenseAutomationView/selectors/transactionCategorizationSelector.js +127 -12
  24. package/lib/esm/view/expenseAutomationView/transactionFilterHelpers.js +258 -0
  25. package/lib/esm/view/recommendation/fetchEntityRecommendationsForLineUpdateEpic.js +87 -0
  26. package/lib/esm/view/recommendation/recommendationHelper.js +29 -0
  27. package/lib/esm/view/recommendation/recommendationReducer.js +26 -1
  28. package/lib/esm/view/spendManagement/spendManagementFilterHelpers.js +4 -2
  29. package/lib/esm/view/subscriptionView/subscriptionViewSelector.js +1 -1
  30. package/lib/esm/view/taskManager/taskListView/taskListReducer.js +1 -1
  31. package/lib/esm/view/transactionDetail/transactionDetailReducer.js +121 -6
  32. package/lib/esm/view/transactionDetail/transactionDetailSelector.js +22 -0
  33. package/lib/index.d.ts +12 -9
  34. package/lib/index.js +44 -32
  35. package/lib/view/companyHealthMetricView/companyHealthMetricViewSelector.js +1 -1
  36. package/lib/view/companyView/helpers/cockpitHelpers.js +1 -1
  37. package/lib/view/companyView/selector/companyManagementViewSelector.js +1 -1
  38. package/lib/view/companyView/selector/companyPortfolioViewSelector.js +1 -1
  39. package/lib/view/companyView/types/cockpitTypes.d.ts +1 -1
  40. package/lib/view/expenseAutomationView/helpers/transactionCategorizationLocalDataHelper.d.ts +1 -0
  41. package/lib/view/expenseAutomationView/helpers/transactionCategorizationLocalDataHelper.js +23 -2
  42. package/lib/view/expenseAutomationView/reducers/transactionsViewReducer.d.ts +19 -2
  43. package/lib/view/expenseAutomationView/reducers/transactionsViewReducer.js +127 -14
  44. package/lib/view/expenseAutomationView/selectorTypes/transactionsViewSelectorTypes.d.ts +2 -0
  45. package/lib/view/expenseAutomationView/selectors/transactionCategorizationSelector.d.ts +7 -1
  46. package/lib/view/expenseAutomationView/selectors/transactionCategorizationSelector.js +130 -12
  47. package/lib/view/expenseAutomationView/transactionFilterHelpers.d.ts +66 -0
  48. package/lib/view/expenseAutomationView/transactionFilterHelpers.js +262 -0
  49. package/lib/view/expenseAutomationView/types/transactionsViewState.d.ts +3 -0
  50. package/lib/view/recommendation/fetchEntityRecommendationsForLineUpdateEpic.d.ts +9 -0
  51. package/lib/view/recommendation/fetchEntityRecommendationsForLineUpdateEpic.js +91 -0
  52. package/lib/view/recommendation/recommendationHelper.d.ts +9 -0
  53. package/lib/view/recommendation/recommendationHelper.js +31 -1
  54. package/lib/view/recommendation/recommendationReducer.d.ts +20 -1
  55. package/lib/view/recommendation/recommendationReducer.js +27 -2
  56. package/lib/view/spendManagement/billPay/billList/billListState.d.ts +1 -1
  57. package/lib/view/spendManagement/chargeCards/chargeCardPaymentHistory/chargeCardPaymentHistory.d.ts +1 -1
  58. package/lib/view/spendManagement/reimbursement/remiListView/remiListState.d.ts +1 -1
  59. package/lib/view/spendManagement/spendManagementFilterHelpers.d.ts +12 -3
  60. package/lib/view/spendManagement/spendManagementFilterHelpers.js +4 -2
  61. package/lib/view/subscriptionView/subscriptionViewSelector.js +1 -1
  62. package/lib/view/taskManager/taskListView/taskList.d.ts +1 -1
  63. package/lib/view/taskManager/taskListView/taskListReducer.js +1 -1
  64. package/lib/view/transactionDetail/transactionDetailReducer.d.ts +11 -1
  65. package/lib/view/transactionDetail/transactionDetailReducer.js +122 -7
  66. package/lib/view/transactionDetail/transactionDetailSelector.d.ts +2 -0
  67. package/lib/view/transactionDetail/transactionDetailSelector.js +24 -1
  68. package/lib/view/transactionDetail/transactionDetailTypes.d.ts +1 -0
  69. 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">, 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
+ }, "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>, updateSelectedTransactionId: import("@reduxjs/toolkit").ActionCreatorWithPayload<{
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.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) {
440
+ (0, transactionCategorizationLocalDataHelper_1.shouldAutoSelectAndAdd)(selectedTransaction, newTransactionLocalData, selectedCheckBoxTransactionIds, uncategorizedAccounts, isUncategorizedExpenseCategoryEnabled, isAccountingClassesEnabled)) {
433
441
  draft.transactionCategorizationView[selectedTab].selectedCheckBoxTransactionIds = [
434
- ...draft.transactionCategorizationView[selectedTab]
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: (0, transactionCategorizationLocalDataHelper_1.setEntityRecommendationForLineIdInLocalData)(draft.transactionCategorizationView[selectedTab], transaction, transactionLocalData.transactionReviewLocalData, entity, lineIds, uncategorizedAccounts, action.payload.recommendationWithCOTByLineId, isUncategorizedExpenseCategoryEnabled, isAccountingClassesEnabled),
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.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) {
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.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) {
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 { ExpenseAutomationTransactionViewSelector } from '../selectorTypes/transactionsViewSelectorTypes';
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 transactionLocalData = transactionIds
40
- .map((transactionId) => {
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
- return {
121
+ transactionLocalDataMap.set(transactionId, {
44
122
  transactionId,
45
123
  transactionReviewLocalData: transactionData.transactionReviewLocalData,
46
- };
124
+ });
47
125
  }
48
- return null;
49
- })
50
- .filter((transaction) => transaction != null);
51
- const transactions = (0, transactionSelector_1.getSupportedTransactionsByIds)(transactionState, transactionIds);
52
- const transactionsWithCOT = transactions.map((transaction) => (0, transactionHelper_1.getTransactionWithCOT)(transaction));
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: transactionsWithCOT,
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[];