@zeniai/client-epic-state 5.2.34-beta0ND → 5.2.35-beta0MM
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 +43 -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 +29 -0
- package/lib/entity/jeSchedules/jeSchedulesPayload.js +49 -0
- package/lib/entity/jeSchedules/jeSchedulesState.d.ts +31 -0
- package/lib/entity/notificationRegistry/notificationRegistryReducer.d.ts +1 -2
- package/lib/entity/notificationRegistry/notificationRegistryReducer.js +9 -20
- package/lib/entity/notificationRegistry/notificationRegistrySelector.d.ts +1 -2
- package/lib/entity/notificationRegistry/notificationRegistrySelector.js +1 -7
- package/lib/entity/notificationRegistry/notificationRegistryState.d.ts +0 -5
- package/lib/entity/notificationRegistry/notificationRegistryState.js +1 -7
- package/lib/entity/sectionProjectView/sectionProjectViewReducer.js +1 -3
- package/lib/epic.d.ts +8 -1
- package/lib/epic.js +18 -4
- package/lib/esm/entity/actualMatching/actualMatchingPayload.js +40 -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 +49 -0
- package/lib/esm/entity/notificationRegistry/notificationRegistryReducer.js +9 -20
- package/lib/esm/entity/notificationRegistry/notificationRegistrySelector.js +0 -5
- package/lib/esm/entity/notificationRegistry/notificationRegistryState.js +0 -5
- package/lib/esm/entity/sectionProjectView/sectionProjectViewReducer.js +1 -3
- package/lib/esm/epic.js +18 -4
- package/lib/esm/index.js +10 -6
- package/lib/esm/reducer.js +6 -0
- package/lib/esm/view/aiCfoView/aiCfoViewReducer.js +2 -4
- package/lib/esm/view/aiCfoView/epics/fetchRoutineRunsEpic.js +1 -3
- package/lib/esm/view/expenseAutomationView/epics/actualMatching/fetchActualMatchingEpic.js +46 -0
- package/lib/esm/view/expenseAutomationView/epics/actualMatching/fetchActualMatchingMatchEpic.js +35 -0
- package/lib/esm/view/expenseAutomationView/epics/actualMatching/fetchActualMatchingPageEpic.js +7 -0
- package/lib/esm/view/expenseAutomationView/epics/actualMatching/matchAndReverseAccrualsEpic.js +52 -0
- package/lib/esm/view/expenseAutomationView/epics/actualMatching/searchMatchAccrualsEpic.js +44 -0
- package/lib/esm/view/expenseAutomationView/epics/actualMatching/searchMatchTransactionsEpic.js +73 -0
- package/lib/esm/view/expenseAutomationView/epics/actualMatching/undoReversalAccrualsEpic.js +52 -0
- package/lib/esm/view/expenseAutomationView/epics/common/fetchAllExpenseAutomationTabsEpic.js +28 -11
- package/lib/esm/view/expenseAutomationView/epics/common/refreshExpenseAutomationCurrentTabEpic.js +9 -1
- package/lib/esm/view/expenseAutomationView/epics/jeSchedule/prefetchOtherJeSchedulesTabEpic.js +3 -1
- package/lib/esm/view/expenseAutomationView/epics/jeSchedule/switchJESchedulesTabEpic.js +5 -0
- package/lib/esm/view/expenseAutomationView/expenseAutomationViewSelector.js +22 -7
- package/lib/esm/view/expenseAutomationView/payload/actualMatchingPayload.js +68 -0
- package/lib/esm/view/expenseAutomationView/reducers/actualMatchingViewReducer.js +364 -0
- package/lib/esm/view/expenseAutomationView/selectorTypes/actualMatchingViewSelectorTypes.js +1 -0
- package/lib/esm/view/expenseAutomationView/selectors/actualMatchingViewSelector.js +281 -0
- package/lib/esm/view/expenseAutomationView/selectors/jeSchedulesViewSelector.js +3 -0
- package/lib/esm/view/expenseAutomationView/types/actualMatchingViewState.js +32 -0
- package/lib/esm/view/expenseAutomationView/types/jeSchedulesViewState.js +5 -1
- package/lib/esm/view/notificationPreferencesView/epics/saveNotificationPreferencesEpic.js +7 -20
- package/lib/esm/view/notificationPreferencesView/notificationPreferencesViewReducer.js +17 -43
- package/lib/esm/view/notificationPreferencesView/notificationPreferencesViewSelector.js +4 -24
- package/lib/esm/view/settingsView/epic/fetchNotificationSettingsEpic.js +2 -12
- package/lib/index.d.ts +16 -8
- package/lib/index.js +78 -55
- package/lib/reducer.d.ts +2 -0
- package/lib/reducer.js +6 -0
- package/lib/rootStateTypes.d.ts +4 -0
- package/lib/view/aiCfoView/aiCfoViewReducer.js +2 -4
- package/lib/view/aiCfoView/aiCfoViewSelector.d.ts +1 -1
- package/lib/view/aiCfoView/epics/fetchRoutineRunsEpic.js +1 -3
- package/lib/view/expenseAutomationView/epics/actualMatching/fetchActualMatchingEpic.d.ts +9 -0
- package/lib/view/expenseAutomationView/epics/actualMatching/fetchActualMatchingEpic.js +50 -0
- 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/fetchActualMatchingPageEpic.d.ts +5 -0
- package/lib/view/expenseAutomationView/epics/actualMatching/fetchActualMatchingPageEpic.js +11 -0
- package/lib/view/expenseAutomationView/epics/actualMatching/matchAndReverseAccrualsEpic.d.ts +8 -0
- package/lib/view/expenseAutomationView/epics/actualMatching/matchAndReverseAccrualsEpic.js +56 -0
- package/lib/view/expenseAutomationView/epics/actualMatching/searchMatchAccrualsEpic.d.ts +8 -0
- package/lib/view/expenseAutomationView/epics/actualMatching/searchMatchAccrualsEpic.js +48 -0
- package/lib/view/expenseAutomationView/epics/actualMatching/searchMatchTransactionsEpic.d.ts +8 -0
- package/lib/view/expenseAutomationView/epics/actualMatching/searchMatchTransactionsEpic.js +77 -0
- package/lib/view/expenseAutomationView/epics/actualMatching/undoReversalAccrualsEpic.d.ts +8 -0
- package/lib/view/expenseAutomationView/epics/actualMatching/undoReversalAccrualsEpic.js +56 -0
- package/lib/view/expenseAutomationView/epics/common/fetchAllExpenseAutomationTabsEpic.d.ts +2 -1
- package/lib/view/expenseAutomationView/epics/common/fetchAllExpenseAutomationTabsEpic.js +28 -11
- package/lib/view/expenseAutomationView/epics/common/refreshExpenseAutomationCurrentTabEpic.d.ts +2 -1
- package/lib/view/expenseAutomationView/epics/common/refreshExpenseAutomationCurrentTabEpic.js +9 -1
- package/lib/view/expenseAutomationView/epics/jeSchedule/prefetchOtherJeSchedulesTabEpic.js +3 -1
- package/lib/view/expenseAutomationView/epics/jeSchedule/switchJESchedulesTabEpic.d.ts +2 -1
- package/lib/view/expenseAutomationView/epics/jeSchedule/switchJESchedulesTabEpic.js +5 -0
- package/lib/view/expenseAutomationView/expenseAutomationViewSelector.js +22 -7
- package/lib/view/expenseAutomationView/payload/actualMatchingPayload.d.ts +85 -0
- package/lib/view/expenseAutomationView/payload/actualMatchingPayload.js +74 -0
- package/lib/view/expenseAutomationView/reducers/actualMatchingViewReducer.d.ts +74 -0
- package/lib/view/expenseAutomationView/reducers/actualMatchingViewReducer.js +368 -0
- package/lib/view/expenseAutomationView/reducers/jeSchedulesViewReducer.d.ts +4 -4
- package/lib/view/expenseAutomationView/selectorTypes/actualMatchingViewSelectorTypes.d.ts +83 -0
- package/lib/view/expenseAutomationView/selectorTypes/actualMatchingViewSelectorTypes.js +2 -0
- package/lib/view/expenseAutomationView/selectorTypes/expenseAutomationViewSelectorTypes.d.ts +2 -0
- package/lib/view/expenseAutomationView/selectors/actualMatchingViewSelector.d.ts +29 -0
- package/lib/view/expenseAutomationView/selectors/actualMatchingViewSelector.js +296 -0
- package/lib/view/expenseAutomationView/selectors/jeSchedulesViewSelector.js +3 -0
- package/lib/view/expenseAutomationView/types/actualMatchingViewState.d.ts +99 -0
- package/lib/view/expenseAutomationView/types/actualMatchingViewState.js +38 -0
- package/lib/view/expenseAutomationView/types/jeSchedulesViewState.d.ts +1 -1
- package/lib/view/expenseAutomationView/types/jeSchedulesViewState.js +5 -1
- package/lib/view/notificationPreferencesView/epics/saveNotificationPreferencesEpic.js +6 -19
- package/lib/view/notificationPreferencesView/notificationPreferencesViewReducer.d.ts +5 -8
- package/lib/view/notificationPreferencesView/notificationPreferencesViewReducer.js +17 -43
- package/lib/view/notificationPreferencesView/notificationPreferencesViewSelector.d.ts +0 -4
- package/lib/view/notificationPreferencesView/notificationPreferencesViewSelector.js +5 -30
- package/lib/view/notificationPreferencesView/notificationPreferencesViewState.d.ts +3 -4
- package/lib/view/settingsView/epic/fetchNotificationSettingsEpic.js +2 -12
- package/lib/view/settingsView/settingsViewPayload.d.ts +0 -2
- package/package.json +1 -1
|
@@ -0,0 +1,296 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.parseActualMatchingMatchId = parseActualMatchingMatchId;
|
|
7
|
+
exports.isAutoReversedAccrual = isAutoReversedAccrual;
|
|
8
|
+
exports.isManuallyReversedAccrual = isManuallyReversedAccrual;
|
|
9
|
+
exports.isPendingReviewAccrual = isPendingReviewAccrual;
|
|
10
|
+
exports.isReversedMatchKind = isReversedMatchKind;
|
|
11
|
+
exports.getClearedMatchedAmount = getClearedMatchedAmount;
|
|
12
|
+
exports.getActualMatchingAmount = getActualMatchingAmount;
|
|
13
|
+
exports.getActualMatchingReversalDate = getActualMatchingReversalDate;
|
|
14
|
+
exports.getExpenseAutomationActualMatchingMatchView = getExpenseAutomationActualMatchingMatchView;
|
|
15
|
+
exports.getExpenseAutomationActualMatchingView = getExpenseAutomationActualMatchingView;
|
|
16
|
+
const orderBy_1 = __importDefault(require("lodash/orderBy"));
|
|
17
|
+
const timePeriod_1 = require("../../../commonStateTypes/timePeriod");
|
|
18
|
+
const actualMatchingSelector_1 = require("../../../entity/actualMatching/actualMatchingSelector");
|
|
19
|
+
const jeScheduleHelper_1 = require("../../../entity/jeSchedules/jeScheduleHelper");
|
|
20
|
+
const jeSchedulesSelector_1 = require("../../../entity/jeSchedules/jeSchedulesSelector");
|
|
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
|
+
};
|
|
66
|
+
function isAutoReversedAccrual(accrual) {
|
|
67
|
+
return (accrual.accrualStatus === 'reversed' &&
|
|
68
|
+
accrual.reversalTrigger === 'bill_match');
|
|
69
|
+
}
|
|
70
|
+
function isManuallyReversedAccrual(accrual) {
|
|
71
|
+
return (accrual.accrualStatus === 'reversed' &&
|
|
72
|
+
accrual.reversalTrigger === 'manual_reverse');
|
|
73
|
+
}
|
|
74
|
+
function isPendingReviewAccrual(accrual) {
|
|
75
|
+
if (accrual.accrualStatus !== 'posted' || accrual.matchSuggestion == null) {
|
|
76
|
+
return false;
|
|
77
|
+
}
|
|
78
|
+
const resolution = accrual.matchSuggestion.resolution;
|
|
79
|
+
return resolution == null || resolution.length === 0;
|
|
80
|
+
}
|
|
81
|
+
function isReversedMatchKind(kind) {
|
|
82
|
+
return kind === 'auto_reversed' || kind === 'manually_reversed';
|
|
83
|
+
}
|
|
84
|
+
function getClearedMatchedAmount(accrual) {
|
|
85
|
+
return accrual.cleared?.matchedAmount?.amount;
|
|
86
|
+
}
|
|
87
|
+
function getActualMatchingAmount(row) {
|
|
88
|
+
return row.actualAmount?.amount ?? row.estimatedAmount.amount;
|
|
89
|
+
}
|
|
90
|
+
function getActualMatchingReversalDate(accrual) {
|
|
91
|
+
if (isPendingReviewAccrual(accrual)) {
|
|
92
|
+
return accrual.matchSuggestion.matchedTransactionDate;
|
|
93
|
+
}
|
|
94
|
+
return accrual.cleared?.matchedTransactionDate;
|
|
95
|
+
}
|
|
96
|
+
function collectGroupedMembers(members) {
|
|
97
|
+
if (members.length <= 1) {
|
|
98
|
+
return undefined;
|
|
99
|
+
}
|
|
100
|
+
return members.map((member) => ({
|
|
101
|
+
accrualId: member.accrualId,
|
|
102
|
+
estimatedAmount: member.estimatedAmount,
|
|
103
|
+
jeDebitAccountName: member.jeDebitAccountName,
|
|
104
|
+
memo: member.memo,
|
|
105
|
+
serviceMonth: member.serviceMonth,
|
|
106
|
+
}));
|
|
107
|
+
}
|
|
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);
|
|
114
|
+
return {
|
|
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,
|
|
129
|
+
};
|
|
130
|
+
}
|
|
131
|
+
function matchesSearch(row, searchString) {
|
|
132
|
+
const trimmed = searchString.trim().toLowerCase();
|
|
133
|
+
if (trimmed.length === 0) {
|
|
134
|
+
return true;
|
|
135
|
+
}
|
|
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));
|
|
143
|
+
}
|
|
144
|
+
function getActualMatchingSortValue(row, sortKey) {
|
|
145
|
+
switch (sortKey) {
|
|
146
|
+
case 'vendor':
|
|
147
|
+
return row.vendorName.toLowerCase();
|
|
148
|
+
case 'date':
|
|
149
|
+
return row.reversalDate?.valueOf() ?? row.transactionDate;
|
|
150
|
+
case 'amount':
|
|
151
|
+
return getActualMatchingAmount(row);
|
|
152
|
+
case 'category':
|
|
153
|
+
return row.jeDebitAccountName?.toLowerCase();
|
|
154
|
+
case 'class':
|
|
155
|
+
return row.jeDebitAccountingClassName?.toLowerCase();
|
|
156
|
+
case 'type':
|
|
157
|
+
return row.transactionType?.toLowerCase();
|
|
158
|
+
case 'lifecycle':
|
|
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
|
+
}
|
|
174
|
+
default:
|
|
175
|
+
return undefined;
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
function sortActualMatchingRows(rows, uiState) {
|
|
179
|
+
const lodashOrder = uiState.sortOrder === 'ascending' ? 'asc' : 'desc';
|
|
180
|
+
return (0, orderBy_1.default)(rows, [(row) => getActualMatchingSortValue(row, uiState.sortKey)], [lodashOrder]);
|
|
181
|
+
}
|
|
182
|
+
function emptyKpiSummary() {
|
|
183
|
+
return {
|
|
184
|
+
autoReversed: { count: 0, amount: 0 },
|
|
185
|
+
pendingReview: { count: 0, amount: 0 },
|
|
186
|
+
totalThisClose: { count: 0, amount: 0 },
|
|
187
|
+
ai: { count: 0 },
|
|
188
|
+
manual: { count: 0 },
|
|
189
|
+
};
|
|
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)(state.actualMatchingState, matchId),
|
|
198
|
+
detailFetchState: view.detailFetchStateByMatchId[matchId] ?? NOT_STARTED,
|
|
199
|
+
refreshStatus: view.detailRefreshStatusByMatchId[matchId] ?? NOT_STARTED,
|
|
200
|
+
undoReversalStatus: view.undoReversalStatus ?? NOT_STARTED,
|
|
201
|
+
};
|
|
202
|
+
}
|
|
203
|
+
function getExpenseAutomationActualMatchingView(state) {
|
|
204
|
+
const { expenseAutomationActualMatchingViewState, expenseAutomationViewState } = state;
|
|
205
|
+
const { matchIdsByPeriod, fetchState, error, refreshStatus, uiState, matchModal, undoReversalStatus, } = expenseAutomationActualMatchingViewState;
|
|
206
|
+
const currentTenant = (0, tenantSelector_1.getCurrentTenant)(state);
|
|
207
|
+
const selectedPeriod = expenseAutomationViewState.selectedPeriodByTenantId[currentTenant?.tenantId ?? ''];
|
|
208
|
+
const monthYearPeriodId = selectedPeriod != null ? (0, timePeriod_1.toMonthYearPeriodId)(selectedPeriod) : undefined;
|
|
209
|
+
const matchIds = monthYearPeriodId != null ? matchIdsByPeriod[monthYearPeriodId] : undefined;
|
|
210
|
+
const rows = (matchIds ?? [])
|
|
211
|
+
.map((matchId) => (0, actualMatchingSelector_1.getActualMatchingMatchById)(state.actualMatchingState, matchId))
|
|
212
|
+
.filter((match) => match != null)
|
|
213
|
+
.filter((match) => match.members.length > 0)
|
|
214
|
+
.map(toActualMatchingRow)
|
|
215
|
+
.filter((row) => matchesSearch(row, uiState.searchString));
|
|
216
|
+
const reversed = sortActualMatchingRows(rows.filter((row) => isReversedMatchKind(row.kind)), uiState);
|
|
217
|
+
const pendingReview = sortActualMatchingRows(rows.filter((row) => row.kind === 'pending_review'), uiState);
|
|
218
|
+
const autoReversedForKpi = reversed.filter((row) => row.kind === 'auto_reversed');
|
|
219
|
+
const listedRows = [...reversed, ...pendingReview];
|
|
220
|
+
const kpiSummary = listedRows.length === 0
|
|
221
|
+
? emptyKpiSummary()
|
|
222
|
+
: {
|
|
223
|
+
autoReversed: {
|
|
224
|
+
count: autoReversedForKpi.length,
|
|
225
|
+
amount: sumRowAmounts(autoReversedForKpi),
|
|
226
|
+
},
|
|
227
|
+
pendingReview: {
|
|
228
|
+
count: pendingReview.length,
|
|
229
|
+
amount: sumRowAmounts(pendingReview),
|
|
230
|
+
},
|
|
231
|
+
totalThisClose: {
|
|
232
|
+
count: listedRows.length,
|
|
233
|
+
amount: sumRowAmounts(listedRows),
|
|
234
|
+
},
|
|
235
|
+
ai: {
|
|
236
|
+
count: listedRows.filter((row) => row.origin === 'agent').length,
|
|
237
|
+
},
|
|
238
|
+
manual: {
|
|
239
|
+
count: listedRows.filter((row) => row.origin === 'human').length,
|
|
240
|
+
},
|
|
241
|
+
};
|
|
242
|
+
const searchedAccruals = matchModal.accrualSearch.results
|
|
243
|
+
.map((key) => (0, jeSchedulesSelector_1.getJEOneTimeAccrualByKey)(key, state.jeSchedulesState))
|
|
244
|
+
.filter((accrual) => accrual != null);
|
|
245
|
+
const openedMatch = matchModal.openedFromMatchId != null
|
|
246
|
+
? (0, actualMatchingSelector_1.getActualMatchingMatchById)(state.actualMatchingState, matchModal.openedFromMatchId)
|
|
247
|
+
: undefined;
|
|
248
|
+
const pinnedAccruals = (openedMatch?.members ?? []).map(toMatchModalAccrual);
|
|
249
|
+
const firstSuggestion = openedMatch?.members[0]?.matchSuggestion;
|
|
250
|
+
const prefill = openedMatch == null
|
|
251
|
+
? undefined
|
|
252
|
+
: {
|
|
253
|
+
selectedAccrualIds: openedMatch.members.map((member) => member.accrualId),
|
|
254
|
+
actualAmount: openedMatch.actualAmount.amount,
|
|
255
|
+
matchedLineId: firstSuggestion?.matchedLineId,
|
|
256
|
+
matchedTransactionId: firstSuggestion?.matchedTransactionId,
|
|
257
|
+
};
|
|
258
|
+
return {
|
|
259
|
+
fetchState,
|
|
260
|
+
error,
|
|
261
|
+
reversed,
|
|
262
|
+
pendingReview,
|
|
263
|
+
kpiSummary,
|
|
264
|
+
uiState,
|
|
265
|
+
refreshStatus,
|
|
266
|
+
hasLoadedForSelectedPeriod: matchIds != null,
|
|
267
|
+
undoReversalStatus,
|
|
268
|
+
matchModal: {
|
|
269
|
+
isOpen: matchModal.isOpen,
|
|
270
|
+
openedFromMatchId: matchModal.openedFromMatchId,
|
|
271
|
+
prefill,
|
|
272
|
+
confirmStatus: matchModal.confirmStatus,
|
|
273
|
+
lastBatchResults: matchModal.lastBatchResults,
|
|
274
|
+
transactionSearch: {
|
|
275
|
+
query: matchModal.transactionSearch.query,
|
|
276
|
+
results: uniqueTransactionSearchResults(matchModal.pinnedTransactionResults, matchModal.transactionSearch.results),
|
|
277
|
+
fetchState: {
|
|
278
|
+
fetchState: matchModal.transactionSearch.fetchState,
|
|
279
|
+
error: matchModal.transactionSearch.error,
|
|
280
|
+
},
|
|
281
|
+
nextPageToken: matchModal.transactionSearch.nextPageToken,
|
|
282
|
+
isLoadingMore: matchModal.transactionSearch.isLoadingMore,
|
|
283
|
+
},
|
|
284
|
+
accrualSearch: {
|
|
285
|
+
query: matchModal.accrualSearch.query,
|
|
286
|
+
results: uniqueMatchModalAccruals(pinnedAccruals, searchedAccruals),
|
|
287
|
+
fetchState: {
|
|
288
|
+
fetchState: matchModal.accrualSearch.fetchState,
|
|
289
|
+
error: matchModal.accrualSearch.error,
|
|
290
|
+
},
|
|
291
|
+
nextPageToken: matchModal.accrualSearch.nextPageToken,
|
|
292
|
+
isLoadingMore: matchModal.accrualSearch.isLoadingMore,
|
|
293
|
+
},
|
|
294
|
+
},
|
|
295
|
+
};
|
|
296
|
+
}
|
|
@@ -381,6 +381,9 @@ function getExpenseAutomationJESchedulesView(state) {
|
|
|
381
381
|
// reports undefined rather than 0, so the UI can hide the badge instead of asserting "none".
|
|
382
382
|
const scheduleCountsByTab = {};
|
|
383
383
|
jeSchedulesViewState_1.ALL_JE_PAGE_TABS.forEach((pageTab) => {
|
|
384
|
+
if (pageTab === 'actual_matching') {
|
|
385
|
+
return;
|
|
386
|
+
}
|
|
384
387
|
const periodTabKey = monthYearPeriodId != null
|
|
385
388
|
? (0, jeSchedulesViewState_1.getJESchedulePeriodTabKey)(pageTab, monthYearPeriodId)
|
|
386
389
|
: null;
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
import { FetchStateAndError, FetchedState, ID } from '../../../commonStateTypes/common';
|
|
2
|
+
import { SortOrder } from '../../../commonStateTypes/selectorTypes/sortOrderTypes';
|
|
3
|
+
import { MonthYearPeriodId } from '../../../commonStateTypes/timePeriod';
|
|
4
|
+
import { ActualMatchingMatchId } from '../../../entity/actualMatching/actualMatchingTypes';
|
|
5
|
+
import { JEOneTimeAccrualKey } from '../../../entity/jeSchedules/jeSchedulesTypes';
|
|
6
|
+
export declare const toActualMatchingSortKey: (v: string) => "type" | "date" | "vendor" | "category" | "class" | "amount" | "variance" | "lifecycle" | "service" | "accrued" | "actual";
|
|
7
|
+
export type ActualMatchingSortKey = ReturnType<typeof toActualMatchingSortKey>;
|
|
8
|
+
export declare const MATCH_TRANSACTION_SEARCH_PAGE_SIZE = 50;
|
|
9
|
+
export declare const MATCH_ACCRUAL_SEARCH_LIMIT = 50;
|
|
10
|
+
export declare const MATCH_SEARCH_DEBOUNCE_MS = 300;
|
|
11
|
+
export declare const toMatchAndReverseResultStatus: (v: string) => "error" | "reversed" | "noop" | "conflict" | "claim_lost";
|
|
12
|
+
export type MatchAndReverseResultStatus = ReturnType<typeof toMatchAndReverseResultStatus>;
|
|
13
|
+
export interface ActualMatchingViewUIState {
|
|
14
|
+
scrollPosition: {
|
|
15
|
+
scrollTop: number;
|
|
16
|
+
scrollLeft?: number;
|
|
17
|
+
} | undefined;
|
|
18
|
+
searchString: string;
|
|
19
|
+
sortKey: ActualMatchingSortKey;
|
|
20
|
+
sortOrder: SortOrder;
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Sibling of Missing Receipts `MatchCandidate`. Confirm needs `lineId` and
|
|
24
|
+
* `transactionIntegrationId` on every row — those fields are required here.
|
|
25
|
+
*/
|
|
26
|
+
export interface ActualMatchingTransactionSearchResult {
|
|
27
|
+
amount: number;
|
|
28
|
+
currencyCode: string;
|
|
29
|
+
currencySymbol: string;
|
|
30
|
+
lineId: string;
|
|
31
|
+
syncToken: string;
|
|
32
|
+
transactionDate: string;
|
|
33
|
+
transactionId: ID;
|
|
34
|
+
transactionIntegrationId: string;
|
|
35
|
+
transactionType: string;
|
|
36
|
+
vendorName: string;
|
|
37
|
+
accountDescription?: string;
|
|
38
|
+
accountId?: ID;
|
|
39
|
+
accountingClassId?: ID;
|
|
40
|
+
accountingClassName?: string;
|
|
41
|
+
accountName?: string;
|
|
42
|
+
transactionDescription?: string;
|
|
43
|
+
transactionMemo?: string;
|
|
44
|
+
transactionTypeName?: string;
|
|
45
|
+
vendorId?: ID;
|
|
46
|
+
}
|
|
47
|
+
export interface MatchAndReverseResult {
|
|
48
|
+
accrualId: ID;
|
|
49
|
+
status: MatchAndReverseResultStatus;
|
|
50
|
+
reason?: string;
|
|
51
|
+
}
|
|
52
|
+
export interface MatchAndReverseAccrualsParams {
|
|
53
|
+
accrualIds: ID[];
|
|
54
|
+
lineId: string;
|
|
55
|
+
transactionId: ID;
|
|
56
|
+
transactionIntegrationId: string;
|
|
57
|
+
transactionSyncToken: string;
|
|
58
|
+
transactionType: string;
|
|
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
|
+
}
|
|
70
|
+
export interface ActualMatchingTransactionSearchState extends FetchStateAndError {
|
|
71
|
+
isLoadingMore: boolean;
|
|
72
|
+
nextPageToken: string | null;
|
|
73
|
+
query: string;
|
|
74
|
+
results: ActualMatchingTransactionSearchResult[];
|
|
75
|
+
}
|
|
76
|
+
export interface ActualMatchingAccrualSearchState extends FetchStateAndError {
|
|
77
|
+
isLoadingMore: boolean;
|
|
78
|
+
nextPageToken: string | null;
|
|
79
|
+
query: string;
|
|
80
|
+
results: JEOneTimeAccrualKey[];
|
|
81
|
+
}
|
|
82
|
+
export interface ActualMatchingMatchModalState {
|
|
83
|
+
accrualSearch: ActualMatchingAccrualSearchState;
|
|
84
|
+
confirmStatus: FetchStateAndError;
|
|
85
|
+
isOpen: boolean;
|
|
86
|
+
pinnedTransactionResults: ActualMatchingTransactionSearchResult[];
|
|
87
|
+
transactionSearch: ActualMatchingTransactionSearchState;
|
|
88
|
+
lastBatchResults?: MatchAndReverseResult[];
|
|
89
|
+
openedFromMatchId?: ActualMatchingMatchId;
|
|
90
|
+
}
|
|
91
|
+
export interface ActualMatchingViewState extends FetchedState {
|
|
92
|
+
detailFetchStateByMatchId: Record<ActualMatchingMatchId, FetchStateAndError>;
|
|
93
|
+
detailRefreshStatusByMatchId: Record<ActualMatchingMatchId, FetchStateAndError>;
|
|
94
|
+
matchIdsByPeriod: Record<MonthYearPeriodId, ActualMatchingMatchId[]>;
|
|
95
|
+
matchModal: ActualMatchingMatchModalState;
|
|
96
|
+
refreshStatus: FetchStateAndError;
|
|
97
|
+
uiState: ActualMatchingViewUIState;
|
|
98
|
+
undoReversalStatus: FetchStateAndError;
|
|
99
|
+
}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
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
|
+
const stringToUnion_1 = require("../../../commonStateTypes/stringToUnion");
|
|
5
|
+
const ACTUAL_MATCHING_SORT_KEYS = [
|
|
6
|
+
'vendor',
|
|
7
|
+
'date',
|
|
8
|
+
'amount',
|
|
9
|
+
'category',
|
|
10
|
+
'class',
|
|
11
|
+
'type',
|
|
12
|
+
'lifecycle',
|
|
13
|
+
'service',
|
|
14
|
+
'accrued',
|
|
15
|
+
'actual',
|
|
16
|
+
'variance',
|
|
17
|
+
];
|
|
18
|
+
const toActualMatchingSortKey = (v) => (0, stringToUnion_1.stringToUnion)(v, ACTUAL_MATCHING_SORT_KEYS);
|
|
19
|
+
exports.toActualMatchingSortKey = toActualMatchingSortKey;
|
|
20
|
+
exports.MATCH_TRANSACTION_SEARCH_PAGE_SIZE = 50;
|
|
21
|
+
exports.MATCH_ACCRUAL_SEARCH_LIMIT = 50;
|
|
22
|
+
exports.MATCH_SEARCH_DEBOUNCE_MS = 300;
|
|
23
|
+
const MATCH_AND_REVERSE_RESULT_STATUSES = [
|
|
24
|
+
'reversed',
|
|
25
|
+
'noop',
|
|
26
|
+
'conflict',
|
|
27
|
+
'claim_lost',
|
|
28
|
+
'error',
|
|
29
|
+
];
|
|
30
|
+
const toMatchAndReverseResultStatus = (v) => (0, stringToUnion_1.stringToUnion)(v, MATCH_AND_REVERSE_RESULT_STATUSES);
|
|
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;
|
|
@@ -12,7 +12,7 @@ import { ZeniDate } from '../../../zeniDayJS';
|
|
|
12
12
|
import { JETransactionLink } from '../../scheduleView/scheduleDetailView/scheduleDetailState';
|
|
13
13
|
export declare const toJEScheduleSortKey: (v: string) => "type" | "vendor" | "category" | "class" | "memo" | "jePostingDate" | "runningBalance" | "depCategory" | "scheduleCategory" | "startMonth" | "amortizationPeriod" | "remainingMonths" | "totalAmount" | "transactionDate";
|
|
14
14
|
export type JEScheduleSortKey = ReturnType<typeof toJEScheduleSortKey>;
|
|
15
|
-
export declare const toJEPageTab: (v: string) => "schedules" | "existing_schedules";
|
|
15
|
+
export declare const toJEPageTab: (v: string) => "schedules" | "actual_matching" | "existing_schedules";
|
|
16
16
|
export type JEPageTab = ReturnType<typeof toJEPageTab>;
|
|
17
17
|
export declare const ALL_JE_PAGE_TABS: readonly JEPageTab[];
|
|
18
18
|
export type JESchedulePeriodTabKey = `${JEPageTab}_${MonthYearPeriodId}`;
|
|
@@ -20,7 +20,11 @@ const JE_SCHEDULE_SORT_KEYS = [
|
|
|
20
20
|
];
|
|
21
21
|
const toJEScheduleSortKey = (v) => (0, stringToUnion_1.stringToUnion)(v, JE_SCHEDULE_SORT_KEYS);
|
|
22
22
|
exports.toJEScheduleSortKey = toJEScheduleSortKey;
|
|
23
|
-
const JE_PAGE_TABS = [
|
|
23
|
+
const JE_PAGE_TABS = [
|
|
24
|
+
'schedules',
|
|
25
|
+
'actual_matching',
|
|
26
|
+
'existing_schedules',
|
|
27
|
+
];
|
|
24
28
|
const toJEPageTab = (v) => (0, stringToUnion_1.stringToUnion)(v, JE_PAGE_TABS);
|
|
25
29
|
exports.toJEPageTab = toJEPageTab;
|
|
26
30
|
exports.ALL_JE_PAGE_TABS = JE_PAGE_TABS;
|
|
@@ -3,7 +3,6 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.saveNotificationPreferencesEpic = void 0;
|
|
4
4
|
const rxjs_1 = require("rxjs");
|
|
5
5
|
const operators_1 = require("rxjs/operators");
|
|
6
|
-
const notificationRegistryState_1 = require("../../../entity/notificationRegistry/notificationRegistryState");
|
|
7
6
|
const snackbarReducer_1 = require("../../../entity/snackbar/snackbarReducer");
|
|
8
7
|
const responsePayload_1 = require("../../../responsePayload");
|
|
9
8
|
const notificationPreferencesEndpoint_1 = require("../notificationPreferencesEndpoint");
|
|
@@ -17,19 +16,9 @@ const saveNotificationPreferencesEpic = (actions$, state$, zeniAPI) => actions$.
|
|
|
17
16
|
// ignored, so stale success/failure actions cannot clobber the newer
|
|
18
17
|
// batch's state. Server-side ordering is arrival-order LWW.
|
|
19
18
|
(0, operators_1.switchMap)(([, state]) => {
|
|
20
|
-
|
|
21
|
-
const
|
|
22
|
-
|
|
23
|
-
notificationRegistryState_1.NOTIFICATION_DOMAINS.forEach((domain) => {
|
|
24
|
-
const overrides = (0, notificationPreferencesViewSelector_1.getNotificationLocalOverridesForDomain)(state, domain);
|
|
25
|
-
const preferencesPatch = (0, notificationPreferencesViewPayload_1.mapPreferencesToPayload)(overrides);
|
|
26
|
-
if (Object.keys(preferencesPatch).length === 0) {
|
|
27
|
-
return;
|
|
28
|
-
}
|
|
29
|
-
overridesByDomain[domain] = overrides;
|
|
30
|
-
body[`${domain}_preferences`] = preferencesPatch;
|
|
31
|
-
});
|
|
32
|
-
if (Object.keys(body).length === 0) {
|
|
19
|
+
const overrides = (0, notificationPreferencesViewSelector_1.getNotificationLocalOverrides)(state);
|
|
20
|
+
const preferencesPatch = (0, notificationPreferencesViewPayload_1.mapPreferencesToPayload)(overrides);
|
|
21
|
+
if (Object.keys(preferencesPatch).length === 0) {
|
|
33
22
|
// No diff → do not dispatch a synthetic success (that would wipe
|
|
34
23
|
// stored preferences via the reducer). Simply no-op.
|
|
35
24
|
return rxjs_1.EMPTY;
|
|
@@ -42,6 +31,7 @@ const saveNotificationPreferencesEpic = (actions$, state$, zeniAPI) => actions$.
|
|
|
42
31
|
// in-flight save's response (Success/Failure never dispatched, so
|
|
43
32
|
// the counter never drained and future saves got their merge dropped).
|
|
44
33
|
const cancelEpochAtDispatch = state.notificationPreferencesViewState.cancelEpoch;
|
|
34
|
+
const body = { task_checklist_preferences: preferencesPatch };
|
|
45
35
|
// Suppress the error snackbar when the response lands AFTER the user
|
|
46
36
|
// pressed Cancel — the Failure reducer already swallows the state
|
|
47
37
|
// update, so the toast would be a stale error for a save the user
|
|
@@ -70,11 +60,8 @@ const saveNotificationPreferencesEpic = (actions$, state$, zeniAPI) => actions$.
|
|
|
70
60
|
if ((0, responsePayload_1.isSuccessResponse)(response)) {
|
|
71
61
|
return (0, rxjs_1.of)((0, notificationPreferencesViewReducer_1.saveNotificationPreferencesSuccess)({
|
|
72
62
|
cancelEpochAtDispatch,
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
task_checklist: response.data?.task_checklist_preferences,
|
|
76
|
-
commenting: response.data?.commenting_preferences,
|
|
77
|
-
},
|
|
63
|
+
savedOverrides: overrides,
|
|
64
|
+
serverEcho: response.data?.task_checklist_preferences,
|
|
78
65
|
}));
|
|
79
66
|
}
|
|
80
67
|
const actions = [
|
|
@@ -1,33 +1,30 @@
|
|
|
1
|
-
import { NotificationChannel,
|
|
1
|
+
import { NotificationChannel, NotificationFrequency } from '../../entity/notificationRegistry/notificationRegistryState';
|
|
2
2
|
import { ZeniAPIStatus } from '../../responsePayload';
|
|
3
3
|
import { NotificationPreferencesPayload } from './notificationPreferencesViewPayload';
|
|
4
|
-
import {
|
|
4
|
+
import { NotificationPreferences, NotificationPreferencesViewState } from './notificationPreferencesViewState';
|
|
5
5
|
export declare const initialState: NotificationPreferencesViewState;
|
|
6
6
|
export interface SetFrequencyPayload {
|
|
7
7
|
frequency: NotificationFrequency;
|
|
8
8
|
groupId: string;
|
|
9
|
-
domain?: NotificationDomain;
|
|
10
9
|
}
|
|
11
10
|
export interface TogglePreferencePayload {
|
|
12
11
|
channel: NotificationChannel;
|
|
13
12
|
enabled: boolean;
|
|
14
13
|
eventId: string;
|
|
15
|
-
domain?: NotificationDomain;
|
|
16
14
|
}
|
|
17
15
|
export interface SetGroupChannelMasterPayload {
|
|
18
16
|
channel: NotificationChannel;
|
|
19
17
|
enabled: boolean;
|
|
20
18
|
groupId: string;
|
|
21
|
-
domain?: NotificationDomain;
|
|
22
19
|
}
|
|
23
20
|
export interface FetchNotificationPreferencesSuccessPayload {
|
|
24
|
-
|
|
21
|
+
preferences: NotificationPreferencesPayload | undefined;
|
|
25
22
|
saveEpochAtDispatch: number;
|
|
26
23
|
}
|
|
27
24
|
export interface SaveNotificationPreferencesSuccessPayload {
|
|
28
25
|
cancelEpochAtDispatch: number;
|
|
29
|
-
|
|
30
|
-
|
|
26
|
+
savedOverrides: NotificationPreferences;
|
|
27
|
+
serverEcho: NotificationPreferencesPayload | undefined;
|
|
31
28
|
}
|
|
32
29
|
export interface SaveNotificationPreferencesFailurePayload {
|
|
33
30
|
cancelEpochAtDispatch: number;
|