@zeniai/client-epic-state 5.2.34 → 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.
Files changed (94) hide show
  1. package/lib/entity/actualMatching/actualMatchingPayload.d.ts +25 -0
  2. package/lib/entity/actualMatching/actualMatchingPayload.js +43 -0
  3. package/lib/entity/actualMatching/actualMatchingReducer.d.ts +8 -0
  4. package/lib/entity/actualMatching/actualMatchingReducer.js +33 -0
  5. package/lib/entity/actualMatching/actualMatchingSelector.d.ts +3 -0
  6. package/lib/entity/actualMatching/actualMatchingSelector.js +6 -0
  7. package/lib/entity/actualMatching/actualMatchingState.d.ts +22 -0
  8. package/lib/entity/actualMatching/actualMatchingState.js +2 -0
  9. package/lib/entity/actualMatching/actualMatchingTypes.d.ts +1 -0
  10. package/lib/entity/actualMatching/actualMatchingTypes.js +2 -0
  11. package/lib/entity/jeSchedules/jeSchedulesPayload.d.ts +29 -0
  12. package/lib/entity/jeSchedules/jeSchedulesPayload.js +49 -0
  13. package/lib/entity/jeSchedules/jeSchedulesState.d.ts +31 -0
  14. package/lib/epic.d.ts +8 -1
  15. package/lib/epic.js +14 -0
  16. package/lib/esm/entity/actualMatching/actualMatchingPayload.js +40 -0
  17. package/lib/esm/entity/actualMatching/actualMatchingReducer.js +30 -0
  18. package/lib/esm/entity/actualMatching/actualMatchingSelector.js +3 -0
  19. package/lib/esm/entity/actualMatching/actualMatchingState.js +1 -0
  20. package/lib/esm/entity/actualMatching/actualMatchingTypes.js +1 -0
  21. package/lib/esm/entity/jeSchedules/jeSchedulesPayload.js +49 -0
  22. package/lib/esm/epic.js +14 -0
  23. package/lib/esm/index.js +6 -2
  24. package/lib/esm/reducer.js +6 -0
  25. package/lib/esm/view/expenseAutomationView/epics/actualMatching/fetchActualMatchingEpic.js +46 -0
  26. package/lib/esm/view/expenseAutomationView/epics/actualMatching/fetchActualMatchingMatchEpic.js +35 -0
  27. package/lib/esm/view/expenseAutomationView/epics/actualMatching/fetchActualMatchingPageEpic.js +7 -0
  28. package/lib/esm/view/expenseAutomationView/epics/actualMatching/matchAndReverseAccrualsEpic.js +52 -0
  29. package/lib/esm/view/expenseAutomationView/epics/actualMatching/searchMatchAccrualsEpic.js +44 -0
  30. package/lib/esm/view/expenseAutomationView/epics/actualMatching/searchMatchTransactionsEpic.js +73 -0
  31. package/lib/esm/view/expenseAutomationView/epics/actualMatching/undoReversalAccrualsEpic.js +52 -0
  32. package/lib/esm/view/expenseAutomationView/epics/common/fetchAllExpenseAutomationTabsEpic.js +28 -11
  33. package/lib/esm/view/expenseAutomationView/epics/common/refreshExpenseAutomationCurrentTabEpic.js +9 -1
  34. package/lib/esm/view/expenseAutomationView/epics/jeSchedule/prefetchOtherJeSchedulesTabEpic.js +3 -1
  35. package/lib/esm/view/expenseAutomationView/epics/jeSchedule/switchJESchedulesTabEpic.js +5 -0
  36. package/lib/esm/view/expenseAutomationView/expenseAutomationViewSelector.js +22 -7
  37. package/lib/esm/view/expenseAutomationView/payload/actualMatchingPayload.js +68 -0
  38. package/lib/esm/view/expenseAutomationView/reducers/actualMatchingViewReducer.js +364 -0
  39. package/lib/esm/view/expenseAutomationView/selectorTypes/actualMatchingViewSelectorTypes.js +1 -0
  40. package/lib/esm/view/expenseAutomationView/selectors/actualMatchingViewSelector.js +281 -0
  41. package/lib/esm/view/expenseAutomationView/selectors/jeSchedulesViewSelector.js +3 -0
  42. package/lib/esm/view/expenseAutomationView/types/actualMatchingViewState.js +32 -0
  43. package/lib/esm/view/expenseAutomationView/types/jeSchedulesViewState.js +5 -1
  44. package/lib/esm/view/invoicing/editInvoicingCustomerDetailView/editInvoicingCustomerDetailViewPayload.js +4 -0
  45. package/lib/index.d.ts +13 -5
  46. package/lib/index.js +78 -48
  47. package/lib/reducer.d.ts +2 -0
  48. package/lib/reducer.js +6 -0
  49. package/lib/rootStateTypes.d.ts +4 -0
  50. package/lib/view/expenseAutomationView/epics/actualMatching/fetchActualMatchingEpic.d.ts +9 -0
  51. package/lib/view/expenseAutomationView/epics/actualMatching/fetchActualMatchingEpic.js +50 -0
  52. package/lib/view/expenseAutomationView/epics/actualMatching/fetchActualMatchingMatchEpic.d.ts +12 -0
  53. package/lib/view/expenseAutomationView/epics/actualMatching/fetchActualMatchingMatchEpic.js +39 -0
  54. package/lib/view/expenseAutomationView/epics/actualMatching/fetchActualMatchingPageEpic.d.ts +5 -0
  55. package/lib/view/expenseAutomationView/epics/actualMatching/fetchActualMatchingPageEpic.js +11 -0
  56. package/lib/view/expenseAutomationView/epics/actualMatching/matchAndReverseAccrualsEpic.d.ts +8 -0
  57. package/lib/view/expenseAutomationView/epics/actualMatching/matchAndReverseAccrualsEpic.js +56 -0
  58. package/lib/view/expenseAutomationView/epics/actualMatching/searchMatchAccrualsEpic.d.ts +8 -0
  59. package/lib/view/expenseAutomationView/epics/actualMatching/searchMatchAccrualsEpic.js +48 -0
  60. package/lib/view/expenseAutomationView/epics/actualMatching/searchMatchTransactionsEpic.d.ts +8 -0
  61. package/lib/view/expenseAutomationView/epics/actualMatching/searchMatchTransactionsEpic.js +77 -0
  62. package/lib/view/expenseAutomationView/epics/actualMatching/undoReversalAccrualsEpic.d.ts +8 -0
  63. package/lib/view/expenseAutomationView/epics/actualMatching/undoReversalAccrualsEpic.js +56 -0
  64. package/lib/view/expenseAutomationView/epics/common/fetchAllExpenseAutomationTabsEpic.d.ts +2 -1
  65. package/lib/view/expenseAutomationView/epics/common/fetchAllExpenseAutomationTabsEpic.js +28 -11
  66. package/lib/view/expenseAutomationView/epics/common/refreshExpenseAutomationCurrentTabEpic.d.ts +2 -1
  67. package/lib/view/expenseAutomationView/epics/common/refreshExpenseAutomationCurrentTabEpic.js +9 -1
  68. package/lib/view/expenseAutomationView/epics/jeSchedule/prefetchOtherJeSchedulesTabEpic.js +3 -1
  69. package/lib/view/expenseAutomationView/epics/jeSchedule/switchJESchedulesTabEpic.d.ts +2 -1
  70. package/lib/view/expenseAutomationView/epics/jeSchedule/switchJESchedulesTabEpic.js +5 -0
  71. package/lib/view/expenseAutomationView/expenseAutomationViewSelector.js +22 -7
  72. package/lib/view/expenseAutomationView/payload/actualMatchingPayload.d.ts +85 -0
  73. package/lib/view/expenseAutomationView/payload/actualMatchingPayload.js +74 -0
  74. package/lib/view/expenseAutomationView/reducers/actualMatchingViewReducer.d.ts +74 -0
  75. package/lib/view/expenseAutomationView/reducers/actualMatchingViewReducer.js +368 -0
  76. package/lib/view/expenseAutomationView/reducers/jeSchedulesViewReducer.d.ts +4 -4
  77. package/lib/view/expenseAutomationView/selectorTypes/actualMatchingViewSelectorTypes.d.ts +83 -0
  78. package/lib/view/expenseAutomationView/selectorTypes/actualMatchingViewSelectorTypes.js +2 -0
  79. package/lib/view/expenseAutomationView/selectorTypes/expenseAutomationViewSelectorTypes.d.ts +2 -0
  80. package/lib/view/expenseAutomationView/selectors/actualMatchingViewSelector.d.ts +29 -0
  81. package/lib/view/expenseAutomationView/selectors/actualMatchingViewSelector.js +296 -0
  82. package/lib/view/expenseAutomationView/selectors/jeSchedulesViewSelector.js +3 -0
  83. package/lib/view/expenseAutomationView/types/actualMatchingViewState.d.ts +99 -0
  84. package/lib/view/expenseAutomationView/types/actualMatchingViewState.js +38 -0
  85. package/lib/view/expenseAutomationView/types/jeSchedulesViewState.d.ts +1 -1
  86. package/lib/view/expenseAutomationView/types/jeSchedulesViewState.js +5 -1
  87. package/lib/view/invoicing/editInvoicingCustomerDetailView/editInvoicingCustomerDetailViewPayload.d.ts +1 -11
  88. package/lib/view/invoicing/editInvoicingCustomerDetailView/editInvoicingCustomerDetailViewPayload.js +4 -0
  89. package/lib/view/invoicing/editInvoicingCustomerDetailView/editInvoicingCustomerDetailViewReducer.d.ts +1 -2
  90. package/lib/view/invoicing/editInvoicingCustomerDetailView/editInvoicingCustomerDetailViewSelector.d.ts +1 -2
  91. package/lib/view/invoicing/editInvoicingCustomerDetailView/editInvoicingCustomerDetailViewState.d.ts +15 -1
  92. package/lib/view/invoicing/invoicingCustomerListView/invoicingCustomerListViewReducer.d.ts +1 -1
  93. package/lib/view/invoicing/invoicingCustomerListView/invoicingCustomerListViewState.d.ts +1 -1
  94. 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 = ['schedules', 'existing_schedules'];
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;
@@ -1,7 +1,7 @@
1
1
  import { InvoicingCustomerPayload } from '../../../entity/invoicing/invoicingCustomer/invoicingCustomerPayload';
