@zeniai/client-epic-state 5.0.54 → 5.0.55-betaAR2

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 (25) hide show
  1. package/lib/entity/account/accountSelector.d.ts +20 -1
  2. package/lib/entity/account/accountSelector.js +35 -1
  3. package/lib/entity/account/accountState.d.ts +5 -0
  4. package/lib/entity/account/accountState.js +11 -4
  5. package/lib/entity/class/classSelector.d.ts +5 -0
  6. package/lib/entity/class/classSelector.js +8 -0
  7. package/lib/esm/entity/account/accountSelector.js +33 -1
  8. package/lib/esm/entity/account/accountState.js +7 -1
  9. package/lib/esm/entity/class/classSelector.js +7 -0
  10. package/lib/esm/view/expenseAutomationView/reducers/transactionsViewReducer.js +11 -1
  11. package/lib/esm/view/expenseAutomationView/selectors/transactionCategorizationSelector.js +57 -8
  12. package/lib/esm/view/spendManagement/spendManagementFilterHelpers.js +185 -15
  13. package/lib/esm/view/spendManagement/zeniAccounts/depositAccountDetail/depositAccountDetailSelector.js +1 -1
  14. package/lib/esm/view/spendManagement/zeniAccounts/depositAccountDetail/fetchDepositAccountDetailEpic.js +7 -2
  15. package/lib/tsconfig.typecheck.tsbuildinfo +1 -1
  16. package/lib/view/expenseAutomationView/reducers/transactionsViewReducer.d.ts +5 -1
  17. package/lib/view/expenseAutomationView/reducers/transactionsViewReducer.js +12 -2
  18. package/lib/view/expenseAutomationView/selectors/transactionCategorizationSelector.d.ts +4 -1
  19. package/lib/view/expenseAutomationView/selectors/transactionCategorizationSelector.js +59 -8
  20. package/lib/view/expenseAutomationView/types/transactionsViewState.d.ts +2 -0
  21. package/lib/view/spendManagement/spendManagementFilterHelpers.d.ts +45 -4
  22. package/lib/view/spendManagement/spendManagementFilterHelpers.js +186 -16
  23. package/lib/view/spendManagement/zeniAccounts/depositAccountDetail/depositAccountDetailSelector.js +1 -1
  24. package/lib/view/spendManagement/zeniAccounts/depositAccountDetail/fetchDepositAccountDetailEpic.js +7 -2
  25. 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 '../../spendManagement/spendManagementFilterHelpers';
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;
@@ -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.updateTotalCountForTransactionCategorization = exports.setAllItemsToCategoryClassInLocalDataForCategorization = exports.updateSelectedCustomerForTransaction = exports.updateSelectedVendorForTransaction = exports.updateStatusForTransactionNotMiscategorizedUpdateForCategorization = exports.markTransactionAsNotMiscategorized = exports.updateTransactionCategorizationSaveStatus = 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.setEntityRecommendationForLineIdsForCategorization = exports.clearExpenseAutomationTransactionsView = exports.clearExpenseAutomationTransactionsViewPerTabView = exports.updateSelectedCheckboxTransactionIds = exports.fetchTransactionCategorizationView = exports.resetOtherTabsFetchState = exports.fetchTransactionCategorizationSuccess = exports.updateTotalCountForTransactionCategorization = exports.setAllItemsToCategoryClassInLocalDataForCategorization = exports.updateSelectedCustomerForTransaction = exports.updateSelectedVendorForTransaction = exports.updateStatusForTransactionNotMiscategorizedUpdateForCategorization = exports.markTransactionAsNotMiscategorized = exports.updateTransactionCategorizationSaveStatus = 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"));
@@ -34,6 +34,10 @@ exports.initialTransactionTabViewState = {
34
34
  totalCount: {},
35
35
  limit: 10,
36
36
  },
37
+ filters: {
38
+ categoryCombinationOperator: 'AND',
39
+ categories: [],
40
+ },
37
41
  fetchState: 'Not-Started',
38
42
  error: undefined,
