@zeniai/client-epic-state 5.0.55-betaAR1 → 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 (46) 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/approvalRule/approvalRulePayload.d.ts +5 -27
  6. package/lib/entity/approvalRule/approvalRulePayload.js +10 -131
  7. package/lib/entity/approvalRule/approvalRuleSelector.d.ts +1 -25
  8. package/lib/entity/approvalRule/approvalRuleSelector.js +0 -40
  9. package/lib/entity/approvalRule/approvalRuleState.d.ts +7 -48
  10. package/lib/entity/class/classSelector.d.ts +5 -0
  11. package/lib/entity/class/classSelector.js +8 -0
  12. package/lib/esm/entity/account/accountSelector.js +33 -1
  13. package/lib/esm/entity/account/accountState.js +7 -1
  14. package/lib/esm/entity/approvalRule/approvalRulePayload.js +10 -131
  15. package/lib/esm/entity/approvalRule/approvalRuleSelector.js +0 -35
  16. package/lib/esm/entity/class/classSelector.js +7 -0
  17. package/lib/esm/index.js +1 -2
  18. package/lib/esm/view/expenseAutomationView/reducers/transactionsViewReducer.js +11 -1
  19. package/lib/esm/view/expenseAutomationView/selectors/transactionCategorizationSelector.js +57 -8
  20. package/lib/esm/view/spendManagement/billPay/billPaySetupApproverView/epic/initializeBillPaySetupApproverViewUpdateDataEpic.js +7 -5
  21. package/lib/esm/view/spendManagement/billPay/billPaySetupApproverView/types/commonPayload.js +16 -46
  22. package/lib/esm/view/spendManagement/billPay/editBillView/editBillViewSelector.js +2 -7
  23. package/lib/esm/view/spendManagement/reimbursement/remiSetupApproverView/epic/initializeRemiSetupApproverViewUpdateDataEpic.js +7 -5
  24. package/lib/esm/view/spendManagement/spendManagementFilterHelpers.js +185 -15
  25. package/lib/index.d.ts +2 -3
  26. package/lib/index.js +16 -22
  27. package/lib/tsconfig.typecheck.tsbuildinfo +1 -1
  28. package/lib/view/companyTaskManagerView/companyTaskManagerViewReducer.d.ts +2 -2
  29. package/lib/view/companyView/types/cockpitTypes.d.ts +1 -1
  30. package/lib/view/expenseAutomationView/reducers/transactionsViewReducer.d.ts +5 -1
  31. package/lib/view/expenseAutomationView/reducers/transactionsViewReducer.js +12 -2
  32. package/lib/view/expenseAutomationView/selectors/transactionCategorizationSelector.d.ts +4 -1
  33. package/lib/view/expenseAutomationView/selectors/transactionCategorizationSelector.js +59 -8
  34. package/lib/view/expenseAutomationView/types/transactionsViewState.d.ts +2 -0
  35. package/lib/view/people/peopleTypes.d.ts +1 -1
  36. package/lib/view/spendManagement/billPay/billPaySetupApproverView/epic/initializeBillPaySetupApproverViewUpdateDataEpic.js +6 -4
  37. package/lib/view/spendManagement/billPay/billPaySetupApproverView/types/commonPayload.d.ts +1 -1
  38. package/lib/view/spendManagement/billPay/billPaySetupApproverView/types/commonPayload.js +16 -46
  39. package/lib/view/spendManagement/billPay/billPaySetupApproverView/types/commonState.d.ts +3 -15
  40. package/lib/view/spendManagement/billPay/editBillView/editBillViewSelector.js +2 -7
  41. package/lib/view/spendManagement/chargeCards/chargeCardList/chargeCardList.d.ts +1 -1
  42. package/lib/view/spendManagement/reimbursement/remiSetupApproverView/epic/initializeRemiSetupApproverViewUpdateDataEpic.js +6 -4
  43. package/lib/view/spendManagement/spendManagementFilterHelpers.d.ts +45 -4
  44. package/lib/view/spendManagement/spendManagementFilterHelpers.js +186 -16
  45. package/lib/view/taskManager/taskListView/taskList.d.ts +3 -3
  46. package/package.json +1 -1
@@ -14,139 +14,18 @@ export const toApprovalRule = (payload) => ({
14
14
  version: payload.version,
15
15
  criteria: toApprovalCriteria(payload.criteria),
16
16
  steps: toApprovalSteps(payload.steps),
17
- description: payload.description ?? undefined,
18
- priority: payload.priority,
19
- isFallback: payload.is_fallback ?? false,
20
- // separationOfDuties: backend doesn't ship this field yet; left undefined
21
- // until the spec is finalized.
22
- areApprovalsSerialized: payload.are_approvals_serialized,
23
- pendingApprovalsCount: payload.pending_approvals_count,
24
- pendingEntityApprovalUpdateStatus: payload.pending_entity_approval_update_status,
25
17
  });
