@zeniai/client-epic-state 5.2.22-betaAK0 → 5.2.22-betaAM1

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 (117) hide show
  1. package/lib/entity/invoicing/creditNote/creditNotePayload.d.ts +1 -0
  2. package/lib/entity/invoicing/creditNote/creditNotePayload.js +1 -0
  3. package/lib/entity/invoicing/creditNote/creditNoteState.d.ts +1 -0
  4. package/lib/entity/invoicing/invoice/invoicePayload.d.ts +1 -0
  5. package/lib/entity/invoicing/invoice/invoicePayload.js +1 -0
  6. package/lib/entity/invoicing/invoice/invoiceState.d.ts +1 -0
  7. package/lib/entity/invoicing/invoicingCommonPayload.d.ts +0 -2
  8. package/lib/entity/invoicing/invoicingCustomer/invoicingCustomerPayload.d.ts +1 -0
  9. package/lib/entity/invoicing/invoicingCustomer/invoicingCustomerPayload.js +1 -0
  10. package/lib/entity/invoicing/invoicingCustomer/invoicingCustomerState.d.ts +1 -0
  11. package/lib/entity/invoicing/invoicingSubscription/invoicingSubscriptionPayload.d.ts +2 -1
  12. package/lib/entity/invoicing/invoicingSubscription/invoicingSubscriptionPayload.js +2 -1
  13. package/lib/entity/invoicing/invoicingSubscription/invoicingSubscriptionState.d.ts +2 -1
  14. package/lib/entity/jeSchedules/jeSchedulesPayload.d.ts +24 -0
  15. package/lib/entity/jeSchedules/jeSchedulesPayload.js +40 -0
  16. package/lib/entity/jeSchedules/jeSchedulesState.d.ts +26 -0
  17. package/lib/epic.d.ts +6 -1
  18. package/lib/epic.js +10 -0
  19. package/lib/esm/entity/invoicing/creditNote/creditNotePayload.js +1 -0
  20. package/lib/esm/entity/invoicing/invoice/invoicePayload.js +1 -0
  21. package/lib/esm/entity/invoicing/invoicingCustomer/invoicingCustomerPayload.js +1 -0
  22. package/lib/esm/entity/invoicing/invoicingSubscription/invoicingSubscriptionPayload.js +2 -1
  23. package/lib/esm/entity/jeSchedules/jeSchedulesPayload.js +40 -0
  24. package/lib/esm/epic.js +10 -0
  25. package/lib/esm/index.js +6 -2
  26. package/lib/esm/reducer.js +3 -0
  27. package/lib/esm/view/expenseAutomationView/epics/accountRecon/deleteAccountStatementEpic.js +1 -3
  28. package/lib/esm/view/expenseAutomationView/epics/actualMatching/fetchActualMatchingEpic.js +46 -0
  29. package/lib/esm/view/expenseAutomationView/epics/actualMatching/fetchActualMatchingPageEpic.js +7 -0
  30. package/lib/esm/view/expenseAutomationView/epics/actualMatching/matchAndReverseAccrualsEpic.js +50 -0
  31. package/lib/esm/view/expenseAutomationView/epics/actualMatching/searchMatchAccrualsEpic.js +44 -0
  32. package/lib/esm/view/expenseAutomationView/epics/actualMatching/searchMatchTransactionsEpic.js +44 -0
  33. package/lib/esm/view/expenseAutomationView/epics/common/fetchAllExpenseAutomationTabsEpic.js +28 -11
  34. package/lib/esm/view/expenseAutomationView/epics/common/refreshExpenseAutomationCurrentTabEpic.js +9 -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 +60 -0
  38. package/lib/esm/view/expenseAutomationView/reducers/actualMatchingViewReducer.js +260 -0
  39. package/lib/esm/view/expenseAutomationView/selectorTypes/actualMatchingViewSelectorTypes.js +1 -0
  40. package/lib/esm/view/expenseAutomationView/selectors/actualMatchingViewSelector.js +200 -0
  41. package/lib/esm/view/expenseAutomationView/selectors/jeSchedulesViewSelector.js +3 -0
  42. package/lib/esm/view/expenseAutomationView/types/actualMatchingViewState.js +22 -0
  43. package/lib/esm/view/expenseAutomationView/types/jeSchedulesViewState.js +5 -1
  44. package/lib/esm/view/invoicing/invoicingConfigView/invoicingConfigViewReducer.js +0 -2
  45. package/lib/esm/view/invoicing/invoicingOverview/invoicingOverviewPayload.js +1 -0
  46. package/lib/esm/view/invoicing/invoicingSubscriptionDetailView/invoicingSubscriptionDetailViewSelector.js +1 -2
  47. package/lib/esm/view/invoicing/invoicingSubscriptionListView/invoicingSubscriptionListViewSelector.js +0 -1
  48. package/lib/esm/view/invoicing/invoicingSubscriptionListView/invoicingSubscriptionListViewState.js +2 -0
  49. package/lib/esm/view/spendManagement/billPay/billPaySetupApproverView/epic/fetchBillPaySetupApproverViewEpic.js +18 -2
  50. package/lib/esm/view/spendManagement/billPay/billPaySetupApproverView/epic/initializeBillPaySetupApproverViewUpdateDataEpic.js +0 -1
  51. package/lib/esm/view/spendManagement/billPay/billPaySetupApproverView/types/commonPayload.js +0 -3
  52. package/lib/esm/view/spendManagement/reimbursement/remiSetupApproverView/epic/fetchRemiSetupApproverViewEpic.js +18 -2
  53. package/lib/esm/view/spendManagement/reimbursement/remiSetupApproverView/epic/initializeRemiSetupApproverViewUpdateDataEpic.js +0 -1
  54. package/lib/index.d.ts +9 -5
  55. package/lib/index.js +73 -47
  56. package/lib/reducer.d.ts +1 -0
  57. package/lib/reducer.js +3 -0
  58. package/lib/rootStateTypes.d.ts +2 -0
  59. package/lib/view/expenseAutomationView/epics/accountRecon/deleteAccountStatementEpic.d.ts +1 -2
  60. package/lib/view/expenseAutomationView/epics/accountRecon/deleteAccountStatementEpic.js +1 -3
  61. package/lib/view/expenseAutomationView/epics/actualMatching/fetchActualMatchingEpic.d.ts +9 -0
  62. package/lib/view/expenseAutomationView/epics/actualMatching/fetchActualMatchingEpic.js +50 -0
  63. package/lib/view/expenseAutomationView/epics/actualMatching/fetchActualMatchingPageEpic.d.ts +5 -0
  64. package/lib/view/expenseAutomationView/epics/actualMatching/fetchActualMatchingPageEpic.js +11 -0
  65. package/lib/view/expenseAutomationView/epics/actualMatching/matchAndReverseAccrualsEpic.d.ts +8 -0
  66. package/lib/view/expenseAutomationView/epics/actualMatching/matchAndReverseAccrualsEpic.js +54 -0
  67. package/lib/view/expenseAutomationView/epics/actualMatching/searchMatchAccrualsEpic.d.ts +8 -0
  68. package/lib/view/expenseAutomationView/epics/actualMatching/searchMatchAccrualsEpic.js +48 -0
  69. package/lib/view/expenseAutomationView/epics/actualMatching/searchMatchTransactionsEpic.d.ts +8 -0
  70. package/lib/view/expenseAutomationView/epics/actualMatching/searchMatchTransactionsEpic.js +48 -0
  71. package/lib/view/expenseAutomationView/epics/common/fetchAllExpenseAutomationTabsEpic.d.ts +2 -1
  72. package/lib/view/expenseAutomationView/epics/common/fetchAllExpenseAutomationTabsEpic.js +28 -11
  73. package/lib/view/expenseAutomationView/epics/common/refreshExpenseAutomationCurrentTabEpic.d.ts +2 -1
  74. package/lib/view/expenseAutomationView/epics/common/refreshExpenseAutomationCurrentTabEpic.js +9 -1
  75. package/lib/view/expenseAutomationView/epics/jeSchedule/switchJESchedulesTabEpic.d.ts +2 -1
  76. package/lib/view/expenseAutomationView/epics/jeSchedule/switchJESchedulesTabEpic.js +5 -0
  77. package/lib/view/expenseAutomationView/expenseAutomationViewSelector.js +22 -7
  78. package/lib/view/expenseAutomationView/payload/actualMatchingPayload.d.ts +72 -0
  79. package/lib/view/expenseAutomationView/payload/actualMatchingPayload.js +65 -0
  80. package/lib/view/expenseAutomationView/reducers/actualMatchingViewReducer.d.ts +53 -0
  81. package/lib/view/expenseAutomationView/reducers/actualMatchingViewReducer.js +264 -0
  82. package/lib/view/expenseAutomationView/reducers/jeSchedulesViewReducer.d.ts +2 -2
  83. package/lib/view/expenseAutomationView/selectorTypes/actualMatchingViewSelectorTypes.d.ts +59 -0
  84. package/lib/view/expenseAutomationView/selectorTypes/actualMatchingViewSelectorTypes.js +2 -0
  85. package/lib/view/expenseAutomationView/selectorTypes/expenseAutomationViewSelectorTypes.d.ts +2 -0
  86. package/lib/view/expenseAutomationView/selectors/actualMatchingViewSelector.d.ts +11 -0
  87. package/lib/view/expenseAutomationView/selectors/actualMatchingViewSelector.js +212 -0
  88. package/lib/view/expenseAutomationView/selectors/jeSchedulesViewSelector.js +3 -0
  89. package/lib/view/expenseAutomationView/types/actualMatchingViewState.d.ts +81 -0
  90. package/lib/view/expenseAutomationView/types/actualMatchingViewState.js +27 -0
  91. package/lib/view/expenseAutomationView/types/jeSchedulesViewState.d.ts +1 -1
  92. package/lib/view/expenseAutomationView/types/jeSchedulesViewState.js +5 -1
  93. package/lib/view/invoicing/invoicingConfigView/invoicingConfigViewPayload.d.ts +0 -1
  94. package/lib/view/invoicing/invoicingConfigView/invoicingConfigViewReducer.d.ts +1 -1
  95. package/lib/view/invoicing/invoicingConfigView/invoicingConfigViewReducer.js +0 -2
  96. package/lib/view/invoicing/invoicingConfigView/invoicingConfigViewState.d.ts +0 -1
  97. package/lib/view/invoicing/invoicingOverview/invoicingOverviewPayload.d.ts +1 -0
  98. package/lib/view/invoicing/invoicingOverview/invoicingOverviewPayload.js +1 -0
  99. package/lib/view/invoicing/invoicingOverview/invoicingOverviewState.d.ts +1 -0
  100. package/lib/view/invoicing/invoicingSubscriptionDetailView/invoicingSubscriptionDetailViewSelector.d.ts +1 -3
  101. package/lib/view/invoicing/invoicingSubscriptionDetailView/invoicingSubscriptionDetailViewSelector.js +0 -1
  102. package/lib/view/invoicing/invoicingSubscriptionListView/invoicingSubscriptionListViewSelector.d.ts +0 -2
  103. package/lib/view/invoicing/invoicingSubscriptionListView/invoicingSubscriptionListViewSelector.js +0 -1
  104. package/lib/view/invoicing/invoicingSubscriptionListView/invoicingSubscriptionListViewState.d.ts +2 -2
  105. package/lib/view/invoicing/invoicingSubscriptionListView/invoicingSubscriptionListViewState.js +2 -0
  106. package/lib/view/invoicing/issueCreditNote/issueCreditNotePayload.d.ts +1 -0
  107. package/lib/view/invoicing/subscriptionAction/subscriptionActionRequestPayload.d.ts +0 -8
  108. package/lib/view/spendManagement/billPay/billPaySetupApproverView/epic/fetchBillPaySetupApproverViewEpic.d.ts +2 -1
  109. package/lib/view/spendManagement/billPay/billPaySetupApproverView/epic/fetchBillPaySetupApproverViewEpic.js +18 -2
  110. package/lib/view/spendManagement/billPay/billPaySetupApproverView/epic/initializeBillPaySetupApproverViewUpdateDataEpic.js +0 -1
  111. package/lib/view/spendManagement/billPay/billPaySetupApproverView/types/commonPayload.d.ts +0 -1
  112. package/lib/view/spendManagement/billPay/billPaySetupApproverView/types/commonPayload.js +0 -3
  113. package/lib/view/spendManagement/billPay/billPaySetupApproverView/types/commonState.d.ts +0 -1
  114. package/lib/view/spendManagement/reimbursement/remiSetupApproverView/epic/fetchRemiSetupApproverViewEpic.d.ts +2 -1
  115. package/lib/view/spendManagement/reimbursement/remiSetupApproverView/epic/fetchRemiSetupApproverViewEpic.js +18 -2
  116. package/lib/view/spendManagement/reimbursement/remiSetupApproverView/epic/initializeRemiSetupApproverViewUpdateDataEpic.js +0 -1
  117. package/package.json +38 -71
