@zeniai/client-epic-state 5.2.22-betaAM3 → 5.2.22-betaAM5

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 (48) 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/epic.d.ts +2 -1
  12. package/lib/epic.js +2 -0
  13. package/lib/esm/entity/actualMatching/actualMatchingPayload.js +39 -0
  14. package/lib/esm/entity/actualMatching/actualMatchingReducer.js +30 -0
  15. package/lib/esm/entity/actualMatching/actualMatchingSelector.js +3 -0
  16. package/lib/esm/entity/actualMatching/actualMatchingState.js +1 -0
  17. package/lib/esm/entity/actualMatching/actualMatchingTypes.js +1 -0
  18. package/lib/esm/epic.js +2 -0
  19. package/lib/esm/index.js +3 -3
  20. package/lib/esm/reducer.js +3 -0
  21. package/lib/esm/view/expenseAutomationView/epics/actualMatching/fetchActualMatchingEpic.js +6 -6
  22. package/lib/esm/view/expenseAutomationView/epics/actualMatching/fetchActualMatchingMatchEpic.js +35 -0
  23. package/lib/esm/view/expenseAutomationView/epics/actualMatching/searchMatchTransactionsEpic.js +35 -6
  24. package/lib/esm/view/expenseAutomationView/epics/common/fetchAllExpenseAutomationTabsEpic.js +1 -1
  25. package/lib/esm/view/expenseAutomationView/reducers/actualMatchingViewReducer.js +87 -8
  26. package/lib/esm/view/expenseAutomationView/selectors/actualMatchingViewSelector.js +152 -93
  27. package/lib/esm/view/expenseAutomationView/types/actualMatchingViewState.js +4 -0
  28. package/lib/index.d.ts +6 -3
  29. package/lib/index.js +21 -18
  30. package/lib/reducer.d.ts +1 -0
  31. package/lib/reducer.js +3 -0
  32. package/lib/rootStateTypes.d.ts +2 -0
  33. package/lib/view/expenseAutomationView/epics/actualMatching/fetchActualMatchingEpic.d.ts +2 -2
  34. package/lib/view/expenseAutomationView/epics/actualMatching/fetchActualMatchingEpic.js +6 -6
  35. package/lib/view/expenseAutomationView/epics/actualMatching/fetchActualMatchingMatchEpic.d.ts +12 -0
  36. package/lib/view/expenseAutomationView/epics/actualMatching/fetchActualMatchingMatchEpic.js +39 -0
  37. package/lib/view/expenseAutomationView/epics/actualMatching/searchMatchTransactionsEpic.d.ts +1 -1
  38. package/lib/view/expenseAutomationView/epics/actualMatching/searchMatchTransactionsEpic.js +35 -6
  39. package/lib/view/expenseAutomationView/epics/common/fetchAllExpenseAutomationTabsEpic.js +1 -1
  40. package/lib/view/expenseAutomationView/payload/actualMatchingPayload.d.ts +3 -6
  41. package/lib/view/expenseAutomationView/reducers/actualMatchingViewReducer.d.ts +20 -3
  42. package/lib/view/expenseAutomationView/reducers/actualMatchingViewReducer.js +88 -9
  43. package/lib/view/expenseAutomationView/selectorTypes/actualMatchingViewSelectorTypes.d.ts +24 -2
  44. package/lib/view/expenseAutomationView/selectors/actualMatchingViewSelector.d.ts +16 -2
  45. package/lib/view/expenseAutomationView/selectors/actualMatchingViewSelector.js +155 -93
  46. package/lib/view/expenseAutomationView/types/actualMatchingViewState.d.ts +7 -2
  47. package/lib/view/expenseAutomationView/types/actualMatchingViewState.js +4 -0
  48. package/package.json +1 -1
@@ -1,7 +1,7 @@
1
1
  "use strict";
2
2
  var _a;
3
3
  Object.defineProperty(exports, "__esModule", { value: true });