26
- /**
27
- * Maps the wire-level criteria block into the state-side discriminated
28
- * `Criteria[]` union.
29
- *
30
- * The wire keeps each condition as a flat row inside `conditions[]`.
31
- * Amount comparisons can show up as a `gte` only, a `lte` only, or a
32
- * `gte` + `lte` pair — those collapse into a single AmountCriteria whose
33
- * `comparator` is `greater_than`, `less_than`, or `range` respectively.
34
- *
35
- * Vendor and department conditions map one-to-one: `in` becomes `is`,
36
- * `not_in` becomes `is_not`.
37
- *
38
- * Resilient to two forms of upstream drift:
39
- * - Missing / null criteria → returns [].
40
- * - Legacy criteria shape (array of amount-range objects, the pre-3.0
41
- * wire) → converted to an AmountCriteria so existing rules in production
42
- * still render while the backend rolls out.
43
- */
44
18
  const toApprovalCriteria = (payload) => {
45
- if (payload == null) {
46
- return [];
47
- }
48
- if (Array.isArray(payload)) {
49
- // Legacy pre-3.0 wire: an array of amount-range entries.
50
- return legacyAmountRangeToCriteria(payload);
51
- }
52
- if (!Array.isArray(payload.conditions)) {
53
- return [];
54
- }
55
- const results = [];
56
- const amountCriteria = toAmountCriteria(payload);
57
- if (amountCriteria != null) {
58
- results.push(amountCriteria);
59
- }
60
- payload.conditions
61
- .filter((condition) => condition.field === 'vendor_id')
62
- .forEach((condition) => {
63
- const vendor = toVendorCriteria(condition);
64
- if (vendor != null) {
65
- results.push(vendor);
66
- }
67
- });
68
- payload.conditions
69
- .filter((condition) => condition.field === 'department_id')
70
- .forEach((condition) => {
71
- const department = toDepartmentCriteria(condition);
72
- if (department != null) {
73
- results.push(department);
74
- }
75
- });
76
- return results;
77
- };
78
- const legacyAmountRangeToCriteria = (legacy) => {
79
- if (legacy.length === 0) {
80
- return [];
81
- }
82
- const first = legacy[0] ?? {};
83
- const currency = first.currency_code ?? 'USD';
84
- const symbol = first.currency_symbol ?? '$';
85
- const min = typeof first.min === 'number'
86
- ? toAmount(first.min, currency, symbol)
87
- : undefined;
88
- const max = typeof first.max === 'number'
89
- ? toAmount(first.max, currency, symbol)
90
- : undefined;
91
- if (min == null && max == null) {
92
- return [];
93
- }
94
- const comparator = min != null && max != null
95
- ? 'range'
96
- : min != null
97
- ? 'greater_than'
98
- : 'less_than';
99
- return [{ type: 'amount', comparator, min, max }];
100
- };
101
- const toAmountCriteria = (payload) => {
102
- if (!Array.isArray(payload.conditions)) {
103
- return undefined;
104
- }
105
- const amountConditions = payload.conditions.filter((condition) => condition.field === 'amount');
106
- const gteCondition = amountConditions.find((condition) => condition.type === 'gte' || condition.type === 'eq');
107
- const lteCondition = amountConditions.find((condition) => condition.type === 'lte');
108
- if (gteCondition == null && lteCondition == null) {
109
- return undefined;
110
- }
111
- const currencyCode = payload.currency_code ?? 'USD';
112
- const currencySymbol = payload.currency_symbol ?? '$';
113
- const min = typeof gteCondition?.value === 'number'
114
- ? toAmount(gteCondition.value, currencyCode, currencySymbol)
115
- : undefined;
116
- const max = typeof lteCondition?.value === 'number'
117
- ? toAmount(lteCondition.value, currencyCode, currencySymbol)
118
- : undefined;
119
- let comparator;
120
- if (min != null && max != null) {
121
- comparator = 'range';
122
- }
123
- else if (min != null) {
124
- comparator = 'greater_than';
125
- }
126
- else {
127
- comparator = 'less_than';
128
- }
129
- return { type: 'amount', comparator, min, max };
130
- };
131
- const toVendorCriteria = (condition) => {
132
- if (!Array.isArray(condition.value)) {
133
- return undefined;
134
- }
135
- return {
136
- type: 'vendor',
137
- operator: condition.type === 'not_in' ? 'is_not' : 'is',
138
- vendorIds: condition.value,
139
- };
140
- };
141
- const toDepartmentCriteria = (condition) => {
142
- if (!Array.isArray(condition.value)) {
143
- return undefined;
144
- }
145
- return {
146
- type: 'department',
147
- operator: condition.type === 'not_in' ? 'is_not' : 'is',
148
- departmentIds: condition.value,
149
- };
19
+ return payload.map((criteria) => ({
20
+ rangeType: criteria.type,
21
+ rangeEntity: criteria.range_entity,
22
+ range: {
23
+ min: toAmount(criteria.min, criteria.currency_code, criteria.currency_symbol),
24
+ max: criteria.max != null
25
+ ? toAmount(criteria.max, criteria.currency_code, criteria.currency_symbol)
26
+ : undefined,
27
+ },
28
+ }));
150
29
  };