39
43
  hasValidState() {
@@ -243,6 +247,12 @@ const expenseAutomationTransactionsView = (0, toolkit_1.createSlice)({
243
247
  uiState.totalCount;
244
248
  }
245
249
  },
250
+ updateTransactionFilters(draft, action) {
251
+ const { selectedTab, filters } = action.payload;
252
+ if (filters != null) {
253
+ draft.transactionCategorizationView[selectedTab].filters = filters;
254
+ }
255
+ },
246
256
  saveTransactionCategorization: {
247
257
  prepare(selectedTab, transactionIds, cotTrackingByTransactionId, isUncategorizedExpenseCategoryEnabled) {
248
258
  return {
@@ -810,5 +820,5 @@ const expenseAutomationTransactionsView = (0, toolkit_1.createSlice)({
810
820
  },
811
821
  },
812
822
  });
813
- _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.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.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;
823
+ _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.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.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;
814
824
  exports.default = expenseAutomationTransactionsView.reducer;
@@ -1,3 +1,6 @@
1
+ import { TransactionWithCOT } from '../../../entity/transaction/stateTypes/transaction';
1
2
  import { RootState } from '../../../reducer';
2
- import { ExpenseAutomationTransactionViewSelector } from '../selectorTypes/transactionsViewSelectorTypes';
3
+ import { TransactionView } from '../../spendManagement/spendManagementFilterHelpers';
4
+ import { ExpenseAutomationTransactionViewSelector, TransactionReviewLocalDataSelectorView } from '../selectorTypes/transactionsViewSelectorTypes';
5
+ export declare const toTransactionView: (transaction: TransactionWithCOT, transactionLocalData?: TransactionReviewLocalDataSelectorView) => TransactionView;
3
6
  export declare function getExpenseAutomationTransactionView(state: RootState): ExpenseAutomationTransactionViewSelector;
@@ -3,6 +3,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
3
3
  return (mod && mod.__esModule) ? mod : { "default": mod };
4
4
  };
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.toTransactionView = void 0;
6
7
  exports.getExpenseAutomationTransactionView = getExpenseAutomationTransactionView;
7
8
  const omit_1 = __importDefault(require("lodash/omit"));
8
9
  const reduceFetchState_1 = require("../../../commonStateTypes/reduceFetchState");
@@ -10,14 +11,34 @@ const timePeriod_1 = require("../../../commonStateTypes/timePeriod");
10
11
  const tenantSelector_1 = require("../../../entity/tenant/tenantSelector");
11
12
  const transactionHelper_1 = require("../../../entity/transaction/transactionHelper");
12
13
  const transactionSelector_1 = require("../../../entity/transaction/transactionSelector");
14
+ const spendManagementFilterHelpers_1 = require("../../spendManagement/spendManagementFilterHelpers");
13
15
  const accountListSelector_1 = require("../../accountList/accountListSelector");
14
16
  const classListSelector_1 = require("../../classList/classListSelector");
15
17
  const projectListSelector_1 = require("../../projectList/projectListSelector");
16
18
  const expenseAutomationViewSelectorTypes_1 = require("../selectorTypes/expenseAutomationViewSelectorTypes");
19
+ const toTransactionView = (transaction, transactionLocalData) => {
20
+ return {
21
+ id: transaction.id,
22
+ date: transaction.date,
23
+ amount: transaction.amount,
24
+ vendorName: transaction.vendorName,
25
+ customerName: transaction.customerName,
26
+ vendorId: transaction.vendorId,
27
+ customerId: transaction.customerId,
28
+ description: transaction.description,
29
+ memo: transaction.memo,
30
+ type: transaction.type,
31
+ typeName: transaction.typeName,
32
+ createTime: transaction.createTime,
33
+ transaction: transaction,
34
+ transactionLocalData,
35
+ };
36
+ };
37
+ exports.toTransactionView = toTransactionView;
17
38
  function getExpenseAutomationTransactionView(state) {
18
39
  const { accountState, classState, classListState, accountListState, expenseAutomationTransactionsViewState, expenseAutomationViewState, projectState, projectListState, transactionState, monthEndCloseChecksState, monthEndCloseChecksViewState, } = state;
19
40
  const { selectedTransactionCategorizationTab } = expenseAutomationTransactionsViewState;
20
- const { uiState, refreshStatus, saveStatus, markAsNotMiscategorizedStatus, transactionIdsBySelectedPeriod, transactionReviewLocalDataById, selectedCheckBoxTransactionIds, transactionIdsWithUnsavedData, uploadReceiptStatusById, selectedTransactionId, selectedTransactionLineId, } = expenseAutomationTransactionsViewState.transactionCategorizationView[selectedTransactionCategorizationTab];
41
+ const { uiState, refreshStatus, saveStatus, markAsNotMiscategorizedStatus, transactionIdsBySelectedPeriod, transactionReviewLocalDataById, selectedCheckBoxTransactionIds, transactionIdsWithUnsavedData, uploadReceiptStatusById, selectedTransactionId, selectedTransactionLineId, filters, } = expenseAutomationTransactionsViewState.transactionCategorizationView[selectedTransactionCategorizationTab];
21
42
  const uncategorizedIncomeExpense = (0, accountListSelector_1.getUncategorizedAccounts)(accountState, accountListState, 'accountList');
22
43
  const accountList = (0, accountListSelector_1.getAccountList)(accountState, accountListState, 'accountList');
23
44
  const classList = (0, classListSelector_1.getClassList)(classState, classListState);
@@ -36,10 +57,42 @@ function getExpenseAutomationTransactionView(state) {
36
57
  ? transactionIdsBySelectedPeriod[monthYearPeriodId]
37
58
  : null;
38
59
  const transactionIds = transactionIdsForSelectedPeriod ?? [];
39
- const transactionLocalData = transactionIds
40
- .map((transactionId) => {
60
+ const transactions = (0, transactionSelector_1.getSupportedTransactionsByIds)(transactionState, transactionIds);
61
+ const transactionsWithCOT = transactions.map((transaction) => (0, transactionHelper_1.getTransactionWithCOT)(transaction));
62
+ const transactionLocalDataMap = new Map();
63
+ transactionIds.forEach((transactionId) => {
41
64
  const transactionData = transactionReviewLocalDataById[transactionId];
42
65
  if (transactionData != null) {
66
+ transactionLocalDataMap.set(transactionId, {
67
+ transactionId,
68
+ transactionReviewLocalData: transactionData.transactionReviewLocalData,
69
+ });
70
+ }
71
+ });
72
+ // Step 2: Convert to TransactionView and apply advanced filters
73
+ const transactionViews = transactionsWithCOT.map((transaction) => {
74
+ const localData = transactionLocalDataMap.get(transaction.id);
75
+ return (0, exports.toTransactionView)(transaction, localData);
76
+ });
77
+ // Apply advanced filters if they exist
78
+ const filteredTransactionViews = (0, spendManagementFilterHelpers_1.applyAdvancedFiltersOnList)('transaction_categorization', transactionViews, filters);
79
+ // Convert back to TransactionWithCOT for return
80
+ const filteredTransactionsWithCOT = filteredTransactionViews.map((view) => view.transaction);
81
+ // Get transactionLocalData for filtered transactions
82
+ // Also include transactionLocalData for transactions that don't exist in transactionState
83
+ // but have local data (to match original behavior)
84
+ const filteredTransactionIds = new Set(filteredTransactionViews.map((view) => view.id));
85
+ const filteredTransactionLocalData = transactionIds
86
+ .map((transactionId) => {
87
+ const transactionData = transactionReviewLocalDataById[transactionId];
88
+ if (transactionData == null) {
89
+ return null;
90
+ }
91
+ // Include if transaction is in filtered results, or if transaction doesn't exist in state
92
+ // (to maintain backward compatibility with tests)
93
+ const transactionExists = transactions.some((t) => t.id === transactionId);
94
+ if (filteredTransactionIds.has(transactionId) ||
95
+ !transactionExists) {
43
96
  return {
44
97
  transactionId,
45
98
  transactionReviewLocalData: transactionData.transactionReviewLocalData,
@@ -47,9 +100,7 @@ function getExpenseAutomationTransactionView(state) {
47
100
  }
48
101
  return null;
49
102
  })
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));
103
+ .filter((data) => data != null);
53
104
  const monthEndFetchState = monthYearPeriodId != null
54
105
  ? (monthEndCloseChecksViewState.monthEndCloseChecksViewByTenantId[currentTenant.tenantId]?.[monthYearPeriodId] ?? { fetchState: 'Not-Started', error: undefined })
55
106
  : { fetchState: 'Not-Started', error: undefined };
@@ -96,7 +147,7 @@ function getExpenseAutomationTransactionView(state) {
96
147
  version: 0,
97
148
  fetchState: fetchStatus.fetchState,
98
149
  error: fetchStatus.error,
99
- transactions: transactionsWithCOT,
150
+ transactions: filteredTransactionsWithCOT,
100
151
  selectedCheckBoxTransactionIds,
101
152
  transactionIdsWithUnsavedData,
102
153
  uncategorizedAccounts: uncategorizedIncomeExpense,
@@ -107,7 +158,7 @@ function getExpenseAutomationTransactionView(state) {
107
158
  classHierarchyList,
108
159
  isAccountingProjectsEnabled,
109
160
  projectList,
110
- transactionLocalData,
161
+ transactionLocalData: filteredTransactionLocalData,
111
162
  uiState,
112
163
  refreshStatus,
113
164
  saveStatus,
@@ -15,6 +15,7 @@ import { TransactionCategory, TransactionType } from '../../../entity/transactio
15
15
  import { VendorBase } from '../../../entity/vendor/vendorState';
16
16
  import { ZeniDate } from '../../../zeniDayJS';
17
17
  import { EntityRecommendationKey } from '../../recommendation/recommendationState';
18
+ import { TransactionFilters } from '../../spendManagement/spendManagementFilterHelpers';
18
19
  import { TransactionDetailKey } from '../../transactionDetail/transactionDetailState';
19
20
  export declare const toTransactionsSortKey: (v: string) => "date" | "amount" | "vendor" | "project" | "category" | "class" | "payment_account" | "transaction_type" | "memo_and_receipt";
20
21
  export type TransactionsSortKey = ReturnType<typeof toTransactionsSortKey>;
@@ -91,6 +92,7 @@ export interface SupportedTransactionCategorization {
91
92
  }
92
93
  export declare const initialSupportedTransactionCategorization: SupportedTransactionCategorization;
93
94
  export interface TransactionsTabViewState extends FetchedState {
95
+ filters: TransactionFilters;
94
96
  markAsNotMiscategorizedStatus: FetchStateAndError;
95
97
  refreshStatus: FetchStateAndError;
96
98
  saveStatus: FetchStateAndError;
@@ -1,7 +1,12 @@
1
+ import { Amount } from '../../commonStateTypes/amount';
2
+ import { ID } from '../../commonStateTypes/common';
1
3
  import { TimePeriod } from '../../commonStateTypes/timePeriod';
4
+ import { TransactionType } from '../../entity/transaction/stateTypes/transactionType';
5
+ import { SupportedTransactionWithCOT } from '../../entity/transaction/transactionState';
2
6
  import { UserRoleType } from '../../entity/userRole/userRoleType';
3
7
  import { RootState } from '../../reducer';
4
8
  import { ZeniDate } from '../../zeniDayJS';
9
+ import { TransactionReviewLocalDataSelectorView } from '../expenseAutomationView/selectorTypes/transactionsViewSelectorTypes';
5
10
  import { TaskListFilterCategoryField, TaskListFilters } from '../taskManager/taskListView/taskList';
6
11
  import { TaskWithUserDetails } from '../taskManager/taskListView/taskListSelector';
7
12
  import { BillTransactionView } from './billPay/billList/billListSelector';
@@ -10,8 +15,8 @@ import { PaymentHistoryFilterCategoryDropdownOption, PaymentHistoryFilters } fro
10
15
  import { ChargeCardRepaymentWithUser } from './chargeCards/chargeCardPaymentHistory/chargeCardPaymentHistorySelector';
11
16
  import { ReimbursementView } from './reimbursement/remiListView/remiListSelector';
12
17
  import { ReimbursementFilters, RemiListViewFilterCategoryField } from './reimbursement/remiListView/remiListState';
13
- export type SpendManagementFiltersType = BillPayFilters | ReimbursementFilters | TaskListFilters | PaymentHistoryFilters;
14
- export type SpendManagementFilterEntityType = 'bill_pay' | 'reimbursement' | 'task_management' | 'charge_card_payment_history';
18
+ export type SpendManagementFiltersType = BillPayFilters | ReimbursementFilters | TaskListFilters | TransactionFilters | PaymentHistoryFilters;
19
+ export type SpendManagementFilterEntityType = 'bill_pay' | 'reimbursement' | 'task_management' | 'transaction_categorization' | 'charge_card_payment_history';
15
20
  export type FilterCategoryType = 'searchAutocomplete' | 'user' | 'dateRange' | 'numberRange' | 'dropdown';
16
21
  export interface MatchingOperatorDropdownOption {
17
22
  label: 'is' | 'is not';
@@ -33,9 +38,45 @@ export interface TaskFilterCategoryDropdownOption {
33
38
  multiple?: boolean;
34
39
  type?: FilterCategoryType;
35
40
  }
36
- export type SpendManagementFilterCategoryDropdownOption = BillPayFilterCategoryDropdownOption | ReimbursementFilterCategoryDropdownOption | TaskFilterCategoryDropdownOption | PaymentHistoryFilterCategoryDropdownOption;
41
+ export type SpendManagementFilterCategoryDropdownOption = BillPayFilterCategoryDropdownOption | ReimbursementFilterCategoryDropdownOption | TaskFilterCategoryDropdownOption | TransactionFilterCategoryDropdownOption | PaymentHistoryFilterCategoryDropdownOption;
42
+ export interface TransactionFilterCategoryDropdownOption {
43
+ value: TransactionFilterCategoryField;
44
+ multiple?: boolean;
45
+ type?: FilterCategoryType;
46
+ }
47
+ export type TransactionFilterEntityType = 'transaction_categorization' | 'customer' | 'vendor' | 'merchant';
48
+ export type TransactionFilterCategoryField = 'payment_account_name' | 'payment_account_type' | 'payee' | 'category' | 'class' | 'amount';
49
+ export declare const TRANSACTION_FILTER_CATEGORIES: TransactionFilterCategoryDropdownOption[];
50
+ export interface TransactionFilters {
51
+ categories: TransactionFilterCategory[];
52
+ categoryCombinationOperator: CategoryCombinationOperator;
53
+ }
54
+ /** Amount filter operators for transaction_categorization (expense automation). Other entities use only equal/not-equal. */
55
+ export type TransactionFilterAmountMatchingOperator = 'equal' | 'not-equal' | 'lessThan' | 'greaterThan' | 'inBetween';
56
+ export interface TransactionFilterCategory {
57
+ field: TransactionFilterCategoryField;
58
+ matchingOperator: TransactionFilterAmountMatchingOperator;
59
+ values: (string | ZeniDate)[];
60
+ valuesCombinationOperator: 'ANY';
61
+ }
62
+ export interface TransactionView {
63
+ amount: Amount;
64
+ createTime: ZeniDate;
65
+ date: ZeniDate;
66
+ description: string;
67
+ id: ID;
68
+ memo: string;
69
+ transaction: SupportedTransactionWithCOT;
70
+ type: TransactionType;
71
+ customerId?: ID;
72
+ customerName?: string;
73
+ transactionLocalData?: TransactionReviewLocalDataSelectorView;
74
+ typeName?: string;
75
+ vendorId?: ID;
76
+ vendorName?: string;
77
+ }
37
78
  export type FilterCategoryValueType = string | number | ZeniDate;
38
- export declare const applyAdvancedFiltersOnList: (entity: SpendManagementFilterEntityType, allItems: BillTransactionView[] | ReimbursementView[] | TaskWithUserDetails[] | ChargeCardRepaymentWithUser[], filters?: BillPayFilters | ReimbursementFilters | TaskListFilters | PaymentHistoryFilters, filteredItems?: (BillTransactionView | ReimbursementView | TaskWithUserDetails | ChargeCardRepaymentWithUser)[], index?: number) => (BillTransactionView | ReimbursementView | TaskWithUserDetails | ChargeCardRepaymentWithUser)[];
79
+ export declare const applyAdvancedFiltersOnList: (entity: SpendManagementFilterEntityType, allItems: BillTransactionView[] | ReimbursementView[] | TaskWithUserDetails[] | TransactionView[] | ChargeCardRepaymentWithUser[], filters?: BillPayFilters | ReimbursementFilters | TaskListFilters | TransactionFilters | PaymentHistoryFilters, filteredItems?: (BillTransactionView | ReimbursementView | TaskWithUserDetails | TransactionView | ChargeCardRepaymentWithUser)[], index?: number) => (BillTransactionView | ReimbursementView | TaskWithUserDetails | TransactionView | ChargeCardRepaymentWithUser)[];
39
80
  export declare const isBillListDownloadable: (state: RootState, currentTimePeriod: TimePeriod) => boolean;
40
81
  export declare const isRemiListDownloadable: (state: RootState, currentTimePeriod: TimePeriod) => boolean;
41
82
  export declare const hideCreatedByFilter: (userRole: UserRoleType[]) => boolean;
@@ -3,7 +3,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
3
3
  return (mod && mod.__esModule) ? mod : { "default": mod };
4
4
  };
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
- exports.hideCreatedByFilter = exports.isRemiListDownloadable = exports.isBillListDownloadable = exports.applyAdvancedFiltersOnList = void 0;
6
+ exports.hideCreatedByFilter = exports.isRemiListDownloadable = exports.isBillListDownloadable = exports.applyAdvancedFiltersOnList = exports.TRANSACTION_FILTER_CATEGORIES = void 0;
7
7
  const get_1 = __importDefault(require("lodash/get"));
8
8
  const userSelector_1 = require("../../entity/user/userSelector");
9
9
  const userRoleType_1 = require("../../entity/userRole/userRoleType");
@@ -13,28 +13,81 @@ const billListState_1 = require("./billPay/billList/billListState");
13
13
  const helpers_1 = require("./helpers");
14
14
  const remiListSelector_1 = require("./reimbursement/remiListView/remiListSelector");
15
15
  const remiListState_1 = require("./reimbursement/remiListView/remiListState");
16
+ exports.TRANSACTION_FILTER_CATEGORIES = [
17
+ { value: 'payment_account_name', type: 'dropdown' },
18
+ { value: 'payment_account_type', type: 'dropdown' },
19
+ { value: 'payee', type: 'searchAutocomplete' },
20
+ { value: 'category', type: 'dropdown' },
21
+ { value: 'class', type: 'dropdown' },
22
+ { value: 'amount', type: 'numberRange' },
23
+ ];
16
24
  //filters items against filter values representing a range. ex: date (from-to), amount(1k<-->5k)
25
+ // For amount: supports new transaction_categorization operators (inBetween, lessThan, greaterThan) and
26
+ // backward compatibility for old format values: ["1000<->5000"] with matchingOperator "equal".
27
+ // Other entities (bill_pay, reimbursement, etc.) use only equal/not-equal and are unchanged.
17
28
  const filterItemOnRangeCategoryType = (valueForItem, currentFilter) => {
18
29
  let doesItemFallInValueRange = false;
19
30
  const filterField = currentFilter.field;
20
31
  if (filterField === 'amount') {
21
- for (const filterValue of currentFilter.values) {
22
- const currentValue = parseInt(valueForItem.toString());
23
- const lowerValue = parseInt(filterValue?.toString()?.split('<->')[0] ?? '');
24
- const higherValue = parseInt(filterValue?.toString()?.split('<->')[1] ?? '');
25
- if (currentValue >= lowerValue && currentValue <= higherValue) {
26
- doesItemFallInValueRange = true;
32
+ const currentValue = Number(valueForItem);
33
+ const op = currentFilter.matchingOperator;
34
+ const values = currentFilter.values;
35
+ if (op === 'inBetween') {
36
+ // New format: values = [min, max] (expense automation transaction_categorization only)
37
+ if (values.length >= 2) {
38
+ const min = Number(values[0]);
39
+ const max = Number(values[1]);
40
+ doesItemFallInValueRange = currentValue >= min && currentValue <= max;
27
41
  }
28
42
  }
29
- }
30
- else {
31
- const currentValue = valueForItem;
32
- const lowerValue = currentFilter.values[0];
33
- const higherValue = currentFilter.values[1];
34
- if (currentValue.isSameOrAfter(lowerValue) &&
35
- currentValue.isSameOrBefore(higherValue)) {
36
- doesItemFallInValueRange = true;
43
+ else if (op === 'lessThan') {
44
+ if (values.length >= 1) {
45
+ const threshold = Number(values[0]);
46
+ doesItemFallInValueRange = currentValue < threshold;
47
+ }
48
+ }
49
+ else if (op === 'greaterThan') {
50
+ if (values.length >= 1) {
51
+ const threshold = Number(values[0]);
52
+ doesItemFallInValueRange = currentValue > threshold;
53
+ }
54
+ }
55
+ else if (op === 'equal' &&
56
+ values.length === 1 &&
57
+ String(values[0]).includes('<->')) {
58
+ // Backward compatibility: old format ["1000<->5000"] with matchingOperator "equal"
59
+ const parts = String(values[0]).split('<->');
60
+ const lowerValue = Number(parts[0] ?? '');
61
+ const higherValue = Number(parts[1] ?? '');
62
+ doesItemFallInValueRange =
63
+ currentValue >= lowerValue && currentValue <= higherValue;
64
+ }
65
+ else if (op === 'equal' && values.length === 1) {
66
+ // New format: exact match on single value (expense automation)
67
+ const val = Number(values[0]);
68
+ doesItemFallInValueRange = currentValue === val;
69
+ }
70
+ else {
71
+ // Existing logic for equal/not-equal (bill_pay, reimbursement, etc. or multiple range values)
72
+ for (const filterValue of values) {
73
+ const lowerValue = Number.parseInt(filterValue?.toString()?.split('<->')[0] ?? '', 10);
74
+ const higherValue = Number.parseInt(filterValue?.toString()?.split('<->')[1] ?? '', 10);
75
+ if (currentValue >= lowerValue && currentValue <= higherValue) {
76
+ doesItemFallInValueRange = true;
77
+ }
78
+ }
37
79
  }
80
+ return op === 'not-equal'
81
+ ? !doesItemFallInValueRange
82
+ : doesItemFallInValueRange;
83
+ }
84
+ // Date range and other range fields (unchanged for other entities)
85
+ const currentValue = valueForItem;
86
+ const lowerValue = currentFilter.values[0];
87
+ const higherValue = currentFilter.values[1];
88
+ if (currentValue.isSameOrAfter(lowerValue) &&
89
+ currentValue.isSameOrBefore(higherValue)) {
90
+ doesItemFallInValueRange = true;
38
91
  }
39
92
  return currentFilter.matchingOperator === 'equal'
40
93
  ? doesItemFallInValueRange
@@ -119,7 +172,11 @@ const applyAdvancedFiltersOnList = (entity, allItems, filters, filteredItems = [
119
172
  ? getCategoryValueForReimbursement(key, item)
120
173
  : entity === 'task_management'
121
174
  ? getCategoryValueForTaskList(key, item)
122
- : getCategoryValueForPaymentHistory(key, item);
175
+ : entity === 'transaction_categorization'
176
+ ? getCategoryValueForTransaction(key, item)
177
+ : entity === 'charge_card_payment_history'
178
+ ? getCategoryValueForPaymentHistory(key, item)
179
+ : undefined;
123
180
  if (categoryValue == null) {
124
181
  if (currentFilter.matchingOperator === 'not-equal') {
125
182
  return true;
@@ -241,6 +298,119 @@ const getCategoryValueForReimbursement = (key, reimbursement) => {
241
298
  return undefined;
242
299
  }
243
300
  };
301
+ const getCategoryValueForTransaction = (key, transaction) => {
302
+ switch (key) {
303
+ case 'amount': {
304
+ // Get from transactionLocalData line items (preferred) - sum all line item amounts
305
+ const localDataForAmount = transaction.transactionLocalData?.transactionReviewLocalData;
306
+ if (localDataForAmount?.lineItemById) {
307
+ const lineItems = Object.values(localDataForAmount.lineItemById);
308
+ if (lineItems.length > 0) {
309
+ // Sum all line item amounts
310
+ const totalAmount = lineItems.reduce((sum, lineItem) => sum + (lineItem.amount?.amount ?? 0), 0);
311
+ return totalAmount;
312
+ }
313
+ }
314
+ // Fallback to transaction-level amount or sum from transaction lines
315
+ if (transaction.transaction.lines &&
316
+ transaction.transaction.lines.length > 0) {
317
+ const totalAmount = transaction.transaction.lines.reduce((sum, line) => sum + (line.amount?.amount ?? 0), 0);
318
+ return totalAmount;
319
+ }
320
+ // Final fallback to transaction amount
321
+ return transaction.amount.amount;
322
+ }
323
+ case 'payee': {
324
+ // Priority: vendorName > customerName > from transactionLocalData
325
+ if (transaction.vendorName) {
326
+ return transaction.vendorName;
327
+ }
328
+ if (transaction.customerName) {
329
+ return transaction.customerName;
330
+ }
331
+ // Check transactionLocalData for vendor/customer
332
+ const localData = transaction.transactionLocalData?.transactionReviewLocalData;
333
+ if (localData?.vendor?.name) {
334
+ return localData.vendor.name;
335
+ }
336
+ if (localData?.customer?.name) {
337
+ return localData.customer.name;
338
+ }
339
+ return undefined;
340
+ }
341
+ case 'payment_account_name': {
342
+ // Match the value the row renders: TransactionCategorizationListRow reads
343
+ // `currentTransaction?.account?.accountName` for the Payment Account Name
344
+ // column. Returning the same field here keeps filter-match parity with the
345
+ // visible cell, so any row a user can see is also a row the filter can match.
346
+ return transaction.transaction.account?.accountName;
347
+ }
348
+ case 'payment_account_type': {
349
+ // Compare against the raw `paymentType` enum (e.g. "credit_card", "check",
350
+ // "cash"). The same enum is what TransactionCategorizationListRow uses for
351
+ // its icon switch on line ~1675, and it's what the dropdown options emit
352
+ // as `value`. Display labels come from each account's `paymentTypeName`
353
+ // field (populated by mapAccountBasePayloadToAccountBase from the backend
354
+ // payload) — no client-side label map required.
355
+ return transaction.transaction.paymentType;
356
+ }
357
+ case 'category': {
358
+ // Get from transactionLocalData (preferred) or from transaction lines
359
+ const localDataForCategory = transaction.transactionLocalData?.transactionReviewLocalData;
360
+ if (localDataForCategory) {
361
+ // Get category from first line item or most common
362
+ const firstLineItem = Object.values(localDataForCategory.lineItemById)[0];
363
+ if (firstLineItem?.account?.accountId) {
364
+ return firstLineItem.account.accountId;
365
+ }
366
+ if (firstLineItem?.account?.qboId) {
367
+ return firstLineItem.account.qboId;
368
+ }
369
+ if (firstLineItem?.account?.accountName) {
370
+ return firstLineItem.account.accountName;
371
+ }
372
+ }
373
+ // Fallback to transaction lines
374
+ const firstLineForCategory = transaction.transaction.lines?.[0];
375
+ if (firstLineForCategory?.type ===
376
+ 'transaction_with_account_and_class_line' ||
377
+ firstLineForCategory?.type ===
378
+ 'transaction_with_product_or_service_line' ||
379
+ firstLineForCategory?.type === 'journal_entry_transaction_line') {
380
+ const account = firstLineForCategory.account;
381
+ return account?.accountId ?? account?.qboId ?? account?.accountName;
382
+ }
383
+ return undefined;
384
+ }
385
+ case 'class': {
386
+ // Similar to category but for class
387
+ const localDataForClass = transaction.transactionLocalData?.transactionReviewLocalData;
388
+ if (localDataForClass) {
389
+ const firstLineItemForClass = Object.values(localDataForClass.lineItemById)[0];
390
+ if (firstLineItemForClass?.class?.classId) {
391
+ return firstLineItemForClass.class.classId;
392
+ }
393
+ if (firstLineItemForClass?.class?.qboId) {
394
+ return firstLineItemForClass.class.qboId;
395
+ }
396
+ if (firstLineItemForClass?.class?.className) {
397
+ return firstLineItemForClass.class.className;
398
+ }
399
+ }
400
+ const firstLineForClass = transaction.transaction.lines?.[0];
401
+ if (firstLineForClass?.type === 'transaction_with_account_and_class_line' ||
402
+ firstLineForClass?.type ===
403
+ 'transaction_with_product_or_service_line' ||
404
+ firstLineForClass?.type === 'journal_entry_transaction_line') {
405
+ const classData = firstLineForClass.class;
406
+ return classData?.classId ?? classData?.qboId ?? classData?.className;
407
+ }
408
+ return undefined;
409
+ }
410
+ default:
411
+ return undefined;
412
+ }
413
+ };
244
414
  const getCategoryValueForPaymentHistory = (key, repayment) => {
245
415
  switch (key) {
246
416
  case 'repaymentDate':
@@ -34,7 +34,7 @@ const getDepositAccountDetail = (state, depositAccountId) => {
34
34
  const zeniAccountDetail = zeniAccountDetailState.depositAccountDetailById[depositAccountId];
35
35
  const depositAccount = (0, depositAccountSelector_1.getDepositAccountByDepositAccountId)(depositAccountState, depositAccountId);
36
36
  const zeniAccountsConfig = (0, zeniAccountsConfigSelector_1.getZeniAccountsConfigDetail)(state);
37
- const transactionListView = (0, depositAccountTransactionListSelector_1.getDepositAccountTransactionList)(state, depositAccountId, 5);
37
+ const transactionListView = (0, depositAccountTransactionListSelector_1.getDepositAccountTransactionList)(state, depositAccountId);
38
38
  let accountUpdateStatus = {
39
39
  editName: {
40
40
  fetchState: 'Not-Started',
@@ -19,7 +19,7 @@ const fetchDepositAccountDetailEpic = (actions$, state$) => actions$.pipe((0, op
19
19
  zeniAccountActions.push((0, paymentAccountListReducer_1.fetchPaymentAccountList)());
20
20
  zeniAccountActions.push((0, zeniAccountsConfigReducer_1.fetchZeniAccountsConfig)());
21
21
  zeniAccountActions.push((0, depositAccountDetailReducer_1.fetchDepositAccount)(depositAccountId));
22
- zeniAccountActions.push((0, depositAccountTransactionListReducer_1.fetchDepositAccountTransactionList)(depositAccountId, true, 5));
22
+ zeniAccountActions.push((0, depositAccountTransactionListReducer_1.fetchDepositAccountTransactionList)(depositAccountId, true));
23
23
  zeniAccountActions.push((0, depositAccountDetailReducer_1.fetchAccountHistory)(depositAccountId));
24
24
  }
25
25
  else {
@@ -40,7 +40,12 @@ const fetchDepositAccountDetailEpic = (actions$, state$) => actions$.pipe((0, op
40
40
  targetZeniAccountAccount.fetchState !== 'In-Progress')) {
41
41
  zeniAccountActions.push((0, depositAccountDetailReducer_1.fetchDepositAccount)(depositAccountId));
42
42
  }
43
- zeniAccountActions.push((0, depositAccountTransactionListReducer_1.fetchDepositAccountTransactionList)(depositAccountId, false, 5));
43
+ const transactionList = state.depositAccountTransactionListState.byDepositId[depositAccountId];
44
+ if (transactionList == null ||
45
+ (transactionList.fetchState !== 'Completed' &&
46
+ transactionList.fetchState !== 'In-Progress')) {
47
+ zeniAccountActions.push((0, depositAccountTransactionListReducer_1.fetchDepositAccountTransactionList)(depositAccountId, false));
48
+ }
44
49
  const zeniAccountsConfig = state.zeniAccountsConfigState;
45
50
  if (zeniAccountsConfig.hasValidState() === false &&
46
51
  zeniAccountsConfig.fetchState !== 'In-Progress') {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zeniai/client-epic-state",
3
- "version": "5.0.54",
3
+ "version": "5.0.55-betaAR2",
4
4
  "description": "Shared module between Web & Mobile containing required abstractions for state management, async network communication. ",
5
5
  "main": "lib/index.js",
6
6
  "module": "lib/esm/index.js",