4
- exports.updateActualMatchingUIState = exports.searchMatchTransactionsSuccess = exports.searchMatchTransactionsFailure = exports.searchMatchTransactions = exports.searchMatchAccrualsSuccess = exports.searchMatchAccrualsFailure = exports.searchMatchAccruals = exports.openMatchNewModal = exports.matchAndReverseAccrualsSuccess = exports.matchAndReverseAccrualsFailure = exports.matchAndReverseAccruals = exports.fetchActualMatchingSuccess = exports.fetchActualMatchingPage = exports.fetchActualMatchingFailure = exports.fetchActualMatching = exports.closeMatchNewModal = exports.clearMatchNewModal = exports.clearActualMatchingView = exports.initialState = exports.initialMatchModalState = exports.initialAccrualSearchState = exports.initialTransactionSearchState = void 0;
4
+ exports.updateActualMatchingUIState = exports.searchMatchTransactionsSuccess = exports.searchMatchTransactionsFailure = exports.searchMatchTransactions = exports.searchMatchAccrualsSuccess = exports.searchMatchAccrualsFailure = exports.searchMatchAccruals = exports.openMatchNewModal = exports.matchAndReverseAccrualsSuccess = exports.matchAndReverseAccrualsFailure = exports.matchAndReverseAccruals = exports.fetchActualMatchingSuccess = exports.fetchActualMatchingPage = exports.fetchActualMatchingMatchSuccess = exports.fetchActualMatchingMatchFailure = exports.fetchActualMatchingMatch = exports.fetchActualMatchingFailure = exports.fetchActualMatching = exports.closeMatchNewModal = exports.clearMatchNewModal = exports.clearActualMatchingView = exports.initialState = exports.initialMatchModalState = exports.initialAccrualSearchState = exports.initialTransactionSearchState = void 0;
5
5
  const toolkit_1 = require("@reduxjs/toolkit");
6
6
  const timePeriod_1 = require("../../../commonStateTypes/timePeriod");
7
7
  const jeScheduleHelper_1 = require("../../../entity/jeSchedules/jeScheduleHelper");
@@ -24,18 +24,22 @@ exports.initialAccrualSearchState = {
24
24
  };
25
25
  exports.initialMatchModalState = {
26
26
  isOpen: false,
27
+ openedFromMatchId: undefined,
28
+ pinnedTransactionResults: [],
27
29
  transactionSearch: exports.initialTransactionSearchState,
28
30
  accrualSearch: exports.initialAccrualSearchState,
29
31
  confirmStatus: { fetchState: 'Not-Started', error: undefined },
30
32
  };
