@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.
Files changed (59) hide show
  1. package/lib/entity/actualMatching/actualMatchingPayload.d.ts +25 -0
  2. package/lib/entity/actualMatching/actualMatchingPayload.js +42 -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 +2 -0
  12. package/lib/entity/jeSchedules/jeSchedulesPayload.js +2 -0
  13. package/lib/entity/jeSchedules/jeSchedulesState.d.ts +2 -0
  14. package/lib/epic.d.ts +3 -1
  15. package/lib/epic.js +4 -0
  16. package/lib/esm/entity/actualMatching/actualMatchingPayload.js +39 -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 +2 -0
  22. package/lib/esm/epic.js +4 -0
  23. package/lib/esm/index.js +5 -5
  24. package/lib/esm/reducer.js +3 -0
  25. package/lib/esm/view/expenseAutomationView/epics/actualMatching/fetchActualMatchingEpic.js +6 -6
  26. package/lib/esm/view/expenseAutomationView/epics/actualMatching/fetchActualMatchingMatchEpic.js +35 -0
  27. package/lib/esm/view/expenseAutomationView/epics/actualMatching/matchAndReverseAccrualsEpic.js +2 -1
  28. package/lib/esm/view/expenseAutomationView/epics/actualMatching/searchMatchTransactionsEpic.js +35 -6
  29. package/lib/esm/view/expenseAutomationView/epics/actualMatching/undoReversalAccrualsEpic.js +51 -0
  30. package/lib/esm/view/expenseAutomationView/epics/common/fetchAllExpenseAutomationTabsEpic.js +1 -1
  31. package/lib/esm/view/expenseAutomationView/payload/actualMatchingPayload.js +9 -1
  32. package/lib/esm/view/expenseAutomationView/reducers/actualMatchingViewReducer.js +112 -8
  33. package/lib/esm/view/expenseAutomationView/selectors/actualMatchingViewSelector.js +145 -98
  34. package/lib/esm/view/expenseAutomationView/types/actualMatchingViewState.js +10 -0
  35. package/lib/index.d.ts +8 -5
  36. package/lib/index.js +53 -48
  37. package/lib/reducer.d.ts +1 -0
  38. package/lib/reducer.js +3 -0
  39. package/lib/rootStateTypes.d.ts +2 -0
  40. package/lib/view/expenseAutomationView/epics/actualMatching/fetchActualMatchingEpic.d.ts +2 -2
  41. package/lib/view/expenseAutomationView/epics/actualMatching/fetchActualMatchingEpic.js +6 -6
  42. package/lib/view/expenseAutomationView/epics/actualMatching/fetchActualMatchingMatchEpic.d.ts +12 -0
  43. package/lib/view/expenseAutomationView/epics/actualMatching/fetchActualMatchingMatchEpic.js +39 -0
  44. package/lib/view/expenseAutomationView/epics/actualMatching/matchAndReverseAccrualsEpic.js +2 -1
  45. package/lib/view/expenseAutomationView/epics/actualMatching/searchMatchTransactionsEpic.d.ts +1 -1
  46. package/lib/view/expenseAutomationView/epics/actualMatching/searchMatchTransactionsEpic.js +35 -6
  47. package/lib/view/expenseAutomationView/epics/actualMatching/undoReversalAccrualsEpic.d.ts +8 -0
  48. package/lib/view/expenseAutomationView/epics/actualMatching/undoReversalAccrualsEpic.js +55 -0
  49. package/lib/view/expenseAutomationView/epics/common/fetchAllExpenseAutomationTabsEpic.js +1 -1
  50. package/lib/view/expenseAutomationView/payload/actualMatchingPayload.d.ts +20 -7
  51. package/lib/view/expenseAutomationView/payload/actualMatchingPayload.js +9 -0
  52. package/lib/view/expenseAutomationView/reducers/actualMatchingViewReducer.d.ts +26 -5
  53. package/lib/view/expenseAutomationView/reducers/actualMatchingViewReducer.js +113 -9
  54. package/lib/view/expenseAutomationView/selectorTypes/actualMatchingViewSelectorTypes.d.ts +16 -2
  55. package/lib/view/expenseAutomationView/selectors/actualMatchingViewSelector.d.ts +17 -2
  56. package/lib/view/expenseAutomationView/selectors/actualMatchingViewSelector.js +148 -98
  57. package/lib/view/expenseAutomationView/types/actualMatchingViewState.d.ts +20 -2
  58. package/lib/view/expenseAutomationView/types/actualMatchingViewState.js +12 -1
  59. 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(accrual: JEOneTimeAccrual): number;
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(accrual) {
36
- if (isPendingReviewAccrual(accrual)) {
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(members, kind) {
98
- const accrual = members[0];
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
- ...accrual,
101
- kind,
102
- groupedAccrualIds: collectGroupedAccrualIds(members),
103
- groupedMembers: collectGroupedMembers(members),
104
- reversalDate: getActualMatchingReversalDate(accrual),
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 collapseActualMatchingRows(accruals, kind) {
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
- return (accrual.vendorName.toLowerCase().includes(trimmed) ||
134
- accrual.memo.toLowerCase().includes(trimmed));
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 (row.cleared?.matchedTransactionType ??
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 { accrualKeysByPeriod, fetchState, error, refreshStatus, uiState, matchModal, } = expenseAutomationActualMatchingViewState;
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 accrualKeys = monthYearPeriodId != null
177
- ? accrualKeysByPeriod[monthYearPeriodId]
209
+ const matchIds = monthYearPeriodId != null
210
+ ? matchIdsByPeriod[monthYearPeriodId]
178
211
  : undefined;
179
- const accruals = (accrualKeys ?? [])
180
- .map((key) => (0, jeSchedulesSelector_1.getJEOneTimeAccrualByKey)(key, state.jeSchedulesState))
181
- .filter((accrual) => accrual != null);
182
- const filtered = accruals.filter((accrual) => matchesSearch(accrual, uiState.searchString));
183
- const autoReversed = sortActualMatchingRows(collapseActualMatchingRows(filtered.filter(isAutoReversedAccrual), 'auto_reversed'), uiState);
184
- const pendingReview = sortActualMatchingRows(collapseActualMatchingRows(filtered.filter(isPendingReviewAccrual), 'pending_review'), uiState);
185
- const manuallyReversed = sortActualMatchingRows(collapseActualMatchingRows(filtered.filter(isManuallyReversedAccrual), 'manually_reversed'), uiState);
186
- const listedRows = [...autoReversed, ...pendingReview, ...manuallyReversed];
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: autoReversed.length,
192
- amount: sumCollapsedActualMatchingAmounts(autoReversed),
226
+ count: autoReversedForKpi.length,
227
+ amount: sumRowAmounts(autoReversedForKpi),
193
228
  },
194
229
  pendingReview: {
195
230
  count: pendingReview.length,
196
- amount: sumCollapsedActualMatchingAmounts(pendingReview),
231
+ amount: sumRowAmounts(pendingReview),
197
232
  },
198
233
  totalThisClose: {
199
234
  count: listedRows.length,
200
- amount: sumCollapsedActualMatchingAmounts(listedRows),
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 accrualSearchResults = matchModal.accrualSearch.results
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
- autoReversed,
263
+ reversed,
216
264
  pendingReview,
217
- manuallyReversed,
218
265
  kpiSummary,
219
266
  uiState,
220
267
  refreshStatus,
221
- hasLoadedForSelectedPeriod: accrualKeys != null,
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: accrualSearchResults,
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
- accrualKeysByPeriod: Record<MonthYearPeriodId, JEOneTimeAccrualKey[]>;
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-betaAM4",
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",