@zeniai/client-epic-state 5.0.50-betaAR1 → 5.0.50-betaAS1
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/approvalRule/approvalRulePayload.d.ts +5 -27
- package/lib/entity/approvalRule/approvalRulePayload.js +10 -87
- 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/esm/entity/approvalRule/approvalRulePayload.js +10 -87
- package/lib/esm/entity/approvalRule/approvalRuleSelector.js +0 -35
- package/lib/esm/index.js +1 -2
- 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/zeniAccounts/depositAccountDetail/depositAccountDetailSelector.js +1 -1
- package/lib/index.d.ts +2 -3
- package/lib/index.js +16 -22
- package/lib/view/companyTaskManagerView/companyTaskManagerViewReducer.d.ts +2 -2
- package/lib/view/companyView/types/cockpitTypes.d.ts +1 -1
- 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/zeniAccounts/depositAccountDetail/depositAccountDetailSelector.js +1 -1
- package/lib/view/taskManager/taskListView/taskList.d.ts +3 -3
- package/package.json +1 -1
- package/lib/tsconfig.typecheck.tsbuildinfo +0 -1
|
@@ -1,27 +1,11 @@
|
|
|
1
1
|
import { ApprovalRule } from './approvalRuleState';
|
|
2
|
-
/**
|
|
3
|
-
* Condition Payload — one entry inside criteria.conditions[].
|
|
4
|
-
*
|
|
5
|
-
* field examples: 'amount' | 'vendor_id' | 'department_id'
|
|
6
|
-
* type examples: 'gte' | 'lte' | 'eq' | 'in' | 'not_in'
|
|
7
|
-
* value: number for amount comparisons; string[] for in / not_in lookups.
|
|
8
|
-
*/
|
|
9
|
-
export interface ConditionPayload {
|
|
10
|
-
field: string;
|
|
11
|
-
type: string;
|
|
12
|
-
value: number | string[];
|
|
13
|
-
}
|
|
14
|
-
/**
|
|
15
|
-
* Criteria Payload — list of conditions joined by `criteria_operator`.
|
|
16
|
-
*
|
|
17
|
-
* `currency_code` / `currency_symbol` apply to amount conditions inside
|
|
18
|
-
* `conditions[]`. Kept here pending confirmation that they should remain.
|
|
19
|
-
*/
|
|
20
2
|
export interface CriteriaPayload {
|
|
21
|
-
conditions: ConditionPayload[];
|
|
22
|
-
criteria_operator: string;
|
|
23
3
|
currency_code: string;
|
|
24
4
|
currency_symbol: string;
|
|
5
|
+
min: number;
|
|
6
|
+
range_entity: string;
|
|
7
|
+
type: string;
|
|
8
|
+
max?: number | null;
|
|
25
9
|
}
|
|
26
10
|
export interface ActorPayload {
|
|
27
11
|
type: string;
|
|
@@ -41,17 +25,11 @@ export interface StepPayload {
|
|
|
41
25
|
export interface ApprovalRulePayload {
|
|
42
26
|
approval_rule_id: string;
|
|
43
27
|
create_time: string;
|
|
44
|
-
criteria: CriteriaPayload;
|
|
28
|
+
criteria: CriteriaPayload[];
|
|
45
29
|
entity_type: string;
|
|
46
30
|
name: string | null;
|
|
47
31
|
steps: StepPayload[];
|
|
48
32
|
update_time: string;
|
|
49
|
-
are_approvals_serialized?: boolean;
|
|
50
|
-
description?: string | null;
|
|
51
|
-
is_fallback?: boolean;
|
|
52
|
-
pending_approvals_count?: number;
|
|
53
|
-
pending_entity_approval_update_status?: string;
|
|
54
|
-
priority?: number;
|
|
55
33
|
version?: number | string;
|
|
56
34
|
}
|
|
57
35
|
/**
|
|
@@ -17,96 +17,19 @@ const toApprovalRule = (payload) => ({
|
|
|
17
17
|
version: payload.version,
|
|
18
18
|
criteria: toApprovalCriteria(payload.criteria),
|
|
19
19
|
steps: toApprovalSteps(payload.steps),
|
|
20
|
-
description: payload.description ?? undefined,
|
|
21
|
-
priority: payload.priority,
|
|
22
|
-
isFallback: payload.is_fallback ?? false,
|
|
23
|
-
// separationOfDuties: backend doesn't ship this field yet; left undefined
|
|
24
|
-
// until the spec is finalized.
|
|
25
|
-
areApprovalsSerialized: payload.are_approvals_serialized,
|
|
26
|
-
pendingApprovalsCount: payload.pending_approvals_count,
|
|
27
|
-
pendingEntityApprovalUpdateStatus: payload.pending_entity_approval_update_status,
|
|
28
20
|
});
|
|
29
21
|
exports.toApprovalRule = toApprovalRule;
|
|
30
|
-
/**
|
|
31
|
-
* Maps the wire-level criteria block into the state-side discriminated
|
|
32
|
-
* `Criteria[]` union.
|
|
33
|
-
*
|
|
34
|
-
* The wire keeps each condition as a flat row inside `conditions[]`.
|
|
35
|
-
* Amount comparisons can show up as a `gte` only, a `lte` only, or a
|
|
36
|
-
* `gte` + `lte` pair — those collapse into a single AmountCriteria whose
|
|
37
|
-
* `comparator` is `greater_than`, `less_than`, or `range` respectively.
|
|
38
|
-
*
|
|
39
|
-
* Vendor and department conditions map one-to-one: `in` becomes `is`,
|
|
40
|
-
* `not_in` becomes `is_not`.
|
|
41
|
-
*/
|
|
42
22
|
const toApprovalCriteria = (payload) => {
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
results.push(vendor);
|
|
54
|
-
}
|
|
55
|
-
});
|
|
56
|
-
payload.conditions
|
|
57
|
-
.filter((condition) => condition.field === 'department_id')
|
|
58
|
-
.forEach((condition) => {
|
|
59
|
-
const department = toDepartmentCriteria(condition);
|
|
60
|
-
if (department != null) {
|
|
61
|
-
results.push(department);
|
|
62
|
-
}
|
|
63
|
-
});
|
|
64
|
-
return results;
|
|
65
|
-
};
|
|
66
|
-
const toAmountCriteria = (payload) => {
|
|
67
|
-
const amountConditions = payload.conditions.filter((condition) => condition.field === 'amount');
|
|
68
|
-
const gteCondition = amountConditions.find((condition) => condition.type === 'gte' || condition.type === 'eq');
|
|
69
|
-
const lteCondition = amountConditions.find((condition) => condition.type === 'lte');
|
|
70
|
-
if (gteCondition == null && lteCondition == null) {
|
|
71
|
-
return undefined;
|
|
72
|
-
}
|
|
73
|
-
const min = typeof gteCondition?.value === 'number'
|
|
74
|
-
? (0, amount_1.toAmount)(gteCondition.value, payload.currency_code, payload.currency_symbol)
|
|
75
|
-
: undefined;
|
|
76
|
-
const max = typeof lteCondition?.value === 'number'
|
|
77
|
-
? (0, amount_1.toAmount)(lteCondition.value, payload.currency_code, payload.currency_symbol)
|
|
78
|
-
: undefined;
|
|
79
|
-
let comparator;
|
|
80
|
-
if (min != null && max != null) {
|
|
81
|
-
comparator = 'range';
|
|
82
|
-
}
|
|
83
|
-
else if (min != null) {
|
|
84
|
-
comparator = 'greater_than';
|
|
85
|
-
}
|
|
86
|
-
else {
|
|
87
|
-
comparator = 'less_than';
|
|
88
|
-
}
|
|
89
|
-
return { type: 'amount', comparator, min, max };
|
|
90
|
-
};
|
|
91
|
-
const toVendorCriteria = (condition) => {
|
|
92
|
-
if (!Array.isArray(condition.value)) {
|
|
93
|
-
return undefined;
|
|
94
|
-
}
|
|
95
|
-
return {
|
|
96
|
-
type: 'vendor',
|
|
97
|
-
operator: condition.type === 'not_in' ? 'is_not' : 'is',
|
|
98
|
-
vendorIds: condition.value,
|
|
99
|
-
};
|
|
100
|
-
};
|
|
101
|
-
const toDepartmentCriteria = (condition) => {
|
|
102
|
-
if (!Array.isArray(condition.value)) {
|
|
103
|
-
return undefined;
|
|
104
|
-
}
|
|
105
|
-
return {
|
|
106
|
-
type: 'department',
|
|
107
|
-
operator: condition.type === 'not_in' ? 'is_not' : 'is',
|
|
108
|
-
departmentIds: condition.value,
|
|
109
|
-
};
|
|
23
|
+
return payload.map((criteria) => ({
|
|
24
|
+
rangeType: criteria.type,
|
|
25
|
+
rangeEntity: criteria.range_entity,
|
|
26
|
+
range: {
|
|
27
|
+
min: (0, amount_1.toAmount)(criteria.min, criteria.currency_code, criteria.currency_symbol),
|
|
28
|
+
max: criteria.max != null
|
|
29
|
+
? (0, amount_1.toAmount)(criteria.max, criteria.currency_code, criteria.currency_symbol)
|
|
30
|
+
: undefined,
|
|
31
|
+
},
|
|
32
|
+
}));
|
|
110
33
|
};
|
|
111
34
|
const toApprovalSteps = (payload) => {
|
|
112
35
|
return payload.map((step) => ({
|
|
@@ -1,28 +1,4 @@
|
|
|
1
1
|
import { ID } from '../../commonStateTypes/common';
|
|
2
|
-
import {
|
|
3
|
-
import { AmountCriteria, ApprovalRule, ApprovalRuleState, Criteria, DepartmentCriteria, VendorCriteria } from './approvalRuleState';
|
|
2
|
+
import { ApprovalRule, ApprovalRuleState } from './approvalRuleState';
|
|
4
3
|
export declare function getApprovalRuleById(approvalRuleState: ApprovalRuleState, approvalRuleId: ID): ApprovalRule | undefined;
|
|
5
4
|
export declare function getApprovalRulesByIds(approvalRuleState: ApprovalRuleState, approvalRuleIds: ID[]): ApprovalRule[];
|
|
6
|
-
/**
|
|
7
|
-
* Returns the amount-range portion of a rule's criteria, if any.
|
|
8
|
-
*
|
|
9
|
-
* Use this whenever a caller needs to read amount min/max from the new
|
|
10
|
-
* discriminated `Criteria` union without inlining a type guard.
|
|
11
|
-
*/
|
|
12
|
-
export declare function getAmountCriteria(criteria: Criteria[]): AmountCriteria | undefined;
|
|
13
|
-
export declare function getVendorCriteria(criteria: Criteria[]): VendorCriteria | undefined;
|
|
14
|
-
export declare function getDepartmentCriteria(criteria: Criteria[]): DepartmentCriteria | undefined;
|
|
15
|
-
/**
|
|
16
|
-
* Returns all rules of the given entityType, sorted by `priority` ascending.
|
|
17
|
-
*
|
|
18
|
-
* Rules without a `priority` value sort to the end (treated as Infinity).
|
|
19
|
-
* Use this for the list page where rules render in evaluation order.
|
|
20
|
-
*/
|
|
21
|
-
export declare function getApprovalRulesByEntityType(approvalRuleState: ApprovalRuleState, entityType: EntityType): ApprovalRule[];
|
|
22
|
-
/**
|
|
23
|
-
* Returns the tenant's fallback rule for the given entityType, if one exists.
|
|
24
|
-
*
|
|
25
|
-
* The fallback rule is shown by the "fallback engine active" banner on the
|
|
26
|
-
* list page and is used to handle bills/reimbursements that match no other rule.
|
|
27
|
-
*/
|
|
28
|
-
export declare function getFallbackApprovalRule(approvalRuleState: ApprovalRuleState, entityType: EntityType): ApprovalRule | undefined;
|
|
@@ -2,11 +2,6 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.getApprovalRuleById = getApprovalRuleById;
|
|
4
4
|
exports.getApprovalRulesByIds = getApprovalRulesByIds;
|
|
5
|
-
exports.getAmountCriteria = getAmountCriteria;
|
|
6
|
-
exports.getVendorCriteria = getVendorCriteria;
|
|
7
|
-
exports.getDepartmentCriteria = getDepartmentCriteria;
|
|
8
|
-
exports.getApprovalRulesByEntityType = getApprovalRulesByEntityType;
|
|
9
|
-
exports.getFallbackApprovalRule = getFallbackApprovalRule;
|
|
10
5
|
function getApprovalRuleById(approvalRuleState, approvalRuleId) {
|
|
11
6
|
return approvalRuleState.approvalRuleById[approvalRuleId] ?? undefined;
|
|
12
7
|
}
|
|
@@ -16,38 +11,3 @@ function getApprovalRulesByIds(approvalRuleState, approvalRuleIds) {
|
|
|
16
11
|
.filter((value) => value != null);
|
|
17
12
|
return approvalRulesByIds;
|
|
18
13
|
}
|
|
19
|
-
/**
|
|
20
|
-
* Returns the amount-range portion of a rule's criteria, if any.
|
|
21
|
-
*
|
|
22
|
-
* Use this whenever a caller needs to read amount min/max from the new
|
|
23
|
-
* discriminated `Criteria` union without inlining a type guard.
|
|
24
|
-
*/
|
|
25
|
-
function getAmountCriteria(criteria) {
|
|
26
|
-
return criteria.find((c) => c.type === 'amount');
|
|
27
|
-
}
|
|
28
|
-
function getVendorCriteria(criteria) {
|
|
29
|
-
return criteria.find((c) => c.type === 'vendor');
|
|
30
|
-
}
|
|
31
|
-
function getDepartmentCriteria(criteria) {
|
|
32
|
-
return criteria.find((c) => c.type === 'department');
|
|
33
|
-
}
|
|
34
|
-
/**
|
|
35
|
-
* Returns all rules of the given entityType, sorted by `priority` ascending.
|
|
36
|
-
*
|
|
37
|
-
* Rules without a `priority` value sort to the end (treated as Infinity).
|
|
38
|
-
* Use this for the list page where rules render in evaluation order.
|
|
39
|
-
*/
|
|
40
|
-
function getApprovalRulesByEntityType(approvalRuleState, entityType) {
|
|
41
|
-
return Object.values(approvalRuleState.approvalRuleById)
|
|
42
|
-
.filter((rule) => rule.entityType === entityType)
|
|
43
|
-
.sort((a, b) => (a.priority ?? Infinity) - (b.priority ?? Infinity));
|
|
44
|
-
}
|
|
45
|
-
/**
|
|
46
|
-
* Returns the tenant's fallback rule for the given entityType, if one exists.
|
|
47
|
-
*
|
|
48
|
-
* The fallback rule is shown by the "fallback engine active" banner on the
|
|
49
|
-
* list page and is used to handle bills/reimbursements that match no other rule.
|
|
50
|
-
*/
|
|
51
|
-
function getFallbackApprovalRule(approvalRuleState, entityType) {
|
|
52
|
-
return Object.values(approvalRuleState.approvalRuleById).find((rule) => rule.entityType === entityType && rule.isFallback === true);
|
|
53
|
-
}
|
|
@@ -25,37 +25,14 @@ export interface Actor {
|
|
|
25
25
|
subType?: AttributeType | RoleType;
|
|
26
26
|
userId?: ID;
|
|
27
27
|
}
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
* Form-side, the rule create/edit form uses `ApprovalRuleFormCriteria`
|
|
36
|
-
* (defined in commonState) — a structured object with named slots for
|
|
37
|
-
* amount/vendor/department. Epics translate between the two.
|
|
38
|
-
*/
|
|
39
|
-
export type AmountComparator = 'greater_than' | 'less_than' | 'range';
|
|
40
|
-
export interface AmountCriteria {
|
|
41
|
-
comparator: AmountComparator;
|
|
42
|
-
type: 'amount';
|
|
43
|
-
/** Upper bound. Present for `less_than` and `range`. */
|
|
44
|
-
max?: Amount;
|
|
45
|
-
/** Lower bound. Present for `greater_than` and `range`. */
|
|
46
|
-
min?: Amount;
|
|
47
|
-
}
|
|
48
|
-
export interface VendorCriteria {
|
|
49
|
-
operator: 'is' | 'is_not';
|
|
50
|
-
type: 'vendor';
|
|
51
|
-
vendorIds: ID[];
|
|
52
|
-
}
|
|
53
|
-
export interface DepartmentCriteria {
|
|
54
|
-
departmentIds: ID[];
|
|
55
|
-
operator: 'is' | 'is_not';
|
|
56
|
-
type: 'department';
|
|
28
|
+
export interface Criteria {
|
|
29
|
+
range: {
|
|
30
|
+
min: Amount;
|
|
31
|
+
max?: Amount;
|
|
32
|
+
};
|
|
33
|
+
rangeEntity: string;
|
|
34
|
+
rangeType: string;
|
|
57
35
|
}
|
|
58
|
-
export type Criteria = AmountCriteria | VendorCriteria | DepartmentCriteria;
|
|
59
36
|
export interface Step {
|
|
60
37
|
actors: Actor[];
|
|
61
38
|
operator: StepOperatorType;
|
|
@@ -74,25 +51,7 @@ export interface ApprovalRule {
|
|
|
74
51
|
entityType: EntityType;
|
|
75
52
|
steps: Step[];
|
|
76
53
|
updateTime: ZeniDate;
|
|
77
|
-
/** Backend bookkeeping: whether approval steps must run serialized. */
|
|
78
|
-
areApprovalsSerialized?: boolean;
|
|
79
|
-
/** Free-text description shown beneath the rule name on the list page. */
|
|
80
|
-
description?: string;
|
|
81
|
-
/** True when this rule is the tenant's default fallback rule. */
|
|
82
|
-
isFallback?: boolean;
|
|
83
54
|
name?: string;
|
|
84
|
-
/** Backend bookkeeping: number of entities currently pending against this rule. */
|
|
85
|
-
pendingApprovalsCount?: number;
|
|
86
|
-
/** Backend bookkeeping: status of background updates against this rule. */
|
|
87
|
-
pendingEntityApprovalUpdateStatus?: string;
|
|
88
|
-
/** Rule's position in the evaluation order; lower number = higher priority. */
|
|
89
|
-
priority?: number;
|
|
90
|
-
/**
|
|
91
|
-
* When on, the creator of a bill/reimbursement cannot auto-approve
|
|
92
|
-
* their own request even if they are also an approver. Backend spec
|
|
93
|
-
* is still pending — kept optional for now.
|
|
94
|
-
*/
|
|
95
|
-
separationOfDuties?: boolean;
|
|
96
55
|
version?: number | string;
|
|
97
56
|
}
|
|
98
57
|
export interface Approvers {
|
|
@@ -14,95 +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
18
|
const toApprovalCriteria = (payload) => {
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
results.push(vendor);
|
|
50
|
-
}
|
|
51
|
-
});
|
|
52
|
-
payload.conditions
|
|
53
|
-
.filter((condition) => condition.field === 'department_id')
|
|
54
|
-
.forEach((condition) => {
|
|
55
|
-
const department = toDepartmentCriteria(condition);
|
|
56
|
-
if (department != null) {
|
|
57
|
-
results.push(department);
|
|
58
|
-
}
|
|
59
|
-
});
|
|
60
|
-
return results;
|
|
61
|
-
};
|
|
62
|
-
const toAmountCriteria = (payload) => {
|
|
63
|
-
const amountConditions = payload.conditions.filter((condition) => condition.field === 'amount');
|
|
64
|
-
const gteCondition = amountConditions.find((condition) => condition.type === 'gte' || condition.type === 'eq');
|
|
65
|
-
const lteCondition = amountConditions.find((condition) => condition.type === 'lte');
|
|
66
|
-
if (gteCondition == null && lteCondition == null) {
|
|
67
|
-
return undefined;
|
|
68
|
-
}
|
|
69
|
-
const min = typeof gteCondition?.value === 'number'
|
|
70
|
-
? toAmount(gteCondition.value, payload.currency_code, payload.currency_symbol)
|
|
71
|
-
: undefined;
|
|
72
|
-
const max = typeof lteCondition?.value === 'number'
|
|
73
|
-
? toAmount(lteCondition.value, payload.currency_code, payload.currency_symbol)
|
|
74
|
-
: undefined;
|
|
75
|
-
let comparator;
|
|
76
|
-
if (min != null && max != null) {
|
|
77
|
-
comparator = 'range';
|
|
78
|
-
}
|
|
79
|
-
else if (min != null) {
|
|
80
|
-
comparator = 'greater_than';
|
|
81
|
-
}
|
|
82
|
-
else {
|
|
83
|
-
comparator = 'less_than';
|
|
84
|
-
}
|
|
85
|
-
return { type: 'amount', comparator, min, max };
|
|
86
|
-
};
|
|
87
|
-
const toVendorCriteria = (condition) => {
|
|
88
|
-
if (!Array.isArray(condition.value)) {
|
|
89
|
-
return undefined;
|
|
90
|
-
}
|
|
91
|
-
return {
|
|
92
|
-
type: 'vendor',
|
|
93
|
-
operator: condition.type === 'not_in' ? 'is_not' : 'is',
|
|
94
|
-
vendorIds: condition.value,
|
|
95
|
-
};
|
|
96
|
-
};
|
|
97
|
-
const toDepartmentCriteria = (condition) => {
|
|
98
|
-
if (!Array.isArray(condition.value)) {
|
|
99
|
-
return undefined;
|
|
100
|
-
}
|
|
101
|
-
return {
|
|
102
|
-
type: 'department',
|
|
103
|
-
operator: condition.type === 'not_in' ? 'is_not' : 'is',
|
|
104
|
-
departmentIds: condition.value,
|
|
105
|
-
};
|
|
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
|
+
}));
|
|
106
29
|
};
|
|
107
30
|
const toApprovalSteps = (payload) => {
|
|
108
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
|
-
}
|
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, };
|
|
@@ -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
|
}
|
|
@@ -30,7 +30,7 @@ export const getDepositAccountDetail = (state, depositAccountId) => {
|
|
|
30
30
|
const zeniAccountDetail = zeniAccountDetailState.depositAccountDetailById[depositAccountId];
|
|
31
31
|
const depositAccount = getDepositAccountByDepositAccountId(depositAccountState, depositAccountId);
|
|
32
32
|
const zeniAccountsConfig = getZeniAccountsConfigDetail(state);
|
|
33
|
-
const transactionListView = getDepositAccountTransactionList(state, depositAccountId
|
|
33
|
+
const transactionListView = getDepositAccountTransactionList(state, depositAccountId);
|
|
34
34
|
let accountUpdateStatus = {
|
|
35
35
|
editName: {
|
|
36
36
|
fetchState: 'Not-Started',
|