@@ -0,0 +1,260 @@
1
+ import { createSlice } from '@reduxjs/toolkit';
2
+ import { toMonthYearPeriodId, } from '../../../commonStateTypes/timePeriod';
3
+ import { generateJEOneTimeAccrualKey } from '../../../entity/jeSchedules/jeScheduleHelper';
4
+ import { clearAll } from '../../../rootActions';
5
+ export const initialTransactionSearchState = {
6
+ query: '',
7
+ results: [],
8
+ fetchState: 'Not-Started',
9
+ error: undefined,
10
+ nextPageToken: null,
11
+ isLoadingMore: false,
12
+ };
13
+ export const initialAccrualSearchState = {
14
+ query: '',
15
+ results: [],
16
+ fetchState: 'Not-Started',
17
+ error: undefined,
18
+ nextPageToken: null,
19
+ isLoadingMore: false,
20
+ };
21
+ export const initialMatchModalState = {
22
+ isOpen: false,
23
+ transactionSearch: initialTransactionSearchState,
24
+ accrualSearch: initialAccrualSearchState,
25
+ confirmStatus: { fetchState: 'Not-Started', error: undefined },
26
+ };
27
+ export const initialState = {
28
+ accrualKeysByPeriod: {},
29
+ fetchState: 'Not-Started',
30
+ error: undefined,
31
+ refreshStatus: {
32
+ fetchState: 'Not-Started',
33
+ error: undefined,
34
+ },
35
+ uiState: {
36
+ sortKey: 'date',
37
+ sortOrder: 'descending',
38
+ searchString: '',
39
+ scrollPosition: { scrollTop: 0, scrollLeft: undefined },
40
+ },
41
+ matchModal: initialMatchModalState,
42
+ hasValidState() {
43
+ return this.fetchState == 'Completed';
44
+ },
45
+ };
46
+ function resetMatchModalSearches(draft) {
47
+ draft.matchModal.transactionSearch = initialTransactionSearchState;
48
+ draft.matchModal.accrualSearch = initialAccrualSearchState;
49
+ draft.matchModal.confirmStatus = {
50
+ fetchState: 'Not-Started',
51
+ error: undefined,
52
+ };
53
+ draft.matchModal.lastBatchResults = undefined;
54
+ }
55
+ const expenseAutomationActualMatchingView = createSlice({
56
+ name: 'expenseAutomationActualMatchingView',
57
+ initialState,
58
+ reducers: {
59
+ fetchActualMatchingPage: {
60
+ prepare(period, refreshViewInBackground = false) {
61
+ return {
62
+ payload: {
63
+ period,
64
+ refreshViewInBackground,
65
+ },
66
+ };
67
+ },
68
+ reducer() {
69
+ // Epic-only fan-out.
70
+ },
71
+ },
72
+ fetchActualMatching: {
73
+ reducer(draft, action) {
74
+ const { refreshViewInBackground } = action.payload;
75
+ if (refreshViewInBackground) {
76
+ draft.refreshStatus = { fetchState: 'In-Progress', error: undefined };
77
+ }
78
+ else {
79
+ draft.fetchState = 'In-Progress';
80
+ draft.error = undefined;
81
+ }
82
+ },
83
+ prepare(period, refreshViewInBackground = false) {
84
+ return {
85
+ payload: {
86
+ period,
87
+ refreshViewInBackground,
88
+ },
89
+ };
90
+ },
91
+ },
92
+ fetchActualMatchingSuccess(draft, action) {
93
+ const { accruals, selectedPeriod, refreshViewInBackground } = action.payload;
94
+ const periodId = toMonthYearPeriodId(selectedPeriod);
95
+ draft.accrualKeysByPeriod[periodId] = accruals.map((accrual) => generateJEOneTimeAccrualKey(accrual._id));
96
+ if (refreshViewInBackground) {
97
+ draft.refreshStatus = { fetchState: 'Completed', error: undefined };
98
+ }
99
+ else {
100
+ draft.fetchState = 'Completed';
101
+ draft.error = undefined;
102
+ }
103
+ },
104
+ fetchActualMatchingFailure(draft, action) {
105
+ const { status, refreshViewInBackground } = action.payload;
106
+ if (refreshViewInBackground) {
107
+ draft.refreshStatus = { fetchState: 'Error', error: status };
108
+ }
109
+ else {
110
+ draft.fetchState = 'Error';
111
+ draft.error = status;
112
+ }
113
+ },
114
+ updateActualMatchingUIState(draft, action) {
115
+ if (action.payload.sortKey != null) {
116
+ draft.uiState.sortKey = action.payload.sortKey;
117
+ }
118
+ if (action.payload.sortOrder != null) {
119
+ draft.uiState.sortOrder = action.payload.sortOrder;
120
+ }
121
+ if (action.payload.searchString != null) {
122
+ draft.uiState.searchString = action.payload.searchString;
123
+ }
124
+ if (action.payload.scrollPosition != null) {
125
+ draft.uiState.scrollPosition = action.payload.scrollPosition;
126
+ }
127
+ },
128
+ openMatchNewModal(draft) {
129
+ draft.matchModal.isOpen = true;
130
+ },
131
+ closeMatchNewModal(draft) {
132
+ draft.matchModal.isOpen = false;
133
+ resetMatchModalSearches(draft);
134
+ },
135
+ clearMatchNewModal(draft) {
136
+ draft.matchModal.isOpen = false;
137
+ resetMatchModalSearches(draft);
138
+ },
139
+ searchMatchTransactions: {
140
+ reducer(draft, action) {
141
+ const { query, pageToken } = action.payload;
142
+ const isLoadMore = pageToken != null;
143
+ draft.matchModal.transactionSearch.query = query;
144
+ if (isLoadMore) {
145
+ draft.matchModal.transactionSearch.isLoadingMore = true;
146
+ }
147
+ else {
148
+ draft.matchModal.transactionSearch.isLoadingMore = false;
149
+ draft.matchModal.transactionSearch.results = [];
150
+ draft.matchModal.transactionSearch.nextPageToken = null;
151
+ draft.matchModal.transactionSearch.fetchState = 'In-Progress';
152
+ draft.matchModal.transactionSearch.error = undefined;
153
+ }
154
+ },
155
+ prepare({ query, pageToken }) {
156
+ return { payload: { query, pageToken: pageToken ?? undefined } };
157
+ },
158
+ },
159
+ searchMatchTransactionsSuccess(draft, action) {
160
+ const { append, nextPageToken, results } = action.payload;
161
+ if (append) {
162
+ const merged = [
163
+ ...draft.matchModal.transactionSearch.results,
164
+ ...results,
165
+ ];
166
+ const byKey = new Map(merged.map((result) => [
167
+ `${result.transactionId}:${result.lineId}`,
168
+ result,
169
+ ]));
170
+ draft.matchModal.transactionSearch.results = Array.from(byKey.values());
171
+ }
172
+ else {
173
+ draft.matchModal.transactionSearch.results = results;
174
+ }
175
+ draft.matchModal.transactionSearch.nextPageToken = nextPageToken;
176
+ draft.matchModal.transactionSearch.isLoadingMore = false;
177
+ draft.matchModal.transactionSearch.fetchState = 'Completed';
178
+ draft.matchModal.transactionSearch.error = undefined;
179
+ },
180
+ searchMatchTransactionsFailure(draft, action) {
181
+ draft.matchModal.transactionSearch.isLoadingMore = false;
182
+ draft.matchModal.transactionSearch.fetchState = 'Error';
183
+ draft.matchModal.transactionSearch.error = action.payload.error;
184
+ },
185
+ searchMatchAccruals: {
186
+ reducer(draft, action) {
187
+ const { query, pageToken } = action.payload;
188
+ const isLoadMore = pageToken != null;
189
+ draft.matchModal.accrualSearch.query = query;
190
+ if (isLoadMore) {
191
+ draft.matchModal.accrualSearch.isLoadingMore = true;
192
+ }
193
+ else {
194
+ draft.matchModal.accrualSearch.isLoadingMore = false;
195
+ draft.matchModal.accrualSearch.results = [];
196
+ draft.matchModal.accrualSearch.nextPageToken = null;
197
+ draft.matchModal.accrualSearch.fetchState = 'In-Progress';
198
+ draft.matchModal.accrualSearch.error = undefined;
199
+ }
200
+ },
201
+ prepare({ query, pageToken }) {
202
+ return { payload: { query, pageToken: pageToken ?? undefined } };
203
+ },
204
+ },
205
+ searchMatchAccrualsSuccess(draft, action) {
206
+ const { append, nextPageToken, results } = action.payload;
207
+ const keys = results.map((accrual) => generateJEOneTimeAccrualKey(accrual._id));
208
+ if (append) {
209
+ const merged = [...draft.matchModal.accrualSearch.results, ...keys];
210
+ draft.matchModal.accrualSearch.results = Array.from(new Set(merged));
211
+ }
212
+ else {
213
+ draft.matchModal.accrualSearch.results = keys;
214
+ }
215
+ draft.matchModal.accrualSearch.nextPageToken = nextPageToken;
216
+ draft.matchModal.accrualSearch.isLoadingMore = false;
217
+ draft.matchModal.accrualSearch.fetchState = 'Completed';
218
+ draft.matchModal.accrualSearch.error = undefined;
219
+ },
220
+ searchMatchAccrualsFailure(draft, action) {
221
+ draft.matchModal.accrualSearch.isLoadingMore = false;
222
+ draft.matchModal.accrualSearch.fetchState = 'Error';
223
+ draft.matchModal.accrualSearch.error = action.payload.error;
224
+ },
225
+ matchAndReverseAccruals: {
226
+ reducer(draft) {
227
+ draft.matchModal.confirmStatus = {
228
+ fetchState: 'In-Progress',
229
+ error: undefined,
230
+ };
231
+ },
232
+ prepare(params) {
233
+ return { payload: params };
234
+ },
235
+ },
236
+ matchAndReverseAccrualsSuccess(draft, action) {
237
+ draft.matchModal.confirmStatus = {
238
+ fetchState: 'Completed',
239
+ error: undefined,
240
+ };
241
+ draft.matchModal.lastBatchResults = action.payload.results;
242
+ },
243
+ matchAndReverseAccrualsFailure(draft, action) {
244
+ draft.matchModal.confirmStatus = {
245
+ fetchState: 'Error',
246
+ error: action.payload.status,
247
+ };
248
+ },
249
+ clearActualMatchingView(draft) {
250
+ Object.assign(draft, initialState);
251
+ },
252
+ },
253
+ extraReducers: (builder) => {
254
+ builder.addCase(clearAll, (draft) => {
255
+ Object.assign(draft, initialState);
256
+ });
257
+ },
258
+ });
259
+ export const { clearActualMatchingView, clearMatchNewModal, closeMatchNewModal, fetchActualMatching, fetchActualMatchingFailure, fetchActualMatchingPage, fetchActualMatchingSuccess, matchAndReverseAccruals, matchAndReverseAccrualsFailure, matchAndReverseAccrualsSuccess, openMatchNewModal, searchMatchAccruals, searchMatchAccrualsFailure, searchMatchAccrualsSuccess, searchMatchTransactions, searchMatchTransactionsFailure, searchMatchTransactionsSuccess, updateActualMatchingUIState, } = expenseAutomationActualMatchingView.actions;
260
+ export default expenseAutomationActualMatchingView.reducer;
@@ -0,0 +1,200 @@
1
+ import orderBy from 'lodash/orderBy';
2
+ import { toMonthYearPeriodId } from '../../../commonStateTypes/timePeriod';
3
+ import { getJEOneTimeAccrualByKey, } from '../../../entity/jeSchedules/jeSchedulesSelector';
4
+ import { getCurrentTenant } from '../../../entity/tenant/tenantSelector';
5
+ export function isAutoReversedAccrual(accrual) {
6
+ return (accrual.accrualStatus === 'reversed' &&
7
+ accrual.reversalTrigger === 'bill_match');
8
+ }
9
+ export function isManuallyReversedAccrual(accrual) {
10
+ return (accrual.accrualStatus === 'reversed' &&
11
+ accrual.reversalTrigger === 'manual_reverse');
12
+ }
13
+ export function isPendingReviewAccrual(accrual) {
14
+ if (accrual.accrualStatus !== 'posted' || accrual.matchSuggestion == null) {
15
+ return false;
16
+ }
17
+ const resolution = accrual.matchSuggestion.resolution;
18
+ return resolution == null || resolution.length === 0;
19
+ }
20
+ function isGroupedClearedMatch(accrual) {
21
+ const groupSum = accrual.cleared?.groupSum?.amount;
22
+ if (groupSum == null || groupSum <= 0) {
23
+ return false;
24
+ }
25
+ const matchShape = accrual.cleared?.matchShape;
26
+ const accrualIdsLength = accrual.cleared?.accrualIds?.length ?? 0;
27
+ return matchShape === '1:N' || matchShape === 'N:1' || accrualIdsLength > 1;
28
+ }
29
+ export function getClearedAllocatedActualAmount(accrual) {
30
+ const matchedAmount = accrual.cleared?.matchedAmount?.amount;
31
+ if (matchedAmount == null) {
32
+ return undefined;
33
+ }
34
+ if (!isGroupedClearedMatch(accrual)) {
35
+ return matchedAmount;
36
+ }
37
+ const groupSum = accrual.cleared?.groupSum?.amount;
38
+ if (groupSum == null || groupSum <= 0) {
39
+ return matchedAmount;
40
+ }
41
+ return matchedAmount * (accrual.estimatedAmount.amount / groupSum);
42
+ }
43
+ export function getActualMatchingAmount(accrual) {
44
+ if (isPendingReviewAccrual(accrual)) {
45
+ return (accrual.matchSuggestion?.matchedAmount?.amount ??
46
+ accrual.estimatedAmount.amount);
47
+ }
48
+ if (isAutoReversedAccrual(accrual) || isManuallyReversedAccrual(accrual)) {
49
+ return (getClearedAllocatedActualAmount(accrual) ?? accrual.estimatedAmount.amount);
50
+ }
51
+ return accrual.estimatedAmount.amount;
52
+ }
53
+ export function getActualMatchingReversalDate(accrual) {
54
+ if (!isAutoReversedAccrual(accrual) && !isManuallyReversedAccrual(accrual)) {
55
+ return undefined;
56
+ }
57
+ return accrual.actualReversalPostDate ?? accrual.cleared?.reversedAt;
58
+ }
59
+ function toActualMatchingRow(accrual, kind) {
60
+ return {
61
+ ...accrual,
62
+ kind,
63
+ reversalDate: kind === 'pending_review'
64
+ ? undefined
65
+ : getActualMatchingReversalDate(accrual),
66
+ };
67
+ }
68
+ function matchesSearch(accrual, searchString) {
69
+ const trimmed = searchString.trim().toLowerCase();
70
+ if (trimmed.length === 0) {
71
+ return true;
72
+ }
73
+ return (accrual.vendorName.toLowerCase().includes(trimmed) ||
74
+ accrual.memo.toLowerCase().includes(trimmed));
75
+ }
76
+ function getActualMatchingSortValue(row, sortKey) {
77
+ switch (sortKey) {
78
+ case 'vendor':
79
+ return row.vendorName.toLowerCase();
80
+ case 'date':
81
+ return row.reversalDate?.valueOf();
82
+ case 'amount':
83
+ return getActualMatchingAmount(row);
84
+ case 'category':
85
+ return row.jeDebitAccountName?.toLowerCase();
86
+ case 'class':
87
+ return row.jeDebitAccountingClassName?.toLowerCase();
88
+ case 'type':
89
+ return (row.cleared?.matchedTransactionType ??
90
+ row.matchSuggestion?.matchedTransactionType)?.toLowerCase();
91
+ case 'lifecycle':
92
+ return row.kind;
93
+ default:
94
+ return undefined;
95
+ }
96
+ }
97
+ function sortActualMatchingRows(rows, uiState) {
98
+ const lodashOrder = uiState.sortOrder === 'ascending' ? 'asc' : 'desc';
99
+ return orderBy(rows, [(row) => getActualMatchingSortValue(row, uiState.sortKey)], [lodashOrder]);
100
+ }
101
+ function emptyKpiSummary() {
102
+ return {
103
+ autoReversed: { count: 0, amount: 0 },
104
+ pendingReview: { count: 0, amount: 0 },
105
+ totalThisClose: { count: 0, amount: 0 },
106
+ ai: { count: 0 },
107
+ manual: { count: 0 },
108
+ };
109
+ }
110
+ export function getExpenseAutomationActualMatchingView(state) {
111
+ const { expenseAutomationActualMatchingViewState, expenseAutomationViewState } = state;
112
+ const { accrualKeysByPeriod, fetchState, error, refreshStatus, uiState, matchModal, } = expenseAutomationActualMatchingViewState;
113
+ const currentTenant = getCurrentTenant(state);
114
+ const selectedPeriod = expenseAutomationViewState.selectedPeriodByTenantId[currentTenant.tenantId];
115
+ const monthYearPeriodId = selectedPeriod != null ? toMonthYearPeriodId(selectedPeriod) : undefined;
116
+ const accrualKeys = monthYearPeriodId != null
117
+ ? accrualKeysByPeriod[monthYearPeriodId]
118
+ : undefined;
119
+ const accruals = (accrualKeys ?? [])
120
+ .map((key) => getJEOneTimeAccrualByKey(key, state.jeSchedulesState))
121
+ .filter((accrual) => accrual != null);
122
+ const filtered = accruals.filter((accrual) => matchesSearch(accrual, uiState.searchString));
123
+ const autoReversed = sortActualMatchingRows(filtered
124
+ .filter(isAutoReversedAccrual)
125
+ .map((accrual) => toActualMatchingRow(accrual, 'auto_reversed')), uiState);
126
+ const pendingReview = sortActualMatchingRows(filtered
127
+ .filter(isPendingReviewAccrual)
128
+ .map((accrual) => toActualMatchingRow(accrual, 'pending_review')), uiState);
129
+ const manuallyReversed = sortActualMatchingRows(filtered
130
+ .filter(isManuallyReversedAccrual)
131
+ .map((accrual) => toActualMatchingRow(accrual, 'manually_reversed')), uiState);
132
+ const listedAccruals = accruals.filter((accrual) => isAutoReversedAccrual(accrual) ||
133
+ isPendingReviewAccrual(accrual) ||
134
+ isManuallyReversedAccrual(accrual));
135
+ const kpiSummary = listedAccruals.length === 0
136
+ ? emptyKpiSummary()
137
+ : {
138
+ autoReversed: {
139
+ count: listedAccruals.filter(isAutoReversedAccrual).length,
140
+ amount: listedAccruals
141
+ .filter(isAutoReversedAccrual)
142
+ .reduce((sum, accrual) => sum + getActualMatchingAmount(accrual), 0),
143
+ },
144
+ pendingReview: {
145
+ count: listedAccruals.filter(isPendingReviewAccrual).length,
146
+ amount: listedAccruals
147
+ .filter(isPendingReviewAccrual)
148
+ .reduce((sum, accrual) => sum + getActualMatchingAmount(accrual), 0),
149
+ },
150
+ totalThisClose: {
151
+ count: listedAccruals.length,
152
+ amount: listedAccruals.reduce((sum, accrual) => sum + getActualMatchingAmount(accrual), 0),
153
+ },
154
+ ai: {
155
+ count: listedAccruals.filter((accrual) => accrual.origin === 'agent').length,
156
+ },
157
+ manual: {
158
+ count: listedAccruals.filter((accrual) => accrual.origin === 'human').length,
159
+ },
160
+ };
161
+ const accrualSearchResults = matchModal.accrualSearch.results
162
+ .map((key) => getJEOneTimeAccrualByKey(key, state.jeSchedulesState))
163
+ .filter((accrual) => accrual != null);
164
+ return {
165
+ fetchState,
166
+ error,
167
+ autoReversed,
168
+ pendingReview,
169
+ manuallyReversed,
170
+ kpiSummary,
171
+ uiState,
172
+ refreshStatus,
173
+ hasLoadedForSelectedPeriod: accrualKeys != null,
174
+ matchModal: {
175
+ isOpen: matchModal.isOpen,
176
+ confirmStatus: matchModal.confirmStatus,
177
+ lastBatchResults: matchModal.lastBatchResults,
178
+ transactionSearch: {
179
+ query: matchModal.transactionSearch.query,
180
+ results: matchModal.transactionSearch.results,
181
+ fetchState: {
182
+ fetchState: matchModal.transactionSearch.fetchState,
183
+ error: matchModal.transactionSearch.error,
184
+ },
185
+ nextPageToken: matchModal.transactionSearch.nextPageToken,
186
+ isLoadingMore: matchModal.transactionSearch.isLoadingMore,
187
+ },
188
+ accrualSearch: {
189
+ query: matchModal.accrualSearch.query,
190
+ results: accrualSearchResults,
191
+ fetchState: {
192
+ fetchState: matchModal.accrualSearch.fetchState,
193
+ error: matchModal.accrualSearch.error,
194
+ },
195
+ nextPageToken: matchModal.accrualSearch.nextPageToken,
196
+ isLoadingMore: matchModal.accrualSearch.isLoadingMore,
197
+ },
198
+ },
199
+ };
200
+ }
@@ -367,6 +367,9 @@ export function getExpenseAutomationJESchedulesView(state) {
367
367
  // reports undefined rather than 0, so the UI can hide the badge instead of asserting "none".
368
368
  const scheduleCountsByTab = {};
369
369
  ALL_JE_PAGE_TABS.forEach((pageTab) => {
370
+ if (pageTab === 'actual_matching') {
371
+ return;
372
+ }
370
373
  const periodTabKey = monthYearPeriodId != null
371
374
  ? getJESchedulePeriodTabKey(pageTab, monthYearPeriodId)
372
375
  : null;
@@ -0,0 +1,22 @@
1
+ import { stringToUnion } from '../../../commonStateTypes/stringToUnion';
2
+ const ACTUAL_MATCHING_SORT_KEYS = [
3
+ 'vendor',
4
+ 'date',
5
+ 'amount',
6
+ 'category',
7
+ 'class',
8
+ 'type',
9
+ 'lifecycle',
10
+ ];
11
+ export const toActualMatchingSortKey = (v) => stringToUnion(v, ACTUAL_MATCHING_SORT_KEYS);
12
+ export const MATCH_TRANSACTION_SEARCH_PAGE_SIZE = 50;
13
+ export const MATCH_ACCRUAL_SEARCH_LIMIT = 50;
14
+ export const MATCH_SEARCH_DEBOUNCE_MS = 300;
15
+ const MATCH_AND_REVERSE_RESULT_STATUSES = [
16
+ 'reversed',
17
+ 'noop',
18
+ 'conflict',
19
+ 'claim_lost',
20
+ 'error',
21
+ ];
22
+ export const toMatchAndReverseResultStatus = (v) => stringToUnion(v, MATCH_AND_REVERSE_RESULT_STATUSES);
@@ -16,7 +16,11 @@ const JE_SCHEDULE_SORT_KEYS = [
16
16
  'memo',
17
17
  ];
18
18
  export const toJEScheduleSortKey = (v) => stringToUnion(v, JE_SCHEDULE_SORT_KEYS);
19
- const JE_PAGE_TABS = ['schedules', 'existing_schedules'];
19
+ const JE_PAGE_TABS = [
20
+ 'schedules',
21
+ 'actual_matching',
22
+ 'existing_schedules',
23
+ ];
20
24
  export const toJEPageTab = (v) => stringToUnion(v, JE_PAGE_TABS);
21
25
  export const ALL_JE_PAGE_TABS = JE_PAGE_TABS;
22
26
  export const getJESchedulePeriodTabKey = (selectedPageTab, monthYearPeriodId) => `${selectedPageTab}_${monthYearPeriodId}`;
@@ -34,7 +34,6 @@ export const initialState = {
34
34
  discountStatusOptions: [],
35
35
  dunningCaseStatusOptions: [],
36
36
  invoiceStatusOptions: [],
37
- subscriptionCancelReasonCodeOptions: [],
38
37
  subscriptionStatusOptions: [],
39
38
  transactionStatusOptions: [],
40
39
  transactionTypeOptions: [],
@@ -104,7 +103,6 @@ export function mapInvoicingConfigPayloadToState(payload) {
104
103
  discountStatusOptions: (payload.discount_status_options ?? []).map(toInvoicingNamedOption),
105
104
  dunningCaseStatusOptions: (payload.dunning_case_status_options ?? []).map(toInvoicingNamedOption),
106
105
  invoiceStatusOptions: (payload.invoice_status_options ?? []).map(toInvoicingNamedOption),
107
- subscriptionCancelReasonCodeOptions: (payload.subscription_cancel_reason_code_options ?? []).map(toInvoicingNamedOption),
108
106
  subscriptionStatusOptions: (payload.subscription_status_options ?? []).map(toInvoicingNamedOption),
109
107
  transactionStatusOptions: (payload.transaction_status_options ?? []).map(toInvoicingNamedOption),
110
108
  transactionTypeOptions: (payload.transaction_type_options ?? []).map(toInvoicingNamedOption),
@@ -37,6 +37,7 @@ export const mapInvoicingPlanRevenuePointPayloadToState = (payload) => ({
37
37
  mrr: toAmount(payload.mrr, 'USD', '$'),
38
38
  pct: payload.pct,
39
39
  planID: payload.plan,
40
+ productCode: payload.product_code,
40
41
  });
41
42
  export const mapInvoicingDashboardSummaryPayloadToState = (payload) => ({
42
43
  customerMovement: {
@@ -1,12 +1,11 @@
1
1
  import { getInvoicingSubscriptionById as getInvoicingSubscriptionByIdFromState } from '../../../entity/invoicing/invoicingSubscription/invoicingSubscriptionSelector';
2
- import { getInvoicingConfigView, invoicingFieldHelpForGroup, } from '../invoicingConfigView/invoicingConfigViewSelector';
2
+ import { invoicingFieldHelpForGroup } from '../invoicingConfigView/invoicingConfigViewSelector';
3
3
  import { getInvoicingSubscriptionActionState } from '../subscriptionAction/subscriptionActionSelector';
4
4
  export const getInvoicingSubscriptionById = (state, id) => getInvoicingSubscriptionByIdFromState(state.invoicingSubscriptionState, id);
5
5
  export const getInvoicingSubscriptionDetail = (state, invoicingSubscriptionID) => {
6
6
  const { error, fetchState } = state.invoicingSubscriptionDetailViewState;
7
7
  return {
8
8
  fieldHelp: invoicingFieldHelpForGroup(state, 'subscription'),
9
- cancelReasonCodeOptions: getInvoicingConfigView(state).subscriptionCancelReasonCodeOptions,
10
9
  actionState: getInvoicingSubscriptionActionState(invoicingSubscriptionID)(state),
11
10
  subscription: getInvoicingSubscriptionById(state, invoicingSubscriptionID),
12
11
  fetchState,
@@ -28,7 +28,6 @@ export const getInvoicingSubscriptionListView = createSelector((state) => state.
28
28
  count: listViewState.counts,
29
29
  countsFetchState: listViewState.countsFetchState,
30
30
  subscriptionCommercialEditAllowedFromStatuses: configState.subscriptionCommercialEditAllowedFromStatuses,
31
- cancelReasonCodeOptions: configState.subscriptionCancelReasonCodeOptions,
32
31
  subscriptionLifecycleActionOptions: configState.subscriptionLifecycleActionOptions,
33
32
  subscriptionMetadataEditAllowedFromStatuses: configState.subscriptionMetadataEditAllowedFromStatuses,
34
33
  statusOptions,
@@ -3,6 +3,7 @@ export const ALL_INVOICING_SUBSCRIPTION_SORT_KEYS = [
3
3
  'subscription',
4
4
  'customer',
5
5
  'plan',
6
+ 'product_code',
6
7
  'term_end',
7
8
  'next_billing',
8
9
  'auto_collect',
@@ -14,6 +15,7 @@ export const INVOICING_SUBSCRIPTION_COLUMNS = [
14
15
  { key: 'subscription', sortable: true },
15
16
  { key: 'customer', sortable: false },
16
17
  { key: 'plan', sortable: true },
18
+ { key: 'product_code', sortable: true },
17
19
  { key: 'term_end', sortable: true },
18
20
  { key: 'next_billing', sortable: true },
19
21
  { key: 'auto_collect', sortable: true },
@@ -2,13 +2,20 @@ import { from, of } from 'rxjs';
2
2
  import { catchError, filter, mergeMap, switchMap } from 'rxjs/operators';
3
3
  import { updateApprovalRules } from '../../../../../entity/approvalRule/approvalRuleReducer';
4
4
  import { getApprovalRulesByIds } from '../../../../../entity/approvalRule/approvalRuleSelector';
5
+ import { getIsAccountingClassesEnabled } from '../../../../../entity/tenant/tenantSelector';
5
6
  import { updateAllUsers } from '../../../../../entity/user/userReducer';
6
7
  import { createZeniAPIStatus, isSuccessResponse, } from '../../../../../responsePayload';
8
+ import { fetchClassList } from '../../../../classList/classListReducer';
7
9
  import { fetchBillPaySetupApproverView, fetchBillPaySetupApproverViewFailure, fetchBillPaySetupApproverViewSuccess, } from '../billPaySetupApproverViewReducer';
8
10
  export const fetchBillPaySetupApproverViewEpic = (actions$, state$, zeniAPI) => actions$.pipe(filter(fetchBillPaySetupApproverView.match), switchMap((action) => {
9
11
  const { cacheOverride, useV3 } = action.payload;
10
- const { billPaySetupApproverViewState, approvalRuleState } = state$.value;
12
+ const { billPaySetupApproverViewState, approvalRuleState, classListState } = state$.value;
13
+ const isAccountingClassesEnabled = getIsAccountingClassesEnabled(state$.value);
11
14
  const approvalRules = getApprovalRulesByIds(approvalRuleState, billPaySetupApproverViewState.approvalRuleIds);
15
+ const shouldFetchClassList = isAccountingClassesEnabled &&
16
+ (cacheOverride === true ||
17
+ (classListState.hasValidState() === false &&
18
+ classListState.fetchState !== 'In-Progress'));
12
19
  if (cacheOverride === true ||
13
20
  approvalRules.length !==
14
21
  billPaySetupApproverViewState.approvalRuleIds.length ||
@@ -28,6 +35,9 @@ export const fetchBillPaySetupApproverViewEpic = (actions$, state$, zeniAPI) =>
28
35
  updateApprovalRules(response.data.approval_rules),
29
36
  fetchBillPaySetupApproverViewSuccess(approvalRuleIds),
30
37
  ];
38
+ if (shouldFetchClassList) {
39
+ actions.push(fetchClassList());
40
+ }
31
41
  return from(actions);
32
42
  }
33
43
  else {
@@ -37,6 +47,12 @@ export const fetchBillPaySetupApproverViewEpic = (actions$, state$, zeniAPI) =>
37
47
  }
38
48
  else {
39
49
  const { approvalRuleIds } = billPaySetupApproverViewState;
40
- return of(fetchBillPaySetupApproverViewSuccess(approvalRuleIds));
50
+ const actions = [
51
+ fetchBillPaySetupApproverViewSuccess(approvalRuleIds),
52
+ ];
53
+ if (shouldFetchClassList) {
54
+ actions.push(fetchClassList());
55
+ }
56
+ return from(actions);
41
57
  }
42
58
  }));
@@ -21,7 +21,6 @@ export const initializeBillPaySetupApproverViewUpdateDataEpic = (actions$, state
21
21
  name: approvalRule.name,
22
22
  description: approvalRule.description,
23
23
  separationOfDuties: approvalRule.separationOfDuties,
24
- isFallback: approvalRule.isFallback,
25
24
  };
26
25
  fetchActions.push(clearBillPaySetupApproverViewUpdateData(), saveBillPaySetupApproverViewUpdateData(billPaySetupApproverViewUpdateData));
27
26
  }
@@ -86,9 +86,6 @@ export const toApprovalChangableInfoPayload = (approverViewUpdateData) => {
86
86
  payload.is_separation_of_duty_enabled =
87
87
  approverViewUpdateData.separationOfDuties;
88
88
  }
89
- if (approverViewUpdateData.isFallback != null) {
90
- payload.is_fallback = approverViewUpdateData.isFallback;
91
- }
92
89
  if (isUpdate) {
93
90
  payload.approval_rule_id = approverViewUpdateData.approvalRuleId;
94
91
  }