31
33
  exports.initialState = {
32
- accrualKeysByPeriod: {},
34
+ matchIdsByPeriod: {},
33
35
  fetchState: 'Not-Started',
34
36
  error: undefined,
35
37
  refreshStatus: {
36
38
  fetchState: 'Not-Started',
37
39
  error: undefined,
38
40
  },
41
+ detailFetchStateByMatchId: {},
42
+ detailRefreshStatusByMatchId: {},
39
43
  uiState: {
40
44
  sortKey: 'date',
41
45
  sortOrder: 'descending',
@@ -55,6 +59,8 @@ function resetMatchModalSearches(draft) {
55
59
  error: undefined,
56
60
  };
57
61
  draft.matchModal.lastBatchResults = undefined;
62
+ draft.matchModal.openedFromMatchId = undefined;
63
+ draft.matchModal.pinnedTransactionResults = [];
58
64
  }
59
65
  const expenseAutomationActualMatchingView = (0, toolkit_1.createSlice)({
60
66
  name: 'expenseAutomationActualMatchingView',
@@ -94,9 +100,9 @@ const expenseAutomationActualMatchingView = (0, toolkit_1.createSlice)({
94
100
  },
95
101
  },
96
102
  fetchActualMatchingSuccess(draft, action) {
97
- const { accruals, selectedPeriod, refreshViewInBackground } = action.payload;
103
+ const { matchIds, selectedPeriod, refreshViewInBackground } = action.payload;
98
104
  const periodId = (0, timePeriod_1.toMonthYearPeriodId)(selectedPeriod);
99
- draft.accrualKeysByPeriod[periodId] = accruals.map((accrual) => (0, jeScheduleHelper_1.generateJEOneTimeAccrualKey)(accrual._id));
105
+ draft.matchIdsByPeriod[periodId] = matchIds;
100
106
  if (refreshViewInBackground) {
101
107
  draft.refreshStatus = { fetchState: 'Completed', error: undefined };
102
108
  }
@@ -115,6 +121,56 @@ const expenseAutomationActualMatchingView = (0, toolkit_1.createSlice)({
115
121
  draft.error = status;
116
122
  }
117
123
  },
124
+ fetchActualMatchingMatch: {
125
+ prepare(matchId, refreshViewInBackground = false) {
126
+ return { payload: { matchId, refreshViewInBackground } };
127
+ },
128
+ reducer(draft, action) {
129
+ const { matchId, refreshViewInBackground } = action.payload;
130
+ if (refreshViewInBackground) {
131
+ draft.detailRefreshStatusByMatchId[matchId] = {
132
+ fetchState: 'In-Progress',
133
+ error: undefined,
134
+ };
135
+ }
136
+ else {
137
+ draft.detailFetchStateByMatchId[matchId] = {
138
+ fetchState: 'In-Progress',
139
+ error: undefined,
140
+ };
141
+ }
142
+ },
143
+ },
144
+ fetchActualMatchingMatchSuccess(draft, action) {
145
+ const { matchId, refreshViewInBackground } = action.payload;
146
+ if (refreshViewInBackground) {
147
+ draft.detailRefreshStatusByMatchId[matchId] = {
148
+ fetchState: 'Completed',
149
+ error: undefined,
150
+ };
151
+ }
152
+ else {
153
+ draft.detailFetchStateByMatchId[matchId] = {
154
+ fetchState: 'Completed',
155
+ error: undefined,
156
+ };
157
+ }
158
+ },
159
+ fetchActualMatchingMatchFailure(draft, action) {
160
+ const { matchId, refreshViewInBackground, status } = action.payload;
161
+ if (refreshViewInBackground) {
162
+ draft.detailRefreshStatusByMatchId[matchId] = {
163
+ fetchState: 'Error',
164
+ error: status,
165
+ };
166
+ }
167
+ else {
168
+ draft.detailFetchStateByMatchId[matchId] = {
169
+ fetchState: 'Error',
170
+ error: status,
171
+ };
172
+ }
173
+ },
118
174
  updateActualMatchingUIState(draft, action) {
119
175
  if (action.payload.sortKey != null) {
120
176
  draft.uiState.sortKey = action.payload.sortKey;
@@ -129,8 +185,20 @@ const expenseAutomationActualMatchingView = (0, toolkit_1.createSlice)({
129
185
  draft.uiState.scrollPosition = action.payload.scrollPosition;
130
186
  }
131
187
  },
132
- openMatchNewModal(draft) {
133
- draft.matchModal.isOpen = true;
188
+ openMatchNewModal: {
189
+ prepare(matchId) {
190
+ return { payload: { matchId } };
191
+ },
192
+ reducer(draft, action) {
193
+ resetMatchModalSearches(draft);
194
+ draft.matchModal.isOpen = true;
195
+ const matchId = action.payload.matchId;
196
+ draft.matchModal.openedFromMatchId =
197
+ matchId != null && matchId !== '' ? matchId : undefined;
198
+ if (draft.matchModal.openedFromMatchId != null) {
199
+ draft.matchModal.accrualSearch.fetchState = 'Completed';
200
+ }
201
+ },
134
202
  },
135
203
  closeMatchNewModal(draft) {
136
204
  draft.matchModal.isOpen = false;
@@ -156,8 +224,15 @@ const expenseAutomationActualMatchingView = (0, toolkit_1.createSlice)({
156
224
  draft.matchModal.transactionSearch.error = undefined;
157
225
  }
158
226
  },
159
- prepare({ query, pageToken }) {
160
- return { payload: { query, pageToken: pageToken ?? undefined } };
227
+ prepare({ query, pageToken, transactionType, transactionIntegrationId, }) {
228
+ return {
229
+ payload: {
230
+ query,
231
+ pageToken: pageToken ?? undefined,
232
+ transactionType,
233
+ transactionIntegrationId,
234
+ },
235
+ };
161
236
  },
162
237
  },
163
238
  searchMatchTransactionsSuccess(draft, action) {
@@ -175,6 +250,10 @@ const expenseAutomationActualMatchingView = (0, toolkit_1.createSlice)({
175
250
  }
176
251
  else {
177
252
  draft.matchModal.transactionSearch.results = results;
253
+ if (draft.matchModal.openedFromMatchId != null &&
254
+ draft.matchModal.pinnedTransactionResults.length === 0) {
255
+ draft.matchModal.pinnedTransactionResults = results;
256
+ }
178
257
  }
179
258
  draft.matchModal.transactionSearch.nextPageToken = nextPageToken;
180
259
  draft.matchModal.transactionSearch.isLoadingMore = false;
@@ -260,5 +339,5 @@ const expenseAutomationActualMatchingView = (0, toolkit_1.createSlice)({
260
339
  });
261
340
  },
262
341
  });
263
- _a = expenseAutomationActualMatchingView.actions, exports.clearActualMatchingView = _a.clearActualMatchingView, exports.clearMatchNewModal = _a.clearMatchNewModal, exports.closeMatchNewModal = _a.closeMatchNewModal, exports.fetchActualMatching = _a.fetchActualMatching, exports.fetchActualMatchingFailure = _a.fetchActualMatchingFailure, exports.fetchActualMatchingPage = _a.fetchActualMatchingPage, exports.fetchActualMatchingSuccess = _a.fetchActualMatchingSuccess, exports.matchAndReverseAccruals = _a.matchAndReverseAccruals, exports.matchAndReverseAccrualsFailure = _a.matchAndReverseAccrualsFailure, exports.matchAndReverseAccrualsSuccess = _a.matchAndReverseAccrualsSuccess, exports.openMatchNewModal = _a.openMatchNewModal, exports.searchMatchAccruals = _a.searchMatchAccruals, exports.searchMatchAccrualsFailure = _a.searchMatchAccrualsFailure, exports.searchMatchAccrualsSuccess = _a.searchMatchAccrualsSuccess, exports.searchMatchTransactions = _a.searchMatchTransactions, exports.searchMatchTransactionsFailure = _a.searchMatchTransactionsFailure, exports.searchMatchTransactionsSuccess = _a.searchMatchTransactionsSuccess, exports.updateActualMatchingUIState = _a.updateActualMatchingUIState;
342
+ _a = expenseAutomationActualMatchingView.actions, exports.clearActualMatchingView = _a.clearActualMatchingView, exports.clearMatchNewModal = _a.clearMatchNewModal, exports.closeMatchNewModal = _a.closeMatchNewModal, exports.fetchActualMatching = _a.fetchActualMatching, exports.fetchActualMatchingFailure = _a.fetchActualMatchingFailure, exports.fetchActualMatchingMatch = _a.fetchActualMatchingMatch, exports.fetchActualMatchingMatchFailure = _a.fetchActualMatchingMatchFailure, exports.fetchActualMatchingMatchSuccess = _a.fetchActualMatchingMatchSuccess, exports.fetchActualMatchingPage = _a.fetchActualMatchingPage, exports.fetchActualMatchingSuccess = _a.fetchActualMatchingSuccess, exports.matchAndReverseAccruals = _a.matchAndReverseAccruals, exports.matchAndReverseAccrualsFailure = _a.matchAndReverseAccrualsFailure, exports.matchAndReverseAccrualsSuccess = _a.matchAndReverseAccrualsSuccess, exports.openMatchNewModal = _a.openMatchNewModal, exports.searchMatchAccruals = _a.searchMatchAccruals, exports.searchMatchAccrualsFailure = _a.searchMatchAccrualsFailure, exports.searchMatchAccrualsSuccess = _a.searchMatchAccrualsSuccess, exports.searchMatchTransactions = _a.searchMatchTransactions, exports.searchMatchTransactionsFailure = _a.searchMatchTransactionsFailure, exports.searchMatchTransactionsSuccess = _a.searchMatchTransactionsSuccess, exports.updateActualMatchingUIState = _a.updateActualMatchingUIState;
264
343
  exports.default = expenseAutomationActualMatchingView.reducer;
@@ -1,13 +1,29 @@
1
+ import { Amount } from '../../../commonStateTypes/amount';
1
2
  import { FetchStateAndError, ID } from '../../../commonStateTypes/common';
2
3
  import { SelectorView } from '../../../commonStateTypes/viewAndReport/viewAndReport';
3
4
  import { JEOneTimeAccrual } from '../../../entity/jeSchedules/jeSchedulesSelector';
4
5
  import { ZeniDate } from '../../../zeniDayJS';
5
6
  import { ActualMatchingTransactionSearchResult, ActualMatchingViewUIState, MatchAndReverseResult } from '../types/actualMatchingViewState';
6
7
  export type ActualMatchingRowKind = 'auto_reversed' | 'pending_review' | 'manually_reversed';
8
+ export type ActualMatchingGroupedAccrual = {
9
+ accrualId: ID;
10
+ estimatedAmount?: Amount;
11
+ jeDebitAccountName?: string;
12
+ memo?: string;
13
+ serviceMonth?: string;
14
+ };
7
15
  export interface ActualMatchingRow extends JEOneTimeAccrual {
16
+ accruedAmount: Amount;
17
+ actualAmount: Amount;
8
18
  kind: ActualMatchingRowKind;
19
+ matchId: string;
9
20
  groupedAccrualIds?: ID[];
21
+ groupedMembers?: ActualMatchingGroupedAccrual[];
22
+ matchShape?: string;
23
+ matchTier?: string;
10
24
  reversalDate?: ZeniDate;
25
+ transactionDate?: string;
26
+ transactionType?: string;
11
27
  }
12
28
  export interface ActualMatchingKpiSummary {
13
29
  ai: {
@@ -47,14 +63,20 @@ export interface ActualMatchingMatchModalView {
47
63
  results: ActualMatchingTransactionSearchResult[];
48
64
  };
49
65
  lastBatchResults?: MatchAndReverseResult[];
66
+ openedFromMatchId?: string;
67
+ prefill?: {
68
+ selectedAccrualIds: ID[];
69
+ actualAmount?: number;
70
+ matchedLineId?: string;
71
+ matchedTransactionId?: string;
72
+ };
50
73
  }
51
74
  export interface ExpenseAutomationActualMatchingViewSelector extends SelectorView {
52
- autoReversed: ActualMatchingRow[];
53
75
  hasLoadedForSelectedPeriod: boolean;
54
76
  kpiSummary: ActualMatchingKpiSummary;
55
- manuallyReversed: ActualMatchingRow[];
56
77
  matchModal: ActualMatchingMatchModalView;
57
78
  pendingReview: ActualMatchingRow[];
58
79
  refreshStatus: FetchStateAndError;
80
+ reversed: ActualMatchingRow[];
59
81
  uiState: ActualMatchingViewUIState;
60
82
  }
@@ -1,11 +1,25 @@
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
+ match?: ActualMatchingMatch;
23
+ }
24
+ export declare function getExpenseAutomationActualMatchingMatchView(state: RootState, matchId: ActualMatchingMatchId): ExpenseAutomationActualMatchingMatchView;
11
25
  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,83 +93,60 @@ 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}`;
96
+ function collectGroupedMembers(members) {
97
+ if (members.length <= 1) {
98
+ return undefined;
58
99
  }
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}`;
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
+ }));
68
107
  }
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;
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');
74
112
  }
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
- function toActualMatchingRow(accrual, kind, groupedAccrualIds) {
113
+ const first = toMatchModalAccrual(firstMember);
86
114
  return {
87
- ...accrual,
88
- kind,
89
- groupedAccrualIds,
90
- 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,
91
129
  };
92
130
  }
93
- function collapseActualMatchingRows(accruals, kind) {
94
- const groups = new Map();
95
- for (const accrual of accruals) {
96
- const key = getActualMatchingBillCollapseKey(accrual);
97
- const members = groups.get(key);
98
- if (members != null) {
99
- members.push(accrual);
100
- }
101
- else {
102
- groups.set(key, [accrual]);
103
- }
104
- }
105
- const rows = [];
106
- for (const members of groups.values()) {
107
- rows.push(toActualMatchingRow(members[0], kind, collectGroupedAccrualIds(members)));
108
- }
109
- return rows;
110
- }
111
- function sumCollapsedActualMatchingAmounts(rows) {
112
- return rows.reduce((sum, row) => sum + getActualMatchingAmount(row), 0);
113
- }
114
- function matchesSearch(accrual, searchString) {
131
+ function matchesSearch(row, searchString) {
115
132
  const trimmed = searchString.trim().toLowerCase();
116
133
  if (trimmed.length === 0) {
117
134
  return true;
118
135
  }
119
- return (accrual.vendorName.toLowerCase().includes(trimmed) ||
120
- 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));
121
143
  }
122
144
  function getActualMatchingSortValue(row, sortKey) {
123
145
  switch (sortKey) {
124
146
  case 'vendor':
125
147
  return row.vendorName.toLowerCase();
126
148
  case 'date':
127
- return row.reversalDate?.valueOf();
149
+ return row.reversalDate?.valueOf() ?? row.transactionDate;
128
150
  case 'amount':
129
151
  return getActualMatchingAmount(row);
130
152
  case 'category':
@@ -132,10 +154,23 @@ function getActualMatchingSortValue(row, sortKey) {
132
154
  case 'class':
133
155
  return row.jeDebitAccountingClassName?.toLowerCase();
134
156
  case 'type':
135
- return (row.cleared?.matchedTransactionType ??
136
- row.matchSuggestion?.matchedTransactionType)?.toLowerCase();
157
+ return row.transactionType?.toLowerCase();
137
158
  case 'lifecycle':
138
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
+ }
139
174
  default:
140
175
  return undefined;
141
176
  }
@@ -153,37 +188,50 @@ function emptyKpiSummary() {
153
188
  manual: { count: 0 },
154
189
  };
155
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
+ };
201
+ }
156
202
  function getExpenseAutomationActualMatchingView(state) {
157
203
  const { expenseAutomationActualMatchingViewState, expenseAutomationViewState } = state;
158
- const { accrualKeysByPeriod, fetchState, error, refreshStatus, uiState, matchModal, } = expenseAutomationActualMatchingViewState;
204
+ const { matchIdsByPeriod, fetchState, error, refreshStatus, uiState, matchModal, } = expenseAutomationActualMatchingViewState;
159
205
  const currentTenant = (0, tenantSelector_1.getCurrentTenant)(state);
160
206
  const selectedPeriod = expenseAutomationViewState.selectedPeriodByTenantId[currentTenant.tenantId];
161
207
  const monthYearPeriodId = selectedPeriod != null ? (0, timePeriod_1.toMonthYearPeriodId)(selectedPeriod) : undefined;
162
- const accrualKeys = monthYearPeriodId != null
163
- ? accrualKeysByPeriod[monthYearPeriodId]
208
+ const matchIds = monthYearPeriodId != null
209
+ ? matchIdsByPeriod[monthYearPeriodId]
164
210
  : undefined;
165
- const accruals = (accrualKeys ?? [])
166
- .map((key) => (0, jeSchedulesSelector_1.getJEOneTimeAccrualByKey)(key, state.jeSchedulesState))
167
- .filter((accrual) => accrual != null);
168
- const filtered = accruals.filter((accrual) => matchesSearch(accrual, uiState.searchString));
169
- const autoReversed = sortActualMatchingRows(collapseActualMatchingRows(filtered.filter(isAutoReversedAccrual), 'auto_reversed'), uiState);
170
- const pendingReview = sortActualMatchingRows(collapseActualMatchingRows(filtered.filter(isPendingReviewAccrual), 'pending_review'), uiState);
171
- const manuallyReversed = sortActualMatchingRows(collapseActualMatchingRows(filtered.filter(isManuallyReversedAccrual), 'manually_reversed'), uiState);
172
- const listedRows = [...autoReversed, ...pendingReview, ...manuallyReversed];
211
+ const rows = (matchIds ?? [])
212
+ .map((matchId) => (0, actualMatchingSelector_1.getActualMatchingMatchById)(matchId, state.actualMatchingState))
213
+ .filter((match) => match != null)
214
+ .filter((match) => match.members.length > 0)
215
+ .map(toActualMatchingRow)
216
+ .filter((row) => matchesSearch(row, uiState.searchString));
217
+ const reversed = sortActualMatchingRows(rows.filter((row) => isReversedMatchKind(row.kind)), uiState);
218
+ const pendingReview = sortActualMatchingRows(rows.filter((row) => row.kind === 'pending_review'), uiState);
219
+ const autoReversedForKpi = reversed.filter((row) => row.kind === 'auto_reversed');
220
+ const listedRows = [...reversed, ...pendingReview];
173
221
  const kpiSummary = listedRows.length === 0
174
222
  ? emptyKpiSummary()
175
223
  : {
176
224
  autoReversed: {
177
- count: autoReversed.length,
178
- amount: sumCollapsedActualMatchingAmounts(autoReversed),
225
+ count: autoReversedForKpi.length,
226
+ amount: sumRowAmounts(autoReversedForKpi),
179
227
  },
180
228
  pendingReview: {
181
229
  count: pendingReview.length,
182
- amount: sumCollapsedActualMatchingAmounts(pendingReview),
230
+ amount: sumRowAmounts(pendingReview),
183
231
  },
184
232
  totalThisClose: {
185
233
  count: listedRows.length,
186
- amount: sumCollapsedActualMatchingAmounts(listedRows),
234
+ amount: sumRowAmounts(listedRows),
187
235
  },
188
236
  ai: {
189
237
  count: listedRows.filter((row) => row.origin === 'agent').length,
@@ -192,26 +240,40 @@ function getExpenseAutomationActualMatchingView(state) {
192
240
  count: listedRows.filter((row) => row.origin === 'human').length,
193
241
  },
194
242
  };
195
- const accrualSearchResults = matchModal.accrualSearch.results
243
+ const searchedAccruals = matchModal.accrualSearch.results
196
244
  .map((key) => (0, jeSchedulesSelector_1.getJEOneTimeAccrualByKey)(key, state.jeSchedulesState))
197
245
  .filter((accrual) => accrual != null);
246
+ const openedMatch = matchModal.openedFromMatchId != null
247
+ ? (0, actualMatchingSelector_1.getActualMatchingMatchById)(matchModal.openedFromMatchId, state.actualMatchingState)
248
+ : undefined;
249
+ const pinnedAccruals = (openedMatch?.members ?? []).map(toMatchModalAccrual);
250
+ const firstSuggestion = openedMatch?.members[0]?.matchSuggestion;
251
+ const prefill = openedMatch == null
252
+ ? undefined
253
+ : {
254
+ selectedAccrualIds: openedMatch.members.map((member) => member.accrualId),
255
+ actualAmount: openedMatch.actualAmount.amount,
256
+ matchedLineId: firstSuggestion?.matchedLineId,
257
+ matchedTransactionId: firstSuggestion?.matchedTransactionId,
258
+ };
198
259
  return {
199
260
  fetchState,
200
261
  error,
201
- autoReversed,
262
+ reversed,
202
263
  pendingReview,
203
- manuallyReversed,
204
264
  kpiSummary,
205
265
  uiState,
206
266
  refreshStatus,
207
- hasLoadedForSelectedPeriod: accrualKeys != null,
267
+ hasLoadedForSelectedPeriod: matchIds != null,
208
268
  matchModal: {
209
269
  isOpen: matchModal.isOpen,
270
+ openedFromMatchId: matchModal.openedFromMatchId,
271
+ prefill,
210
272
  confirmStatus: matchModal.confirmStatus,
211
273
  lastBatchResults: matchModal.lastBatchResults,
212
274
  transactionSearch: {
213
275
  query: matchModal.transactionSearch.query,
214
- results: matchModal.transactionSearch.results,
276
+ results: uniqueTransactionSearchResults(matchModal.pinnedTransactionResults, matchModal.transactionSearch.results),
215
277
  fetchState: {
216
278
  fetchState: matchModal.transactionSearch.fetchState,
217
279
  error: matchModal.transactionSearch.error,
@@ -221,7 +283,7 @@ function getExpenseAutomationActualMatchingView(state) {
221
283
  },
222
284
  accrualSearch: {
223
285
  query: matchModal.accrualSearch.query,
224
- results: accrualSearchResults,
286
+ results: uniqueMatchModalAccruals(pinnedAccruals, searchedAccruals),
225
287
  fetchState: {
226
288
  fetchState: matchModal.accrualSearch.fetchState,
227
289
  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;
@@ -70,11 +71,15 @@ export interface ActualMatchingMatchModalState {
70
71
  accrualSearch: ActualMatchingAccrualSearchState;
71
72
  confirmStatus: FetchStateAndError;
72
73
  isOpen: boolean;
74
+ pinnedTransactionResults: ActualMatchingTransactionSearchResult[];
73
75
  transactionSearch: ActualMatchingTransactionSearchState;
74
76
  lastBatchResults?: MatchAndReverseResult[];
77
+ openedFromMatchId?: ActualMatchingMatchId;
75
78
  }
76
79
  export interface ActualMatchingViewState extends FetchedState {
77
- accrualKeysByPeriod: Record<MonthYearPeriodId, JEOneTimeAccrualKey[]>;
80
+ detailFetchStateByMatchId: Record<ActualMatchingMatchId, FetchStateAndError>;
81
+ detailRefreshStatusByMatchId: Record<ActualMatchingMatchId, FetchStateAndError>;
82
+ matchIdsByPeriod: Record<MonthYearPeriodId, ActualMatchingMatchId[]>;
78
83
  matchModal: ActualMatchingMatchModalState;
79
84
  refreshStatus: FetchStateAndError;
80
85
  uiState: ActualMatchingViewUIState;
@@ -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;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zeniai/client-epic-state",
3
- "version": "5.2.22-betaAM3",
3
+ "version": "5.2.22-betaAM5",
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",