151
30
  const toApprovalSteps = (payload) => {
152
31
  return payload.map((step) => ({
@@ -7,38 +7,3 @@ export function getApprovalRulesByIds(approvalRuleState, approvalRuleIds) {
7
7
  .filter((value) => value != null);
8
8
  return approvalRulesByIds;
9
9
  }
10
- /**
11
- * Returns the amount-range portion of a rule's criteria, if any.
12
- *
13
- * Use this whenever a caller needs to read amount min/max from the new
14
- * discriminated `Criteria` union without inlining a type guard.
15
- */
16
- export function getAmountCriteria(criteria) {
17
- return criteria.find((c) => c.type === 'amount');
18
- }
19
- export function getVendorCriteria(criteria) {
20
- return criteria.find((c) => c.type === 'vendor');
21
- }
22
- export function getDepartmentCriteria(criteria) {
23
- return criteria.find((c) => c.type === 'department');
24
- }
25
- /**
26
- * Returns all rules of the given entityType, sorted by `priority` ascending.
27
- *
28
- * Rules without a `priority` value sort to the end (treated as Infinity).
29
- * Use this for the list page where rules render in evaluation order.
30
- */
31
- export function getApprovalRulesByEntityType(approvalRuleState, entityType) {
32
- return Object.values(approvalRuleState.approvalRuleById)
33
- .filter((rule) => rule.entityType === entityType)
34
- .sort((a, b) => (a.priority ?? Infinity) - (b.priority ?? Infinity));
35
- }
36
- /**
37
- * Returns the tenant's fallback rule for the given entityType, if one exists.
38
- *
39
- * The fallback rule is shown by the "fallback engine active" banner on the
40
- * list page and is used to handle bills/reimbursements that match no other rule.
41
- */
42
- export function getFallbackApprovalRule(approvalRuleState, entityType) {
43
- return Object.values(approvalRuleState.approvalRuleById).find((rule) => rule.entityType === entityType && rule.isFallback === true);
44
- }
@@ -50,3 +50,10 @@ export function getClassReport(classState, accountState, id, filter) {
50
50
  accounts: accountReport,
51
51
  };
52
52
  }
53
+ /**
54
+ * Returns all classes currently in state (single pass over classesByKey).
55
+ * Use for dropdowns that need class names; map to { classId, className } as needed.
56
+ */
57
+ export function getAllClasses(classState) {
58
+ return Object.values(classState.classesByKey);
59
+ }
package/lib/esm/index.js CHANGED
@@ -31,7 +31,6 @@ import { getAccountGroupKey, toAccountGroupType, } from './entity/accountGroup/a
31
31
  import { getAccountReconByAccountIdAndSelectedPeriod, } from './entity/accountRecon/accountReconSelector';
32
32
  import { getAddressByAddressId } from './entity/address/addressSelector';
33
33
  import { toAttributeOrRoleTypeStrict, toAttributeTypeStrict, toRoleTypeStrict, } from './entity/approvalRule/approvalRuleState';
34
- import { getAmountCriteria, getApprovalRulesByEntityType, getDepartmentCriteria, getFallbackApprovalRule, getVendorCriteria, } from './entity/approvalRule/approvalRuleSelector';
35
34
  import { toOutsideZeniPaymentModeType, } from './entity/billPay/billTransaction/billTransactionState';
36
35
  import { toRecurringBillFrequency, toRecurringBillFrequencyStrict, } from './entity/billPay/recurringBills/recurringBillsState';
37
36
  import { toCardAddressType, toCardType, toCreditLimitFrequencyCodeType, toShippingAddressType, } from './entity/chargeCard/chargeCard';
@@ -560,7 +559,7 @@ export { getUserFinancialAccount };
560
559
  export { fetchRemiSetupView, updateMileageDetails, saveRemiSetupViewDataInLocalStore, acceptRemiTerms, acceptEmployeeRemiTerms, clearRemiSetupView, getRemiSetupViewDetails, getRemiBusinessVerificationDetails, };
561
560
  export { VERIFIED_PAYMENT_ACCOUNT_PROVIDER_VERIFICATION_STATUS, };
562
561
  export { isSuccessResponse, isInvalidSessionError, isAccessDeniedError, };
563
- export { getAmountCriteria, getApprovalRulesByEntityType, getDepartmentCriteria, getFallbackApprovalRule, getVendorCriteria, toAttributeTypeStrict, toAttributeOrRoleTypeStrict, toRoleTypeStrict, };
562
+ export { toAttributeTypeStrict, toAttributeOrRoleTypeStrict, toRoleTypeStrict, };
564
563
  export { getBillPaySetupApproverView, getBillPaySetupApproverUpdateDataView, fetchBillPaySetupApproverView, fetchBillPayApproversDetails, fetchBillPayApproversList, deleteBillPayApprovalRule, saveBillPaySetupApproverViewUpdateData, saveBillPaySetupApproverViewUpdates, setBillsSetupApproverViewListeningToPusherEvent, initializeBillPaySetupApproverViewUpdateData, clearBillPaySetupApproverViewUpdateData, clearBillPaySetupApproverView, };
565
564
  export { getRemiSetupApproverView, getRemiSetupApproverUpdateDataView, fetchRemiSetupApproverView, fetchRemiApproversList, fetchRemiApproversDetails, deleteRemiApprovalRule, saveRemiSetupApproverViewUpdateData, saveRemiSetupApproverViewUpdates, initializeRemiSetupApproverViewUpdateData, setRemiSetupApproverViewListeningToPusherEvent, clearRemiSetupApproverViewUpdateData, clearRemiSetupApproverView, };
566
565
  export { getRemiDetailView, checkApproveRejectBtnShowForRemi, };
@@ -27,6 +27,10 @@ export const initialTransactionTabViewState = {
27
27
  totalCount: {},
28
28
  limit: 10,
29
29
  },
30
+ filters: {
31
+ categoryCombinationOperator: 'AND',
32
+ categories: [],
33
+ },
30
34
  fetchState: 'Not-Started',
31
35
  error: undefined,
32
36
  hasValidState() {
@@ -236,6 +240,12 @@ const expenseAutomationTransactionsView = createSlice({
236
240
  uiState.totalCount;
237
241
  }
238
242
  },
243
+ updateTransactionFilters(draft, action) {
244
+ const { selectedTab, filters } = action.payload;
245
+ if (filters != null) {
246
+ draft.transactionCategorizationView[selectedTab].filters = filters;
247
+ }
248
+ },
239
249
  saveTransactionCategorization: {
240
250
  prepare(selectedTab, transactionIds, cotTrackingByTransactionId, isUncategorizedExpenseCategoryEnabled) {
241
251
  return {
@@ -803,5 +813,5 @@ const expenseAutomationTransactionsView = createSlice({
803
813
  },
804
814
  },
805
815
  });
806
- export const { fetchTransactionCategorization, updateTransactionCategorizationUIState, initializeTransactionCategorizationViewLocalData, saveTransactionCategorizationLocalData, fetchTransactionCategorizationFailure, saveTransactionCategorization, updateTransactionCategorization, updateCurrentSelectedTransactionCategorizationTab, updateTransactionCategorizationSaveStatus, markTransactionAsNotMiscategorized, updateStatusForTransactionNotMiscategorizedUpdateForCategorization, updateSelectedVendorForTransaction, updateSelectedCustomerForTransaction, setAllItemsToCategoryClassInLocalDataForCategorization, updateTotalCountForTransactionCategorization, fetchTransactionCategorizationSuccess, resetOtherTabsFetchState, fetchTransactionCategorizationView, updateSelectedCheckboxTransactionIds, clearExpenseAutomationTransactionsViewPerTabView, clearExpenseAutomationTransactionsView, setEntityRecommendationForLineIdsForCategorization, updateSelectedTransactionId, syncTransactionCategorizationFromDetailSave, backgroundRefetchReviewTab, updateTransactionCategorizationUploadReceiptState, uploadTransactionCategorizationReceiptSuccess, } = expenseAutomationTransactionsView.actions;
816
+ export const { fetchTransactionCategorization, updateTransactionCategorizationUIState, updateTransactionFilters, initializeTransactionCategorizationViewLocalData, saveTransactionCategorizationLocalData, fetchTransactionCategorizationFailure, saveTransactionCategorization, updateTransactionCategorization, updateCurrentSelectedTransactionCategorizationTab, updateTransactionCategorizationSaveStatus, markTransactionAsNotMiscategorized, updateStatusForTransactionNotMiscategorizedUpdateForCategorization, updateSelectedVendorForTransaction, updateSelectedCustomerForTransaction, setAllItemsToCategoryClassInLocalDataForCategorization, updateTotalCountForTransactionCategorization, fetchTransactionCategorizationSuccess, resetOtherTabsFetchState, fetchTransactionCategorizationView, updateSelectedCheckboxTransactionIds, clearExpenseAutomationTransactionsViewPerTabView, clearExpenseAutomationTransactionsView, setEntityRecommendationForLineIdsForCategorization, updateSelectedTransactionId, syncTransactionCategorizationFromDetailSave, backgroundRefetchReviewTab, updateTransactionCategorizationUploadReceiptState, uploadTransactionCategorizationReceiptSuccess, } = expenseAutomationTransactionsView.actions;
807
817
  export default expenseAutomationTransactionsView.reducer;
@@ -4,14 +4,33 @@ import { toMonthYearPeriodId } from '../../../commonStateTypes/timePeriod';
4
4
  import { getCurrentTenant, getIsAccountingClassesEnabled, getIsAccountingProjectsEnabled, } from '../../../entity/tenant/tenantSelector';
5
5
  import { getTransactionWithCOT } from '../../../entity/transaction/transactionHelper';
6
6
  import { getSupportedTransactionsByIds } from '../../../entity/transaction/transactionSelector';
7
+ import { applyAdvancedFiltersOnList, } from '../../spendManagement/spendManagementFilterHelpers';
7
8
  import { getAccountList, getNestedAccountListHierarchy, getUncategorizedAccounts, } from '../../accountList/accountListSelector';
8
9
  import { getClassList, getNestedClassListHierarchy, } from '../../classList/classListSelector';
9
10
  import { getProjectList } from '../../projectList/projectListSelector';
10
11
  import { getAllSteps } from '../selectorTypes/expenseAutomationViewSelectorTypes';
12
+ export const toTransactionView = (transaction, transactionLocalData) => {
13
+ return {
14
+ id: transaction.id,
15
+ date: transaction.date,
16
+ amount: transaction.amount,
17
+ vendorName: transaction.vendorName,
18
+ customerName: transaction.customerName,
19
+ vendorId: transaction.vendorId,
20
+ customerId: transaction.customerId,
21
+ description: transaction.description,
22
+ memo: transaction.memo,
23
+ type: transaction.type,
24
+ typeName: transaction.typeName,
25
+ createTime: transaction.createTime,
26
+ transaction: transaction,
27
+ transactionLocalData,
28
+ };
29
+ };
11
30
  export function getExpenseAutomationTransactionView(state) {
12
31
  const { accountState, classState, classListState, accountListState, expenseAutomationTransactionsViewState, expenseAutomationViewState, projectState, projectListState, transactionState, monthEndCloseChecksState, monthEndCloseChecksViewState, } = state;
13
32
  const { selectedTransactionCategorizationTab } = expenseAutomationTransactionsViewState;
14
- const { uiState, refreshStatus, saveStatus, markAsNotMiscategorizedStatus, transactionIdsBySelectedPeriod, transactionReviewLocalDataById, selectedCheckBoxTransactionIds, transactionIdsWithUnsavedData, uploadReceiptStatusById, selectedTransactionId, selectedTransactionLineId, } = expenseAutomationTransactionsViewState.transactionCategorizationView[selectedTransactionCategorizationTab];
33
+ const { uiState, refreshStatus, saveStatus, markAsNotMiscategorizedStatus, transactionIdsBySelectedPeriod, transactionReviewLocalDataById, selectedCheckBoxTransactionIds, transactionIdsWithUnsavedData, uploadReceiptStatusById, selectedTransactionId, selectedTransactionLineId, filters, } = expenseAutomationTransactionsViewState.transactionCategorizationView[selectedTransactionCategorizationTab];
15
34
  const uncategorizedIncomeExpense = getUncategorizedAccounts(accountState, accountListState, 'accountList');
16
35
  const accountList = getAccountList(accountState, accountListState, 'accountList');
17
36
  const classList = getClassList(classState, classListState);
@@ -30,10 +49,42 @@ export function getExpenseAutomationTransactionView(state) {
30
49
  ? transactionIdsBySelectedPeriod[monthYearPeriodId]
31
50
  : null;
32
51
  const transactionIds = transactionIdsForSelectedPeriod ?? [];
33
- const transactionLocalData = transactionIds
34
- .map((transactionId) => {
52
+ const transactions = getSupportedTransactionsByIds(transactionState, transactionIds);
53
+ const transactionsWithCOT = transactions.map((transaction) => getTransactionWithCOT(transaction));
54
+ const transactionLocalDataMap = new Map();
55
+ transactionIds.forEach((transactionId) => {
35
56
  const transactionData = transactionReviewLocalDataById[transactionId];
36
57
  if (transactionData != null) {
58
+ transactionLocalDataMap.set(transactionId, {
59
+ transactionId,
60
+ transactionReviewLocalData: transactionData.transactionReviewLocalData,
61
+ });
62
+ }
63
+ });
64
+ // Step 2: Convert to TransactionView and apply advanced filters
65
+ const transactionViews = transactionsWithCOT.map((transaction) => {
66
+ const localData = transactionLocalDataMap.get(transaction.id);
67
+ return toTransactionView(transaction, localData);
68
+ });
69
+ // Apply advanced filters if they exist
70
+ const filteredTransactionViews = applyAdvancedFiltersOnList('transaction_categorization', transactionViews, filters);
71
+ // Convert back to TransactionWithCOT for return
72
+ const filteredTransactionsWithCOT = filteredTransactionViews.map((view) => view.transaction);
73
+ // Get transactionLocalData for filtered transactions
74
+ // Also include transactionLocalData for transactions that don't exist in transactionState
75
+ // but have local data (to match original behavior)
76
+ const filteredTransactionIds = new Set(filteredTransactionViews.map((view) => view.id));
77
+ const filteredTransactionLocalData = transactionIds
78
+ .map((transactionId) => {
79
+ const transactionData = transactionReviewLocalDataById[transactionId];
80
+ if (transactionData == null) {
81
+ return null;
82
+ }
83
+ // Include if transaction is in filtered results, or if transaction doesn't exist in state
84
+ // (to maintain backward compatibility with tests)
85
+ const transactionExists = transactions.some((t) => t.id === transactionId);
86
+ if (filteredTransactionIds.has(transactionId) ||
87
+ !transactionExists) {
37
88
  return {
38
89
  transactionId,
39
90
  transactionReviewLocalData: transactionData.transactionReviewLocalData,
@@ -41,9 +92,7 @@ export function getExpenseAutomationTransactionView(state) {
41
92
  }
42
93
  return null;
43
94
  })
44
- .filter((transaction) => transaction != null);
45
- const transactions = getSupportedTransactionsByIds(transactionState, transactionIds);
46
- const transactionsWithCOT = transactions.map((transaction) => getTransactionWithCOT(transaction));
95
+ .filter((data) => data != null);
47
96
  const monthEndFetchState = monthYearPeriodId != null
48
97
  ? (monthEndCloseChecksViewState.monthEndCloseChecksViewByTenantId[currentTenant.tenantId]?.[monthYearPeriodId] ?? { fetchState: 'Not-Started', error: undefined })
49
98
  : { fetchState: 'Not-Started', error: undefined };
@@ -90,7 +139,7 @@ export function getExpenseAutomationTransactionView(state) {
90
139
  version: 0,
91
140
  fetchState: fetchStatus.fetchState,
92
141
  error: fetchStatus.error,
93
- transactions: transactionsWithCOT,
142
+ transactions: filteredTransactionsWithCOT,
94
143
  selectedCheckBoxTransactionIds,
95
144
  transactionIdsWithUnsavedData,
96
145
  uncategorizedAccounts: uncategorizedIncomeExpense,
@@ -101,7 +150,7 @@ export function getExpenseAutomationTransactionView(state) {
101
150
  classHierarchyList,
102
151
  isAccountingProjectsEnabled,
103
152
  projectList,
104
- transactionLocalData,
153
+ transactionLocalData: filteredTransactionLocalData,
105
154
  uiState,
106
155
  refreshStatus,
107
156
  saveStatus,
@@ -1,6 +1,6 @@
1
1
  import { from } from 'rxjs';
2
2
  import { filter, mergeMap } from 'rxjs/operators';
3
- import { getAmountCriteria, getApprovalRuleById, getDepartmentCriteria, getVendorCriteria, } from '../../../../../entity/approvalRule/approvalRuleSelector';
3
+ import { getApprovalRuleById } from '../../../../../entity/approvalRule/approvalRuleSelector';
4
4
  import { clearBillPaySetupApproverViewUpdateData, initializeBillPaySetupApproverViewUpdateData, saveBillPaySetupApproverViewUpdateData, } from '../billPaySetupApproverViewReducer';
5
5
  export const initializeBillPaySetupApproverViewUpdateDataEpic = (actions$, state$) => actions$.pipe(filter(initializeBillPaySetupApproverViewUpdateData.match), mergeMap((action) => {
6
6
  const { approvalRuleId } = action.payload;
@@ -8,13 +8,15 @@ export const initializeBillPaySetupApproverViewUpdateDataEpic = (actions$, state
8
8
  if (approvalRuleId != null) {
9
9
  const approvalRule = getApprovalRuleById(state$.value.approvalRuleState, approvalRuleId);
10
10
  if (approvalRule != null) {
11
+ const criteria = approvalRule.criteria[0];
12
+ const range = criteria?.range;
11
13
  const billPaySetupApproverViewUpdateData = {
12
14
  approvalRuleId,
13
15
  steps: approvalRule.steps,
14
16
  criteria: {
15
- amount: getAmountCriteria(approvalRule.criteria),
16
- vendor: getVendorCriteria(approvalRule.criteria),
17
- department: getDepartmentCriteria(approvalRule.criteria),
17
+ rangeType: criteria?.rangeType,
18
+ rangeEntity: criteria?.rangeEntity,
19
+ range,
18
20
  },
19
21
  };
20
22
  fetchActions.push(clearBillPaySetupApproverViewUpdateData(), saveBillPaySetupApproverViewUpdateData(billPaySetupApproverViewUpdateData));
@@ -23,7 +25,7 @@ export const initializeBillPaySetupApproverViewUpdateDataEpic = (actions$, state
23
25
  else {
24
26
  const billPaySetupApproverViewCreateData = {
25
27
  steps: [],
26
- criteria: {},
28
+ criteria: undefined,
27
29
  };
28
30
  fetchActions.push(clearBillPaySetupApproverViewUpdateData(), saveBillPaySetupApproverViewUpdateData(billPaySetupApproverViewCreateData));
29
31
  }
@@ -1,48 +1,20 @@
1
1
  export const toApprovalChangableInfoPayload = (approverViewUpdateData) => {
2
- // Form-side criteria is a structured object with optional slots for
3
- // amount / vendor / department; flatten it into the wire format's
4
- // `conditions[]` array.
5
- let criteriaPayload;
2
+ let criteriaPayload = [];
6
3
  if (approverViewUpdateData.criteria != null) {
7
- const { amount, vendor, department } = approverViewUpdateData.criteria;
8
- const conditions = [];
9
- if (amount?.min != null) {
10
- conditions.push({
11
- field: 'amount',
12
- type: 'gte',
13
- value: amount.min.amount,
14
- });
15
- }
16
- if (amount?.max != null) {
17
- conditions.push({
18
- field: 'amount',
19
- type: 'lte',
20
- value: amount.max.amount,
21
- });
22
- }
23
- if (vendor != null && vendor.vendorIds.length > 0) {
24
- conditions.push({
25
- field: 'vendor_id',
26
- type: vendor.operator === 'is_not' ? 'not_in' : 'in',
27
- value: vendor.vendorIds,
28
- });
29
- }
30
- if (department != null && department.departmentIds.length > 0) {
31
- conditions.push({
32
- field: 'department_id',
33
- type: department.operator === 'is_not' ? 'not_in' : 'in',
34
- value: department.departmentIds,
35
- });
36
- }
37
- if (conditions.length > 0) {
38
- const currency = amount?.min ?? amount?.max ?? null;
39
- criteriaPayload = {
40
- conditions,
41
- criteria_operator: 'and',
42
- currency_code: currency?.currencyCode ?? 'USD',
43
- currency_symbol: currency?.currencySymbol ?? '$',
44
- };
45
- }
4
+ const criteria = approverViewUpdateData.criteria;
5
+ const { rangeType, rangeEntity, range } = criteria;
6
+ const { min, max } = range;
7
+ const { currencyCode, currencySymbol } = min;
8
+ criteriaPayload = [
9
+ {
10
+ type: rangeType,
11
+ range_entity: rangeEntity,
12
+ min: min.amount,
13
+ max: max?.amount ?? null,
14
+ currency_code: currencyCode,
15
+ currency_symbol: currencySymbol,
16
+ },
17
+ ];
46
18
  }
47
19
  const steps = approverViewUpdateData.steps.map((step) => {
48
20
  return {
@@ -63,12 +35,10 @@ export const toApprovalChangableInfoPayload = (approverViewUpdateData) => {
63
35
  });
64
36
  const isUpdate = approverViewUpdateData.approvalRuleId != null;
65
37
  const payload = {
38
+ criteria: criteriaPayload,
66
39
  steps,
67
40
  is_applicable_on_pending_approval_entity: approverViewUpdateData.isApplicableOnPendingApprovalEntity ?? true,
68
41
  };
69
- if (criteriaPayload != null) {
70
- payload.criteria = criteriaPayload;
71
- }
72
42
  if (isUpdate) {
73
43
  payload.approval_rule_id = approverViewUpdateData.approvalRuleId;
74
44
  }
@@ -1,6 +1,5 @@
1
1
  import recordGet from 'lodash/get';
2
2
  import has from 'lodash/has';
3
- import { getAmountCriteria } from '../../../../entity/approvalRule/approvalRuleSelector';
4
3
  import { reduceFetchState } from '../../../../commonStateTypes/reduceFetchState';
5
4
  import { getBankAccountByBankAccountId, getBankAccountsByBankAccountIds, } from '../../../../entity/bankAccount/bankAccountSelector';
6
5
  import { getContactById, getContactsByIds, } from '../../../../entity/billPay/contact/contactSelector';
@@ -682,13 +681,9 @@ export const getDefaultWithdrawFromAccount = (state, depositAccounts, companyId,
682
681
  export const checkIfCreatorIsApprover = (billAmount, approvalRules, signedInUser) => {
683
682
  let isCreatorAlsoApprover = false;
684
683
  const approvalRule = approvalRules.find((rule) => {
685
- const amountCriteria = getAmountCriteria(rule.criteria);
686
- if (amountCriteria?.min == null) {
687
- return false;
688
- }
689
- const { min, max } = amountCriteria;
684
+ const { max, min } = rule.criteria[0].range;
690
685
  return (billAmount > min.amount &&
691
- (max?.amount != null ? billAmount <= max.amount : true));
686
+ (max?.amount != null ? billAmount <= max?.amount : true));
692
687
  });
693
688
  if (approvalRule != null) {
694
689
  const requireApprovalSteps = approvalRule.steps.filter((step) => step.action === 'require_approval');
@@ -1,6 +1,6 @@
1
1
  import { from } from 'rxjs';
2
2
  import { filter, mergeMap } from 'rxjs/operators';
3
- import { getAmountCriteria, getApprovalRuleById, getDepartmentCriteria, getVendorCriteria, } from '../../../../../entity/approvalRule/approvalRuleSelector';
3
+ import { getApprovalRuleById } from '../../../../../entity/approvalRule/approvalRuleSelector';
4
4
  import { clearRemiSetupApproverViewUpdateData, initializeRemiSetupApproverViewUpdateData, saveRemiSetupApproverViewUpdateData, } from '../remiSetupApproverViewReducer';
5
5
  export const initializeRemiSetupApproverViewUpdateDataEpic = (actions$, state$) => actions$.pipe(filter(initializeRemiSetupApproverViewUpdateData.match), mergeMap((action) => {
6
6
  const { approvalRuleId } = action.payload;
@@ -8,13 +8,15 @@ export const initializeRemiSetupApproverViewUpdateDataEpic = (actions$, state$)
8
8
  if (approvalRuleId != null) {
9
9
  const approvalRule = getApprovalRuleById(state$.value.approvalRuleState, approvalRuleId);
10
10
  if (approvalRule != null) {
11
+ const criteria = approvalRule.criteria[0];
12
+ const range = criteria?.range;
11
13
  const remiSetupApproverViewUpdateData = {
12
14
  approvalRuleId,
13
15
  steps: approvalRule.steps,
14
16
  criteria: {
15
- amount: getAmountCriteria(approvalRule.criteria),
16
- vendor: getVendorCriteria(approvalRule.criteria),
17
- department: getDepartmentCriteria(approvalRule.criteria),
17
+ rangeType: criteria?.rangeType,
18
+ rangeEntity: criteria?.rangeEntity,
19
+ range,
18
20
  },
19
21
  };
20
22
  fetchActions.push(clearRemiSetupApproverViewUpdateData(), saveRemiSetupApproverViewUpdateData(remiSetupApproverViewUpdateData));
@@ -23,7 +25,7 @@ export const initializeRemiSetupApproverViewUpdateDataEpic = (actions$, state$)
23
25
  else {
24
26
  const remiSetupApproverViewCreateData = {
25
27
  steps: [],
26
- criteria: {},
28
+ criteria: undefined,
27
29
  };
28
30
  fetchActions.push(clearRemiSetupApproverViewUpdateData(), saveRemiSetupApproverViewUpdateData(remiSetupApproverViewCreateData));
29
31
  }