2
2
  import { ZeniAPIResponse } from '../../../responsePayload';
3
3
  import { AddressUpdatableInfo } from '../../addressView/addressViewState';
4
- import { InvoicingCustomerFormLocalData } from './editInvoicingCustomerDetailViewState';
4
+ import { InvoicingCustomerFormLocalData, InvoicingPaymentLinkEmailPreviewData } from './editInvoicingCustomerDetailViewState';
5
5
  export type SaveInvoicingCustomerResponse = ZeniAPIResponse<InvoicingCustomerPayload>;
6
6
  /**
7
7
  * Build the create/update customer request body from the form draft. The
@@ -25,15 +25,5 @@ export type InvoicingPaymentLinkEmailPreviewResponse = ZeniAPIResponse<Invoicing
25
25
  * The email rendered once with sentinel tokens standing in for the subject and
26
26
  * body, so the composer can splice a draft into it without another request.
27
27
  */
28
- export interface InvoicingPaymentLinkEmailPreviewData {
29
- /** Default body prefill, plain text. */
30
- body: string;
31
- bodyToken: string;
32
- renderedHtmlTemplate: string;
33
- /** Default subject prefill. */
34
- subject: string;
35
- subjectToken: string;
36
- to: string;
37
- }
38
28
  export declare const toInvoicingPaymentLinkEmailPreview: (payload: InvoicingPaymentLinkEmailPreviewPayload) => InvoicingPaymentLinkEmailPreviewData;
