@zeniai/client-epic-state 5.2.22-betaAM4 → 5.2.22-betaMM1
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/actualMatching/actualMatchingPayload.d.ts +25 -0
- package/lib/entity/actualMatching/actualMatchingPayload.js +42 -0
- package/lib/entity/actualMatching/actualMatchingReducer.d.ts +8 -0
- package/lib/entity/actualMatching/actualMatchingReducer.js +33 -0
- package/lib/entity/actualMatching/actualMatchingSelector.d.ts +3 -0
- package/lib/entity/actualMatching/actualMatchingSelector.js +6 -0
- package/lib/entity/actualMatching/actualMatchingState.d.ts +22 -0
- package/lib/entity/actualMatching/actualMatchingState.js +2 -0
- package/lib/entity/actualMatching/actualMatchingTypes.d.ts +1 -0
- package/lib/entity/actualMatching/actualMatchingTypes.js +2 -0
- package/lib/entity/jeSchedules/jeSchedulesPayload.d.ts +2 -0
- package/lib/entity/jeSchedules/jeSchedulesPayload.js +2 -0
- package/lib/entity/jeSchedules/jeSchedulesState.d.ts +2 -0
- package/lib/epic.d.ts +3 -1
- package/lib/epic.js +4 -0
- package/lib/esm/entity/actualMatching/actualMatchingPayload.js +39 -0
- package/lib/esm/entity/actualMatching/actualMatchingReducer.js +30 -0
- package/lib/esm/entity/actualMatching/actualMatchingSelector.js +3 -0
- package/lib/esm/entity/actualMatching/actualMatchingState.js +1 -0
- package/lib/esm/entity/actualMatching/actualMatchingTypes.js +1 -0
- package/lib/esm/entity/jeSchedules/jeSchedulesPayload.js +2 -0
- package/lib/esm/epic.js +4 -0
- package/lib/esm/index.js +5 -5
- package/lib/esm/reducer.js +3 -0
- package/lib/esm/view/expenseAutomationView/epics/actualMatching/fetchActualMatchingEpic.js +6 -6
- package/lib/esm/view/expenseAutomationView/epics/actualMatching/fetchActualMatchingMatchEpic.js +35 -0
- package/lib/esm/view/expenseAutomationView/epics/actualMatching/matchAndReverseAccrualsEpic.js +2 -1
- package/lib/esm/view/expenseAutomationView/epics/actualMatching/searchMatchTransactionsEpic.js +35 -6
- package/lib/esm/view/expenseAutomationView/epics/actualMatching/undoReversalAccrualsEpic.js +51 -0
- package/lib/esm/view/expenseAutomationView/epics/common/fetchAllExpenseAutomationTabsEpic.js +1 -1
- package/lib/esm/view/expenseAutomationView/payload/actualMatchingPayload.js +9 -1
- package/lib/esm/view/expenseAutomationView/reducers/actualMatchingViewReducer.js +112 -8
- package/lib/esm/view/expenseAutomationView/selectors/actualMatchingViewSelector.js +145 -98
- package/lib/esm/view/expenseAutomationView/types/actualMatchingViewState.js +10 -0
- package/lib/index.d.ts +8 -5
- package/lib/index.js +53 -48
- package/lib/reducer.d.ts +1 -0
- package/lib/reducer.js +3 -0
- package/lib/rootStateTypes.d.ts +2 -0
- package/lib/view/expenseAutomationView/epics/actualMatching/fetchActualMatchingEpic.d.ts +2 -2
- package/lib/view/expenseAutomationView/epics/actualMatching/fetchActualMatchingEpic.js +6 -6
- package/lib/view/expenseAutomationView/epics/actualMatching/fetchActualMatchingMatchEpic.d.ts +12 -0
- package/lib/view/expenseAutomationView/epics/actualMatching/fetchActualMatchingMatchEpic.js +39 -0
- package/lib/view/expenseAutomationView/epics/actualMatching/matchAndReverseAccrualsEpic.js +2 -1
- package/lib/view/expenseAutomationView/epics/actualMatching/searchMatchTransactionsEpic.d.ts +1 -1
- package/lib/view/expenseAutomationView/epics/actualMatching/searchMatchTransactionsEpic.js +35 -6
- package/lib/view/expenseAutomationView/epics/actualMatching/undoReversalAccrualsEpic.d.ts +8 -0
- package/lib/view/expenseAutomationView/epics/actualMatching/undoReversalAccrualsEpic.js +55 -0
- package/lib/view/expenseAutomationView/epics/common/fetchAllExpenseAutomationTabsEpic.js +1 -1
- package/lib/view/expenseAutomationView/payload/actualMatchingPayload.d.ts +20 -7
- package/lib/view/expenseAutomationView/payload/actualMatchingPayload.js +9 -0
- package/lib/view/expenseAutomationView/reducers/actualMatchingViewReducer.d.ts +26 -5
- package/lib/view/expenseAutomationView/reducers/actualMatchingViewReducer.js +113 -9
- package/lib/view/expenseAutomationView/selectorTypes/actualMatchingViewSelectorTypes.d.ts +16 -2
- package/lib/view/expenseAutomationView/selectors/actualMatchingViewSelector.d.ts +17 -2
- package/lib/view/expenseAutomationView/selectors/actualMatchingViewSelector.js +148 -98
- package/lib/view/expenseAutomationView/types/actualMatchingViewState.d.ts +20 -2
- package/lib/view/expenseAutomationView/types/actualMatchingViewState.js +12 -1
- package/package.json +1 -1
|
@@ -13,10 +13,17 @@ export type ActualMatchingGroupedAccrual = {
|
|
|
13
13
|
serviceMonth?: string;
|
|
14
14
|
};
|
|
15
15
|
export interface ActualMatchingRow extends JEOneTimeAccrual {
|
|
16
|
+
accruedAmount: Amount;
|
|
17
|
+
actualAmount: Amount;
|
|
16
18
|
kind: ActualMatchingRowKind;
|
|
19
|
+
matchId: string;
|
|
17
20
|
groupedAccrualIds?: ID[];
|
|
18
21
|
groupedMembers?: ActualMatchingGroupedAccrual[];
|
|
22
|
+
matchShape?: string;
|
|
23
|
+
matchTier?: string;
|
|
19
24
|
reversalDate?: ZeniDate;
|
|
25
|
+
transactionDate?: string;
|
|
26
|
+
transactionType?: string;
|
|
20
27
|
}
|
|
21
28
|
export interface ActualMatchingKpiSummary {
|
|
22
29
|
ai: {
|
|
@@ -56,14 +63,21 @@ export interface ActualMatchingMatchModalView {
|
|
|
56
63
|
results: ActualMatchingTransactionSearchResult[];
|
|
57
64
|
};
|
|
58
65
|
lastBatchResults?: MatchAndReverseResult[];
|
|
66
|
+
openedFromMatchId?: string;
|
|
67
|
+
prefill?: {
|
|
68
|
+
selectedAccrualIds: ID[];
|
|
69
|
+
actualAmount?: number;
|
|
70
|
+
matchedLineId?: string;
|
|
71
|
+
matchedTransactionId?: string;
|
|
72
|
+
};
|
|
59
73
|
}
|
|
60
74
|
export interface ExpenseAutomationActualMatchingViewSelector extends SelectorView {
|
|
61
|
-
autoReversed: ActualMatchingRow[];
|
|
62
75
|
hasLoadedForSelectedPeriod: boolean;
|
|
63
76
|
kpiSummary: ActualMatchingKpiSummary;
|
|
64
|
-
manuallyReversed: ActualMatchingRow[];
|
|
65
77
|
matchModal: ActualMatchingMatchModalView;
|
|
66
78
|
pendingReview: ActualMatchingRow[];
|
|
67
79
|
refreshStatus: FetchStateAndError;
|
|
80
|
+
reversed: ActualMatchingRow[];
|
|
68
81
|
uiState: ActualMatchingViewUIState;
|
|
82
|
+
undoReversalStatus?: FetchStateAndError;
|
|
69
83
|
}
|
|
@@ -1,11 +1,26 @@
|
|
|
1
|
+
import { FetchStateAndError } from '../../../commonStateTypes/common';
|
|
2
|
+
import { ActualMatchingMatch } from '../../../entity/actualMatching/actualMatchingState';
|
|
3
|
+
import { ActualMatchingMatchId } from '../../../entity/actualMatching/actualMatchingTypes';
|
|
1
4
|
import { JEOneTimeAccrual } from '../../../entity/jeSchedules/jeSchedulesSelector';
|
|
2
5
|
import { RootState } from '../../../rootStateTypes';
|
|
3
6
|
import { ZeniDate } from '../../../zeniDayJS';
|
|
4
|
-
import { ExpenseAutomationActualMatchingViewSelector } from '../selectorTypes/actualMatchingViewSelectorTypes';
|
|
7
|
+
import { ActualMatchingRow, ActualMatchingRowKind, ExpenseAutomationActualMatchingViewSelector } from '../selectorTypes/actualMatchingViewSelectorTypes';
|
|
8
|
+
export declare function parseActualMatchingMatchId(matchId: string): {
|
|
9
|
+
transactionIntegrationId: string;
|
|
10
|
+
transactionType: string;
|
|
11
|
+
} | null;
|
|
5
12
|
export declare function isAutoReversedAccrual(accrual: JEOneTimeAccrual): boolean;
|
|
6
13
|
export declare function isManuallyReversedAccrual(accrual: JEOneTimeAccrual): boolean;
|
|
7
14
|
export declare function isPendingReviewAccrual(accrual: JEOneTimeAccrual): boolean;
|
|
15
|
+
export declare function isReversedMatchKind(kind: ActualMatchingRowKind): boolean;
|
|
8
16
|
export declare function getClearedMatchedAmount(accrual: JEOneTimeAccrual): number | undefined;
|
|
9
|
-
export declare function getActualMatchingAmount(
|
|
17
|
+
export declare function getActualMatchingAmount(row: ActualMatchingRow): number;
|
|
10
18
|
export declare function getActualMatchingReversalDate(accrual: JEOneTimeAccrual): ZeniDate | undefined;
|
|
19
|
+
export interface ExpenseAutomationActualMatchingMatchView {
|
|
20
|
+
detailFetchState: FetchStateAndError;
|
|
21
|
+
refreshStatus: FetchStateAndError;
|
|
22
|
+
undoReversalStatus: FetchStateAndError;
|
|
23
|
+
match?: ActualMatchingMatch;
|
|
24
|
+
}
|
|
25
|
+
export declare function getExpenseAutomationActualMatchingMatchView(state: RootState, matchId: ActualMatchingMatchId): ExpenseAutomationActualMatchingMatchView;
|
|
11
26
|
export declare function getExpenseAutomationActualMatchingView(state: RootState): ExpenseAutomationActualMatchingViewSelector;
|
|
@@ -3,17 +3,66 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
3
3
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
4
|
};
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.parseActualMatchingMatchId = parseActualMatchingMatchId;
|
|
6
7
|
exports.isAutoReversedAccrual = isAutoReversedAccrual;
|
|
7
8
|
exports.isManuallyReversedAccrual = isManuallyReversedAccrual;
|
|
8
9
|
exports.isPendingReviewAccrual = isPendingReviewAccrual;
|
|
10
|
+
exports.isReversedMatchKind = isReversedMatchKind;
|
|
9
11
|
exports.getClearedMatchedAmount = getClearedMatchedAmount;
|
|
10
12
|
exports.getActualMatchingAmount = getActualMatchingAmount;
|
|
11
13
|
exports.getActualMatchingReversalDate = getActualMatchingReversalDate;
|
|
14
|
+
exports.getExpenseAutomationActualMatchingMatchView = getExpenseAutomationActualMatchingMatchView;
|
|
12
15
|
exports.getExpenseAutomationActualMatchingView = getExpenseAutomationActualMatchingView;
|
|
13
16
|
const orderBy_1 = __importDefault(require("lodash/orderBy"));
|
|
14
17
|
const timePeriod_1 = require("../../../commonStateTypes/timePeriod");
|
|
18
|
+
const actualMatchingSelector_1 = require("../../../entity/actualMatching/actualMatchingSelector");
|
|
19
|
+
const jeScheduleHelper_1 = require("../../../entity/jeSchedules/jeScheduleHelper");
|
|
15
20
|
const jeSchedulesSelector_1 = require("../../../entity/jeSchedules/jeSchedulesSelector");
|
|
16
21
|
const tenantSelector_1 = require("../../../entity/tenant/tenantSelector");
|
|
22
|
+
function toMatchModalAccrual(member) {
|
|
23
|
+
if ('jeOneTimeAccrualKey' in member && member.jeOneTimeAccrualKey != null) {
|
|
24
|
+
return member;
|
|
25
|
+
}
|
|
26
|
+
return {
|
|
27
|
+
...member,
|
|
28
|
+
jeOneTimeAccrualKey: (0, jeScheduleHelper_1.generateJEOneTimeAccrualKey)(member.accrualId),
|
|
29
|
+
};
|
|
30
|
+
}
|
|
31
|
+
function uniqueMatchModalAccruals(pinned, searched) {
|
|
32
|
+
const byId = new Map();
|
|
33
|
+
pinned.forEach((row) => byId.set(row.accrualId, row));
|
|
34
|
+
searched.forEach((row) => {
|
|
35
|
+
if (!byId.has(row.accrualId)) {
|
|
36
|
+
byId.set(row.accrualId, row);
|
|
37
|
+
}
|
|
38
|
+
});
|
|
39
|
+
return Array.from(byId.values());
|
|
40
|
+
}
|
|
41
|
+
function uniqueTransactionSearchResults(pinned, searched) {
|
|
42
|
+
const byKey = new Map();
|
|
43
|
+
pinned.forEach((row) => byKey.set(`${row.transactionId}:${row.lineId}`, row));
|
|
44
|
+
searched.forEach((row) => {
|
|
45
|
+
const key = `${row.transactionId}:${row.lineId}`;
|
|
46
|
+
if (!byKey.has(key)) {
|
|
47
|
+
byKey.set(key, row);
|
|
48
|
+
}
|
|
49
|
+
});
|
|
50
|
+
return Array.from(byKey.values());
|
|
51
|
+
}
|
|
52
|
+
function parseActualMatchingMatchId(matchId) {
|
|
53
|
+
const separator = matchId.indexOf(':');
|
|
54
|
+
if (separator <= 0 || separator === matchId.length - 1) {
|
|
55
|
+
return null;
|
|
56
|
+
}
|
|
57
|
+
return {
|
|
58
|
+
transactionType: matchId.slice(0, separator).toLowerCase(),
|
|
59
|
+
transactionIntegrationId: matchId.slice(separator + 1),
|
|
60
|
+
};
|
|
61
|
+
}
|
|
62
|
+
const NOT_STARTED = {
|
|
63
|
+
fetchState: 'Not-Started',
|
|
64
|
+
error: undefined,
|
|
65
|
+
};
|
|
17
66
|
function isAutoReversedAccrual(accrual) {
|
|
18
67
|
return (accrual.accrualStatus === 'reversed' &&
|
|
19
68
|
accrual.reversalTrigger === 'bill_match');
|
|
@@ -29,18 +78,14 @@ function isPendingReviewAccrual(accrual) {
|
|
|
29
78
|
const resolution = accrual.matchSuggestion.resolution;
|
|
30
79
|
return resolution == null || resolution.length === 0;
|
|
31
80
|
}
|
|
81
|
+
function isReversedMatchKind(kind) {
|
|
82
|
+
return kind === 'auto_reversed' || kind === 'manually_reversed';
|
|
83
|
+
}
|
|
32
84
|
function getClearedMatchedAmount(accrual) {
|
|
33
85
|
return accrual.cleared?.matchedAmount?.amount;
|
|
34
86
|
}
|
|
35
|
-
function getActualMatchingAmount(
|
|
36
|
-
|
|
37
|
-
return (accrual.matchSuggestion?.matchedAmount?.amount ??
|
|
38
|
-
accrual.estimatedAmount.amount);
|
|
39
|
-
}
|
|
40
|
-
if (isAutoReversedAccrual(accrual) || isManuallyReversedAccrual(accrual)) {
|
|
41
|
-
return getClearedMatchedAmount(accrual) ?? accrual.estimatedAmount.amount;
|
|
42
|
-
}
|
|
43
|
-
return accrual.estimatedAmount.amount;
|
|
87
|
+
function getActualMatchingAmount(row) {
|
|
88
|
+
return row.actualAmount?.amount ?? row.estimatedAmount.amount;
|
|
44
89
|
}
|
|
45
90
|
function getActualMatchingReversalDate(accrual) {
|
|
46
91
|
if (isPendingReviewAccrual(accrual)) {
|
|
@@ -48,40 +93,6 @@ function getActualMatchingReversalDate(accrual) {
|
|
|
48
93
|
}
|
|
49
94
|
return accrual.cleared?.matchedTransactionDate;
|
|
50
95
|
}
|
|
51
|
-
function getActualMatchingBillCollapseKey(accrual) {
|
|
52
|
-
const stamp = isPendingReviewAccrual(accrual)
|
|
53
|
-
? accrual.matchSuggestion
|
|
54
|
-
: accrual.cleared;
|
|
55
|
-
const txnId = stamp?.matchedTransactionId;
|
|
56
|
-
if (txnId != null && txnId !== '') {
|
|
57
|
-
return `txn:${txnId}`;
|
|
58
|
-
}
|
|
59
|
-
const integrationId = stamp?.matchedTransactionIntegrationId;
|
|
60
|
-
if (integrationId != null && integrationId !== '') {
|
|
61
|
-
return `int:${integrationId}`;
|
|
62
|
-
}
|
|
63
|
-
const ids = accrual.cleared?.accrualIds;
|
|
64
|
-
if (ids != null && ids.length > 1) {
|
|
65
|
-
return `cleared:${[...ids].sort().join(',')}`;
|
|
66
|
-
}
|
|
67
|
-
return `accrual:${accrual.accrualId}`;
|
|
68
|
-
}
|
|
69
|
-
function collectGroupedAccrualIds(members) {
|
|
70
|
-
const stampIds = members[0]?.cleared?.accrualIds;
|
|
71
|
-
const memberIds = members.map((member) => member.accrualId);
|
|
72
|
-
if (stampIds != null && stampIds.length >= memberIds.length) {
|
|
73
|
-
return stampIds;
|
|
74
|
-
}
|
|
75
|
-
const seen = new Set();
|
|
76
|
-
const grouped = [];
|
|
77
|
-
for (const id of [...(stampIds ?? []), ...memberIds]) {
|
|
78
|
-
if (!seen.has(id)) {
|
|
79
|
-
seen.add(id);
|
|
80
|
-
grouped.push(id);
|
|
81
|
-
}
|
|
82
|
-
}
|
|
83
|
-
return grouped;
|
|
84
|
-
}
|
|
85
96
|
function collectGroupedMembers(members) {
|
|
86
97
|
if (members.length <= 1) {
|
|
87
98
|
return undefined;
|
|
@@ -94,51 +105,48 @@ function collectGroupedMembers(members) {
|
|
|
94
105
|
serviceMonth: member.serviceMonth,
|
|
95
106
|
}));
|
|
96
107
|
}
|
|
97
|
-
function toActualMatchingRow(
|
|
98
|
-
const
|
|
108
|
+
function toActualMatchingRow(match) {
|
|
109
|
+
const firstMember = match.members[0];
|
|
110
|
+
if (firstMember == null) {
|
|
111
|
+
throw new Error('Actual matching row requires at least one member');
|
|
112
|
+
}
|
|
113
|
+
const first = toMatchModalAccrual(firstMember);
|
|
99
114
|
return {
|
|
100
|
-
...
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
115
|
+
...first,
|
|
116
|
+
matchId: match.matchId,
|
|
117
|
+
kind: match.kind,
|
|
118
|
+
accruedAmount: match.accruedAmount,
|
|
119
|
+
actualAmount: match.actualAmount,
|
|
120
|
+
matchTier: match.matchTier,
|
|
121
|
+
matchShape: match.matchShape,
|
|
122
|
+
transactionType: match.transactionType,
|
|
123
|
+
transactionDate: match.transactionDate,
|
|
124
|
+
groupedAccrualIds: match.members.map((member) => member.accrualId),
|
|
125
|
+
groupedMembers: collectGroupedMembers(match.members),
|
|
126
|
+
reversalDate: getActualMatchingReversalDate(first),
|
|
127
|
+
vendorName: match.vendorName !== '' ? match.vendorName : first.vendorName,
|
|
128
|
+
estimatedAmount: match.accruedAmount,
|
|
105
129
|
};
|
|
106
130
|
}
|
|
107
|
-
function
|
|
108
|
-
const groups = new Map();
|
|
109
|
-
for (const accrual of accruals) {
|
|
110
|
-
const key = getActualMatchingBillCollapseKey(accrual);
|
|
111
|
-
const members = groups.get(key);
|
|
112
|
-
if (members != null) {
|
|
113
|
-
members.push(accrual);
|
|
114
|
-
}
|
|
115
|
-
else {
|
|
116
|
-
groups.set(key, [accrual]);
|
|
117
|
-
}
|
|
118
|
-
}
|
|
119
|
-
const rows = [];
|
|
120
|
-
for (const members of groups.values()) {
|
|
121
|
-
rows.push(toActualMatchingRow(members, kind));
|
|
122
|
-
}
|
|
123
|
-
return rows;
|
|
124
|
-
}
|
|
125
|
-
function sumCollapsedActualMatchingAmounts(rows) {
|
|
126
|
-
return rows.reduce((sum, row) => sum + getActualMatchingAmount(row), 0);
|
|
127
|
-
}
|
|
128
|
-
function matchesSearch(accrual, searchString) {
|
|
131
|
+
function matchesSearch(row, searchString) {
|
|
129
132
|
const trimmed = searchString.trim().toLowerCase();
|
|
130
133
|
if (trimmed.length === 0) {
|
|
131
134
|
return true;
|
|
132
135
|
}
|
|
133
|
-
|
|
134
|
-
|
|
136
|
+
if (row.vendorName.toLowerCase().includes(trimmed)) {
|
|
137
|
+
return true;
|
|
138
|
+
}
|
|
139
|
+
if (row.memo.toLowerCase().includes(trimmed)) {
|
|
140
|
+
return true;
|
|
141
|
+
}
|
|
142
|
+
return (row.groupedMembers ?? []).some((member) => (member.memo ?? '').toLowerCase().includes(trimmed));
|
|
135
143
|
}
|
|
136
144
|
function getActualMatchingSortValue(row, sortKey) {
|
|
137
145
|
switch (sortKey) {
|
|
138
146
|
case 'vendor':
|
|
139
147
|
return row.vendorName.toLowerCase();
|
|
140
148
|
case 'date':
|
|
141
|
-
return row.reversalDate?.valueOf();
|
|
149
|
+
return row.reversalDate?.valueOf() ?? row.transactionDate;
|
|
142
150
|
case 'amount':
|
|
143
151
|
return getActualMatchingAmount(row);
|
|
144
152
|
case 'category':
|
|
@@ -146,10 +154,23 @@ function getActualMatchingSortValue(row, sortKey) {
|
|
|
146
154
|
case 'class':
|
|
147
155
|
return row.jeDebitAccountingClassName?.toLowerCase();
|
|
148
156
|
case 'type':
|
|
149
|
-
return
|
|
150
|
-
row.matchSuggestion?.matchedTransactionType)?.toLowerCase();
|
|
157
|
+
return row.transactionType?.toLowerCase();
|
|
151
158
|
case 'lifecycle':
|
|
152
159
|
return row.kind;
|
|
160
|
+
case 'service':
|
|
161
|
+
return row.serviceMonth;
|
|
162
|
+
case 'accrued':
|
|
163
|
+
return row.accruedAmount?.amount ?? row.estimatedAmount.amount;
|
|
164
|
+
case 'actual':
|
|
165
|
+
return row.actualAmount?.amount;
|
|
166
|
+
case 'variance': {
|
|
167
|
+
const accrued = row.accruedAmount?.amount ?? row.estimatedAmount.amount;
|
|
168
|
+
const actual = row.actualAmount?.amount;
|
|
169
|
+
if (actual == null || accrued === 0) {
|
|
170
|
+
return undefined;
|
|
171
|
+
}
|
|
172
|
+
return ((actual - accrued) / Math.abs(accrued)) * 100;
|
|
173
|
+
}
|
|
153
174
|
default:
|
|
154
175
|
return undefined;
|
|
155
176
|
}
|
|
@@ -167,37 +188,51 @@ function emptyKpiSummary() {
|
|
|
167
188
|
manual: { count: 0 },
|
|
168
189
|
};
|
|
169
190
|
}
|
|
191
|
+
function sumRowAmounts(rows) {
|
|
192
|
+
return rows.reduce((sum, row) => sum + getActualMatchingAmount(row), 0);
|
|
193
|
+
}
|
|
194
|
+
function getExpenseAutomationActualMatchingMatchView(state, matchId) {
|
|
195
|
+
const view = state.expenseAutomationActualMatchingViewState;
|
|
196
|
+
return {
|
|
197
|
+
match: (0, actualMatchingSelector_1.getActualMatchingMatchById)(matchId, state.actualMatchingState),
|
|
198
|
+
detailFetchState: view.detailFetchStateByMatchId[matchId] ?? NOT_STARTED,
|
|
199
|
+
refreshStatus: view.detailRefreshStatusByMatchId[matchId] ?? NOT_STARTED,
|
|
200
|
+
undoReversalStatus: view.undoReversalStatus ?? NOT_STARTED,
|
|
201
|
+
};
|
|
202
|
+
}
|
|
170
203
|
function getExpenseAutomationActualMatchingView(state) {
|
|
171
204
|
const { expenseAutomationActualMatchingViewState, expenseAutomationViewState } = state;
|
|
172
|
-
const {
|
|
205
|
+
const { matchIdsByPeriod, fetchState, error, refreshStatus, uiState, matchModal, undoReversalStatus, } = expenseAutomationActualMatchingViewState;
|
|
173
206
|
const currentTenant = (0, tenantSelector_1.getCurrentTenant)(state);
|
|
174
207
|
const selectedPeriod = expenseAutomationViewState.selectedPeriodByTenantId[currentTenant.tenantId];
|
|
175
208
|
const monthYearPeriodId = selectedPeriod != null ? (0, timePeriod_1.toMonthYearPeriodId)(selectedPeriod) : undefined;
|
|
176
|
-
const
|
|
177
|
-
?
|
|
209
|
+
const matchIds = monthYearPeriodId != null
|
|
210
|
+
? matchIdsByPeriod[monthYearPeriodId]
|
|
178
211
|
: undefined;
|
|
179
|
-
const
|
|
180
|
-
.map((
|
|
181
|
-
.filter((
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
const
|
|
186
|
-
const
|
|
212
|
+
const rows = (matchIds ?? [])
|
|
213
|
+
.map((matchId) => (0, actualMatchingSelector_1.getActualMatchingMatchById)(matchId, state.actualMatchingState))
|
|
214
|
+
.filter((match) => match != null)
|
|
215
|
+
.filter((match) => match.members.length > 0)
|
|
216
|
+
.map(toActualMatchingRow)
|
|
217
|
+
.filter((row) => matchesSearch(row, uiState.searchString));
|
|
218
|
+
const reversed = sortActualMatchingRows(rows.filter((row) => isReversedMatchKind(row.kind)), uiState);
|
|
219
|
+
const pendingReview = sortActualMatchingRows(rows.filter((row) => row.kind === 'pending_review'), uiState);
|
|
220
|
+
const autoReversedForKpi = reversed.filter((row) => row.kind === 'auto_reversed');
|
|
221
|
+
const listedRows = [...reversed, ...pendingReview];
|
|
187
222
|
const kpiSummary = listedRows.length === 0
|
|
188
223
|
? emptyKpiSummary()
|
|
189
224
|
: {
|
|
190
225
|
autoReversed: {
|
|
191
|
-
count:
|
|
192
|
-
amount:
|
|
226
|
+
count: autoReversedForKpi.length,
|
|
227
|
+
amount: sumRowAmounts(autoReversedForKpi),
|
|
193
228
|
},
|
|
194
229
|
pendingReview: {
|
|
195
230
|
count: pendingReview.length,
|
|
196
|
-
amount:
|
|
231
|
+
amount: sumRowAmounts(pendingReview),
|
|
197
232
|
},
|
|
198
233
|
totalThisClose: {
|
|
199
234
|
count: listedRows.length,
|
|
200
|
-
amount:
|
|
235
|
+
amount: sumRowAmounts(listedRows),
|
|
201
236
|
},
|
|
202
237
|
ai: {
|
|
203
238
|
count: listedRows.filter((row) => row.origin === 'agent').length,
|
|
@@ -206,26 +241,41 @@ function getExpenseAutomationActualMatchingView(state) {
|
|
|
206
241
|
count: listedRows.filter((row) => row.origin === 'human').length,
|
|
207
242
|
},
|
|
208
243
|
};
|
|
209
|
-
const
|
|
244
|
+
const searchedAccruals = matchModal.accrualSearch.results
|
|
210
245
|
.map((key) => (0, jeSchedulesSelector_1.getJEOneTimeAccrualByKey)(key, state.jeSchedulesState))
|
|
211
246
|
.filter((accrual) => accrual != null);
|
|
247
|
+
const openedMatch = matchModal.openedFromMatchId != null
|
|
248
|
+
? (0, actualMatchingSelector_1.getActualMatchingMatchById)(matchModal.openedFromMatchId, state.actualMatchingState)
|
|
249
|
+
: undefined;
|
|
250
|
+
const pinnedAccruals = (openedMatch?.members ?? []).map(toMatchModalAccrual);
|
|
251
|
+
const firstSuggestion = openedMatch?.members[0]?.matchSuggestion;
|
|
252
|
+
const prefill = openedMatch == null
|
|
253
|
+
? undefined
|
|
254
|
+
: {
|
|
255
|
+
selectedAccrualIds: openedMatch.members.map((member) => member.accrualId),
|
|
256
|
+
actualAmount: openedMatch.actualAmount.amount,
|
|
257
|
+
matchedLineId: firstSuggestion?.matchedLineId,
|
|
258
|
+
matchedTransactionId: firstSuggestion?.matchedTransactionId,
|
|
259
|
+
};
|
|
212
260
|
return {
|
|
213
261
|
fetchState,
|
|
214
262
|
error,
|
|
215
|
-
|
|
263
|
+
reversed,
|
|
216
264
|
pendingReview,
|
|
217
|
-
manuallyReversed,
|
|
218
265
|
kpiSummary,
|
|
219
266
|
uiState,
|
|
220
267
|
refreshStatus,
|
|
221
|
-
hasLoadedForSelectedPeriod:
|
|
268
|
+
hasLoadedForSelectedPeriod: matchIds != null,
|
|
269
|
+
undoReversalStatus,
|
|
222
270
|
matchModal: {
|
|
223
271
|
isOpen: matchModal.isOpen,
|
|
272
|
+
openedFromMatchId: matchModal.openedFromMatchId,
|
|
273
|
+
prefill,
|
|
224
274
|
confirmStatus: matchModal.confirmStatus,
|
|
225
275
|
lastBatchResults: matchModal.lastBatchResults,
|
|
226
276
|
transactionSearch: {
|
|
227
277
|
query: matchModal.transactionSearch.query,
|
|
228
|
-
results: matchModal.transactionSearch.results,
|
|
278
|
+
results: uniqueTransactionSearchResults(matchModal.pinnedTransactionResults, matchModal.transactionSearch.results),
|
|
229
279
|
fetchState: {
|
|
230
280
|
fetchState: matchModal.transactionSearch.fetchState,
|
|
231
281
|
error: matchModal.transactionSearch.error,
|
|
@@ -235,7 +285,7 @@ function getExpenseAutomationActualMatchingView(state) {
|
|
|
235
285
|
},
|
|
236
286
|
accrualSearch: {
|
|
237
287
|
query: matchModal.accrualSearch.query,
|
|
238
|
-
results:
|
|
288
|
+
results: uniqueMatchModalAccruals(pinnedAccruals, searchedAccruals),
|
|
239
289
|
fetchState: {
|
|
240
290
|
fetchState: matchModal.accrualSearch.fetchState,
|
|
241
291
|
error: matchModal.accrualSearch.error,
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import { FetchStateAndError, FetchedState, ID } from '../../../commonStateTypes/common';
|
|
2
2
|
import { SortOrder } from '../../../commonStateTypes/selectorTypes/sortOrderTypes';
|
|
3
3
|
import { MonthYearPeriodId } from '../../../commonStateTypes/timePeriod';
|
|
4
|
+
import { ActualMatchingMatchId } from '../../../entity/actualMatching/actualMatchingTypes';
|
|
4
5
|
import { JEOneTimeAccrualKey } from '../../../entity/jeSchedules/jeSchedulesTypes';
|
|
5
|
-
export declare const toActualMatchingSortKey: (v: string) => "type" | "date" | "vendor" | "category" | "class" | "amount" | "lifecycle";
|
|
6
|
+
export declare const toActualMatchingSortKey: (v: string) => "type" | "date" | "vendor" | "category" | "class" | "amount" | "variance" | "lifecycle" | "service" | "accrued" | "actual";
|
|
6
7
|
export type ActualMatchingSortKey = ReturnType<typeof toActualMatchingSortKey>;
|
|
7
8
|
export declare const MATCH_TRANSACTION_SEARCH_PAGE_SIZE = 50;
|
|
8
9
|
export declare const MATCH_ACCRUAL_SEARCH_LIMIT = 50;
|
|
@@ -27,6 +28,7 @@ export interface ActualMatchingTransactionSearchResult {
|
|
|
27
28
|
currencyCode: string;
|
|
28
29
|
currencySymbol: string;
|
|
29
30
|
lineId: string;
|
|
31
|
+
syncToken: string;
|
|
30
32
|
transactionDate: string;
|
|
31
33
|
transactionId: ID;
|
|
32
34
|
transactionIntegrationId: string;
|
|
@@ -52,8 +54,19 @@ export interface MatchAndReverseAccrualsParams {
|
|
|
52
54
|
lineId: string;
|
|
53
55
|
transactionId: ID;
|
|
54
56
|
transactionIntegrationId: string;
|
|
57
|
+
transactionSyncToken: string;
|
|
55
58
|
transactionType: string;
|
|
56
59
|
}
|
|
60
|
+
export declare const toUndoReversalResultStatus: (v: string) => "error" | "claim_lost" | "undone";
|
|
61
|
+
export type UndoReversalResultStatus = ReturnType<typeof toUndoReversalResultStatus>;
|
|
62
|
+
export interface UndoReversalResult {
|
|
63
|
+
accrualId: ID;
|
|
64
|
+
status: UndoReversalResultStatus;
|
|
65
|
+
reason?: string;
|
|
66
|
+
}
|
|
67
|
+
export interface UndoReversalAccrualsParams {
|
|
68
|
+
accrualIds: ID[];
|
|
69
|
+
}
|
|
57
70
|
export interface ActualMatchingTransactionSearchState extends FetchStateAndError {
|
|
58
71
|
isLoadingMore: boolean;
|
|
59
72
|
nextPageToken: string | null;
|
|
@@ -70,12 +83,17 @@ export interface ActualMatchingMatchModalState {
|
|
|
70
83
|
accrualSearch: ActualMatchingAccrualSearchState;
|
|
71
84
|
confirmStatus: FetchStateAndError;
|
|
72
85
|
isOpen: boolean;
|
|
86
|
+
pinnedTransactionResults: ActualMatchingTransactionSearchResult[];
|
|
73
87
|
transactionSearch: ActualMatchingTransactionSearchState;
|
|
74
88
|
lastBatchResults?: MatchAndReverseResult[];
|
|
89
|
+
openedFromMatchId?: ActualMatchingMatchId;
|
|
75
90
|
}
|
|
76
91
|
export interface ActualMatchingViewState extends FetchedState {
|
|
77
|
-
|
|
92
|
+
detailFetchStateByMatchId: Record<ActualMatchingMatchId, FetchStateAndError>;
|
|
93
|
+
detailRefreshStatusByMatchId: Record<ActualMatchingMatchId, FetchStateAndError>;
|
|
94
|
+
matchIdsByPeriod: Record<MonthYearPeriodId, ActualMatchingMatchId[]>;
|
|
78
95
|
matchModal: ActualMatchingMatchModalState;
|
|
79
96
|
refreshStatus: FetchStateAndError;
|
|
80
97
|
uiState: ActualMatchingViewUIState;
|
|
98
|
+
undoReversalStatus: FetchStateAndError;
|
|
81
99
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.toMatchAndReverseResultStatus = exports.MATCH_SEARCH_DEBOUNCE_MS = exports.MATCH_ACCRUAL_SEARCH_LIMIT = exports.MATCH_TRANSACTION_SEARCH_PAGE_SIZE = exports.toActualMatchingSortKey = void 0;
|
|
3
|
+
exports.toUndoReversalResultStatus = exports.toMatchAndReverseResultStatus = exports.MATCH_SEARCH_DEBOUNCE_MS = exports.MATCH_ACCRUAL_SEARCH_LIMIT = exports.MATCH_TRANSACTION_SEARCH_PAGE_SIZE = exports.toActualMatchingSortKey = void 0;
|
|
4
4
|
const stringToUnion_1 = require("../../../commonStateTypes/stringToUnion");
|
|
5
5
|
const ACTUAL_MATCHING_SORT_KEYS = [
|
|
6
6
|
'vendor',
|
|
@@ -10,6 +10,10 @@ const ACTUAL_MATCHING_SORT_KEYS = [
|
|
|
10
10
|
'class',
|
|
11
11
|
'type',
|
|
12
12
|
'lifecycle',
|
|
13
|
+
'service',
|
|
14
|
+
'accrued',
|
|
15
|
+
'actual',
|
|
16
|
+
'variance',
|
|
13
17
|
];
|
|
14
18
|
const toActualMatchingSortKey = (v) => (0, stringToUnion_1.stringToUnion)(v, ACTUAL_MATCHING_SORT_KEYS);
|
|
15
19
|
exports.toActualMatchingSortKey = toActualMatchingSortKey;
|
|
@@ -25,3 +29,10 @@ const MATCH_AND_REVERSE_RESULT_STATUSES = [
|
|
|
25
29
|
];
|
|
26
30
|
const toMatchAndReverseResultStatus = (v) => (0, stringToUnion_1.stringToUnion)(v, MATCH_AND_REVERSE_RESULT_STATUSES);
|
|
27
31
|
exports.toMatchAndReverseResultStatus = toMatchAndReverseResultStatus;
|
|
32
|
+
const UNDO_REVERSAL_RESULT_STATUSES = [
|
|
33
|
+
'undone',
|
|
34
|
+
'claim_lost',
|
|
35
|
+
'error',
|
|
36
|
+
];
|
|
37
|
+
const toUndoReversalResultStatus = (v) => (0, stringToUnion_1.stringToUnion)(v, UNDO_REVERSAL_RESULT_STATUSES);
|
|
38
|
+
exports.toUndoReversalResultStatus = toUndoReversalResultStatus;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@zeniai/client-epic-state",
|
|
3
|
-
"version": "5.2.22-
|
|
3
|
+
"version": "5.2.22-betaMM1",
|
|
4
4
|
"description": "Shared module between Web & Mobile containing required abstractions for state management, async network communication. ",
|
|
5
5
|
"main": "lib/index.js",
|
|
6
6
|
"module": "lib/esm/index.js",
|