@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.
- package/lib/entity/account/accountSelector.d.ts +20 -1
- package/lib/entity/account/accountSelector.js +35 -1
- package/lib/entity/account/accountState.d.ts +5 -0
- package/lib/entity/account/accountState.js +11 -4
- package/lib/entity/approvalRule/approvalRulePayload.d.ts +5 -27
- package/lib/entity/approvalRule/approvalRulePayload.js +10 -131
- package/lib/entity/approvalRule/approvalRuleSelector.d.ts +1 -25
- package/lib/entity/approvalRule/approvalRuleSelector.js +0 -40
- package/lib/entity/approvalRule/approvalRuleState.d.ts +7 -48
- package/lib/entity/class/classSelector.d.ts +5 -0
- package/lib/entity/class/classSelector.js +8 -0
- package/lib/esm/entity/account/accountSelector.js +33 -1
- package/lib/esm/entity/account/accountState.js +7 -1
- package/lib/esm/entity/approvalRule/approvalRulePayload.js +10 -131
- package/lib/esm/entity/approvalRule/approvalRuleSelector.js +0 -35
- package/lib/esm/entity/class/classSelector.js +7 -0
- package/lib/esm/index.js +1 -2
- package/lib/esm/view/expenseAutomationView/reducers/transactionsViewReducer.js +11 -1
- package/lib/esm/view/expenseAutomationView/selectors/transactionCategorizationSelector.js +57 -8
- package/lib/esm/view/spendManagement/billPay/billPaySetupApproverView/epic/initializeBillPaySetupApproverViewUpdateDataEpic.js +7 -5
- package/lib/esm/view/spendManagement/billPay/billPaySetupApproverView/types/commonPayload.js +16 -46
- package/lib/esm/view/spendManagement/billPay/editBillView/editBillViewSelector.js +2 -7
- package/lib/esm/view/spendManagement/reimbursement/remiSetupApproverView/epic/initializeRemiSetupApproverViewUpdateDataEpic.js +7 -5
- package/lib/esm/view/spendManagement/spendManagementFilterHelpers.js +185 -15
- package/lib/index.d.ts +2 -3
- package/lib/index.js +16 -22
- package/lib/tsconfig.typecheck.tsbuildinfo +1 -1
- package/lib/view/companyTaskManagerView/companyTaskManagerViewReducer.d.ts +2 -2
- package/lib/view/companyView/types/cockpitTypes.d.ts +1 -1
- package/lib/view/expenseAutomationView/reducers/transactionsViewReducer.d.ts +5 -1
- package/lib/view/expenseAutomationView/reducers/transactionsViewReducer.js +12 -2
- package/lib/view/expenseAutomationView/selectors/transactionCategorizationSelector.d.ts +4 -1
- package/lib/view/expenseAutomationView/selectors/transactionCategorizationSelector.js +59 -8
- package/lib/view/expenseAutomationView/types/transactionsViewState.d.ts +2 -0
- package/lib/view/people/peopleTypes.d.ts +1 -1
- package/lib/view/spendManagement/billPay/billPaySetupApproverView/epic/initializeBillPaySetupApproverViewUpdateDataEpic.js +6 -4
- package/lib/view/spendManagement/billPay/billPaySetupApproverView/types/commonPayload.d.ts +1 -1
- package/lib/view/spendManagement/billPay/billPaySetupApproverView/types/commonPayload.js +16 -46
- package/lib/view/spendManagement/billPay/billPaySetupApproverView/types/commonState.d.ts +3 -15
- package/lib/view/spendManagement/billPay/editBillView/editBillViewSelector.js +2 -7
- package/lib/view/spendManagement/chargeCards/chargeCardList/chargeCardList.d.ts +1 -1
- package/lib/view/spendManagement/reimbursement/remiSetupApproverView/epic/initializeRemiSetupApproverViewUpdateDataEpic.js +6 -4
- package/lib/view/spendManagement/spendManagementFilterHelpers.d.ts +45 -4
- package/lib/view/spendManagement/spendManagementFilterHelpers.js +186 -16
- package/lib/view/taskManager/taskListView/taskList.d.ts +3 -3
- 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
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
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 {
|
|
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
|
|
34
|
-
|
|
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((
|
|
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:
|
|
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 {
|
|
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
|
-
|
|
16
|
-
|
|
17
|
-
|
|
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
|
}
|
package/lib/esm/view/spendManagement/billPay/billPaySetupApproverView/types/commonPayload.js
CHANGED
|
@@ -1,48 +1,20 @@
|
|
|
1
1
|
export const toApprovalChangableInfoPayload = (approverViewUpdateData) => {
|
|
2
|
-
|
|
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
|
|
8
|
-
const
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
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
|
|
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
|
|
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 {
|
|
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
|
-
|
|
16
|
-
|
|
17
|
-
|
|
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
|
}
|