39
29
  export type AddPromotionalCreditsResponse = ZeniAPIResponse<InvoicingCustomerPayload>;
@@ -34,6 +34,10 @@ const localDataToSaveInvoicingCustomerPayload = (localData, billingAddress) => {
34
34
  };
35
35
  };
36
36
  exports.localDataToSaveInvoicingCustomerPayload = localDataToSaveInvoicingCustomerPayload;
37
+ /**
38
+ * The email rendered once with sentinel tokens standing in for the subject and
39
+ * body, so the composer can splice a draft into it without another request.
40
+ */
37
41
  const toInvoicingPaymentLinkEmailPreview = (payload) => ({
38
42
  body: payload.body,
39
43
  bodyToken: payload.body_token,
@@ -1,7 +1,6 @@
1
1
  import { ID } from '../../../commonStateTypes/common';
2
2
  import { ZeniAPIStatus } from '../../../responsePayload';
3
- import { InvoicingPaymentLinkEmailPreviewData } from './editInvoicingCustomerDetailViewPayload';
4
- import { EditInvoicingCustomerDetailViewState, InvoicingCustomerFormLocalData } from './editInvoicingCustomerDetailViewState';
3
+ import { EditInvoicingCustomerDetailViewState, InvoicingCustomerFormLocalData, InvoicingPaymentLinkEmailPreviewData } from './editInvoicingCustomerDetailViewState';
5
4
  /** Add promotional credits to a customer. */
6
5
  export interface SubmitAddPromotionalCreditsPayload {
7
6
  amount: number;
@@ -5,8 +5,7 @@ import { InvoicingFieldHelpByCode, InvoicingNamedOption } from '../../../entity/
5
5
  import { InvoicingCustomer, InvoicingCustomerPaymentMethod } from '../../../entity/invoicing/invoicingCustomer/invoicingCustomerState';
6
6
  import { RootState } from '../../../rootStateTypes';
7
7
  import { InvoicingSetupIntent } from '../customerPaymentMethod/customerPaymentMethodState';
8
- import { InvoicingPaymentLinkEmailPreviewData } from './editInvoicingCustomerDetailViewPayload';
9
- import { InvoicingCustomerFormLocalData } from './editInvoicingCustomerDetailViewState';
8
+ import { InvoicingCustomerFormLocalData, InvoicingPaymentLinkEmailPreviewData } from './editInvoicingCustomerDetailViewState';
10
9
  /**
11
10
  * Read-only view for the customer detail page: the customer entity + its fetch
12
11
  * state, plus everything the page renders in view mode — recent invoices, the
@@ -1,5 +1,19 @@
1
1
  import { FetchStateAndError, FetchedState, ID } from '../../../commonStateTypes/common';
2
- import { InvoicingPaymentLinkEmailPreviewData } from './editInvoicingCustomerDetailViewPayload';
2
+ /**
3
+ * The payment-link email the composer opens with: the backend's prefill plus
4
+ * the tokens the frontend splices the user's edits into. State, not wire shape
5
+ * — `toInvoicingPaymentLinkEmailPreview` in the payload file maps onto it.
6
+ */
7
+ export interface InvoicingPaymentLinkEmailPreviewData {
8
+ /** Default body prefill, plain text. */
9
+ body: string;
10
+ bodyToken: string;
11
+ renderedHtmlTemplate: string;
12
+ /** Default subject prefill. */
13
+ subject: string;
14
+ subjectToken: string;
15
+ to: string;
16
+ }
3
17
  /**
4
18
  * Draft form state for the create/edit customer form. Held in CES so the form
5
19
  * flows its data from here (mirrors the bill-pay / reimbursement pattern). The
@@ -26,7 +26,7 @@ export declare const fetchInvoicingCustomerList: import("@reduxjs/toolkit").Acti
26
26
  ids: ID[];
27
27
  keepExistingListItems: boolean;
28
28
  nextCursor: string | null;
29
- }, "invoicingCustomerListView/updateInvoicingCustomerList">, updateInvoicingCustomerListFailure: import("@reduxjs/toolkit").ActionCreatorWithPayload<ZeniAPIStatus<Record<string, unknown>>, "invoicingCustomerListView/updateInvoicingCustomerListFailure">, fetchInvoicingCustomerCounts: import("@reduxjs/toolkit").ActionCreatorWithoutPayload<"invoicingCustomerListView/fetchInvoicingCustomerCounts">, updateInvoicingCustomerCounts: import("@reduxjs/toolkit").ActionCreatorWithPayload<InvoicingListCounts, "invoicingCustomerListView/updateInvoicingCustomerCounts">, updateInvoicingCustomerCountsFailure: import("@reduxjs/toolkit").ActionCreatorWithPayload<ZeniAPIStatus<Record<string, unknown>>, "invoicingCustomerListView/updateInvoicingCustomerCountsFailure">, updateInvoicingCustomerFilters: import("@reduxjs/toolkit").ActionCreatorWithPayload<InvoicingCustomerFilters, "invoicingCustomerListView/updateInvoicingCustomerFilters">, setInvoicingCustomerActiveTab: import("@reduxjs/toolkit").ActionCreatorWithPayload<"active" | "all" | "at_risk" | "trial", "invoicingCustomerListView/setInvoicingCustomerActiveTab">, addInvoicingCustomerToList: import("@reduxjs/toolkit").ActionCreatorWithPayload<{
29
+ }, "invoicingCustomerListView/updateInvoicingCustomerList">, updateInvoicingCustomerListFailure: import("@reduxjs/toolkit").ActionCreatorWithPayload<ZeniAPIStatus<Record<string, unknown>>, "invoicingCustomerListView/updateInvoicingCustomerListFailure">, fetchInvoicingCustomerCounts: import("@reduxjs/toolkit").ActionCreatorWithoutPayload<"invoicingCustomerListView/fetchInvoicingCustomerCounts">, updateInvoicingCustomerCounts: import("@reduxjs/toolkit").ActionCreatorWithPayload<InvoicingListCounts, "invoicingCustomerListView/updateInvoicingCustomerCounts">, updateInvoicingCustomerCountsFailure: import("@reduxjs/toolkit").ActionCreatorWithPayload<ZeniAPIStatus<Record<string, unknown>>, "invoicingCustomerListView/updateInvoicingCustomerCountsFailure">, updateInvoicingCustomerFilters: import("@reduxjs/toolkit").ActionCreatorWithPayload<InvoicingCustomerFilters, "invoicingCustomerListView/updateInvoicingCustomerFilters">, setInvoicingCustomerActiveTab: import("@reduxjs/toolkit").ActionCreatorWithPayload<"active" | "all" | "trial" | "at_risk", "invoicingCustomerListView/setInvoicingCustomerActiveTab">, addInvoicingCustomerToList: import("@reduxjs/toolkit").ActionCreatorWithPayload<{
30
30
  id: ID;
31
31
  status?: string;
32
32
  }, "invoicingCustomerListView/addInvoicingCustomerToList">;
@@ -20,7 +20,7 @@ export interface InvoicingCustomerColumnConfig {
20
20
  }
21
21
  export declare const INVOICING_CUSTOMER_COLUMNS: InvoicingCustomerColumnConfig[];
22
22
  export declare const ALL_INVOICING_CUSTOMER_TAB_IDS: readonly ["all", "active", "trial", "at_risk"];
23
- export declare const toInvoicingCustomerTabId: (v: string) => "active" | "all" | "at_risk" | "trial";
23
+ export declare const toInvoicingCustomerTabId: (v: string) => "active" | "all" | "trial" | "at_risk";
24
24
  export type InvoicingCustomerTabId = ReturnType<typeof toInvoicingCustomerTabId>;
25
25
  export interface InvoicingCustomerListViewState extends FetchedState {
26
26
  /** Selected status tab (CES-owned so it persists across page revisits). */
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zeniai/client-epic-state",
3
- "version": "5.2.34",
3
+ "version": "5.2.35-beta0MM",
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",