@zeniai/client-epic-state 5.2.14 → 5.2.16

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 (132) hide show
  1. package/lib/entity/accountRecon/accountReconReducer.d.ts +2 -1
  2. package/lib/entity/accountRecon/accountReconReducer.js +22 -10
  3. package/lib/entity/accountRecon/accountReconSelector.d.ts +1 -0
  4. package/lib/entity/accountRecon/accountReconSelector.js +1 -0
  5. package/lib/entity/approvalRule/approvalRuleConflict.d.ts +13 -0
  6. package/lib/entity/approvalRule/approvalRuleConflict.js +16 -1
  7. package/lib/entity/jeSchedules/jeScheduleHelper.d.ts +1 -0
  8. package/lib/entity/jeSchedules/jeScheduleHelper.js +7 -0
  9. package/lib/entity/jeSchedules/jeSchedulesPayload.d.ts +78 -1
  10. package/lib/entity/jeSchedules/jeSchedulesPayload.js +183 -4
  11. package/lib/entity/jeSchedules/jeSchedulesReducer.d.ts +4 -2
  12. package/lib/entity/jeSchedules/jeSchedulesReducer.js +30 -2
  13. package/lib/entity/jeSchedules/jeSchedulesSelector.d.ts +11 -2
  14. package/lib/entity/jeSchedules/jeSchedulesSelector.js +38 -3
  15. package/lib/entity/jeSchedules/jeSchedulesState.d.ts +123 -1
  16. package/lib/entity/jeSchedules/jeSchedulesTypes.d.ts +24 -1
  17. package/lib/entity/jeSchedules/jeSchedulesTypes.js +96 -1
  18. package/lib/entity/snackbar/snackbarTypes.d.ts +1 -1
  19. package/lib/entity/snackbar/snackbarTypes.js +3 -0
  20. package/lib/entity/transaction/payloadTypes/scheduleTransactionPayload.d.ts +2 -0
  21. package/lib/entity/transaction/payloadTypes/scheduleTransactionPayload.js +2 -0
  22. package/lib/entity/transaction/stateTypes/scheduleTransaction.d.ts +2 -0
  23. package/lib/epic.d.ts +10 -1
  24. package/lib/epic.js +18 -0
  25. package/lib/esm/entity/accountRecon/accountReconReducer.js +22 -10
  26. package/lib/esm/entity/accountRecon/accountReconSelector.js +1 -0
  27. package/lib/esm/entity/approvalRule/approvalRuleConflict.js +16 -1
  28. package/lib/esm/entity/jeSchedules/jeScheduleHelper.js +6 -0
  29. package/lib/esm/entity/jeSchedules/jeSchedulesPayload.js +183 -5
  30. package/lib/esm/entity/jeSchedules/jeSchedulesReducer.js +30 -2
  31. package/lib/esm/entity/jeSchedules/jeSchedulesSelector.js +36 -2
  32. package/lib/esm/entity/jeSchedules/jeSchedulesTypes.js +86 -0
  33. package/lib/esm/entity/snackbar/snackbarTypes.js +3 -0
  34. package/lib/esm/entity/transaction/payloadTypes/scheduleTransactionPayload.js +2 -0
  35. package/lib/esm/epic.js +18 -0
  36. package/lib/esm/index.js +16 -10
  37. package/lib/esm/view/expenseAutomationView/epics/accountRecon/confirmStatementMappingEpic.js +2 -2
  38. package/lib/esm/view/expenseAutomationView/epics/accountRecon/deleteCombinedStatementEpic.js +54 -0
  39. package/lib/esm/view/expenseAutomationView/epics/accountRecon/fetchReconciliationViewEpic.js +1 -1
  40. package/lib/esm/view/expenseAutomationView/epics/accountRecon/updateCombinedStatementInfoEpic.js +3 -6
  41. package/lib/esm/view/expenseAutomationView/epics/common/fetchAllExpenseAutomationTabsEpic.js +6 -3
  42. package/lib/esm/view/expenseAutomationView/epics/jeSchedule/fetchJeSchedulePageEpic.js +9 -1
  43. package/lib/esm/view/expenseAutomationView/epics/jeSchedule/fetchJeSchedulesEpic.js +41 -5
  44. package/lib/esm/view/expenseAutomationView/epics/jeSchedule/fetchOneTimeAccrualEpic.js +45 -0
  45. package/lib/esm/view/expenseAutomationView/epics/jeSchedule/ignoreRecommendedJeScheduleEpic.js +14 -2
  46. package/lib/esm/view/expenseAutomationView/epics/jeSchedule/newSchedule/createOneTimeAccrualEpic.js +104 -0
  47. package/lib/esm/view/expenseAutomationView/epics/jeSchedule/newSchedule/initializeNewScheduleEpic.js +25 -0
  48. package/lib/esm/view/expenseAutomationView/epics/jeSchedule/newSchedule/saveNewScheduleEpic.js +138 -0
  49. package/lib/esm/view/expenseAutomationView/epics/jeSchedule/newSchedule/searchTransactionsForNewScheduleEpic.js +79 -0
  50. package/lib/esm/view/expenseAutomationView/epics/jeSchedule/oneTimeAccrualActionsEpic.js +180 -0
  51. package/lib/esm/view/expenseAutomationView/epics/jeSchedule/revertJeScheduleEpic.js +111 -0
  52. package/lib/esm/view/expenseAutomationView/epics/jeSchedule/switchJESchedulesTabEpic.js +28 -0
  53. package/lib/esm/view/expenseAutomationView/helpers/newScheduleLocalDataHelper.js +140 -0
  54. package/lib/esm/view/expenseAutomationView/helpers/reconciliationHelpers.js +12 -0
  55. package/lib/esm/view/expenseAutomationView/payload/jeSchedulesPayload.js +55 -0
  56. package/lib/esm/view/expenseAutomationView/reducers/jeSchedulesViewReducer.js +319 -29
  57. package/lib/esm/view/expenseAutomationView/reducers/reconciliationViewReducer.js +20 -2
  58. package/lib/esm/view/expenseAutomationView/selectorTypes/jeNewScheduleViewSelectorTypes.js +1 -0
  59. package/lib/esm/view/expenseAutomationView/selectors/jeAccountSettingsViewSelector.js +1 -0
  60. package/lib/esm/view/expenseAutomationView/selectors/jeNewScheduleViewSelector.js +106 -0
  61. package/lib/esm/view/expenseAutomationView/selectors/jeSchedulesViewSelector.js +327 -22
  62. package/lib/esm/view/expenseAutomationView/types/jeSchedulesViewState.js +5 -6
  63. package/lib/esm/view/scheduleView/scheduleListView/epics/fetchAccruedScheduleListEpic.js +1 -1
  64. package/lib/esm/view/scheduleView/scheduleListView/epics/fetchDownloadSchedulesEpic.js +7 -2
  65. package/lib/esm/view/scheduleView/scheduleListView/scheduleListReducer.js +5 -3
  66. package/lib/esm/view/spendManagement/billPay/billPaySetupApproverView/billPaySetupApproverViewSelector.js +20 -1
  67. package/lib/esm/view/spendManagement/reimbursement/remiSetupApproverView/remiSetupApproverViewSelector.js +20 -1
  68. package/lib/index.d.ts +18 -13
  69. package/lib/index.js +92 -47
  70. package/lib/view/expenseAutomationView/epics/accountRecon/confirmStatementMappingEpic.d.ts +10 -2
  71. package/lib/view/expenseAutomationView/epics/accountRecon/confirmStatementMappingEpic.js +1 -1
  72. package/lib/view/expenseAutomationView/epics/accountRecon/deleteCombinedStatementEpic.d.ts +9 -0
  73. package/lib/view/expenseAutomationView/epics/accountRecon/deleteCombinedStatementEpic.js +58 -0
  74. package/lib/view/expenseAutomationView/epics/accountRecon/fetchReconciliationViewEpic.js +1 -1
  75. package/lib/view/expenseAutomationView/epics/accountRecon/updateCombinedStatementInfoEpic.js +3 -6
  76. package/lib/view/expenseAutomationView/epics/common/fetchAllExpenseAutomationTabsEpic.js +6 -3
  77. package/lib/view/expenseAutomationView/epics/jeSchedule/fetchJeSchedulePageEpic.js +9 -1
  78. package/lib/view/expenseAutomationView/epics/jeSchedule/fetchJeSchedulesEpic.d.ts +3 -2
  79. package/lib/view/expenseAutomationView/epics/jeSchedule/fetchJeSchedulesEpic.js +39 -3
  80. package/lib/view/expenseAutomationView/epics/jeSchedule/fetchOneTimeAccrualEpic.d.ts +21 -0
  81. package/lib/view/expenseAutomationView/epics/jeSchedule/fetchOneTimeAccrualEpic.js +49 -0
  82. package/lib/view/expenseAutomationView/epics/jeSchedule/ignoreRecommendedJeScheduleEpic.js +14 -2
  83. package/lib/view/expenseAutomationView/epics/jeSchedule/newSchedule/createOneTimeAccrualEpic.d.ts +9 -0
  84. package/lib/view/expenseAutomationView/epics/jeSchedule/newSchedule/createOneTimeAccrualEpic.js +108 -0
  85. package/lib/view/expenseAutomationView/epics/jeSchedule/newSchedule/initializeNewScheduleEpic.d.ts +8 -0
  86. package/lib/view/expenseAutomationView/epics/jeSchedule/newSchedule/initializeNewScheduleEpic.js +29 -0
  87. package/lib/view/expenseAutomationView/epics/jeSchedule/newSchedule/saveNewScheduleEpic.d.ts +9 -0
  88. package/lib/view/expenseAutomationView/epics/jeSchedule/newSchedule/saveNewScheduleEpic.js +142 -0
  89. package/lib/view/expenseAutomationView/epics/jeSchedule/newSchedule/searchTransactionsForNewScheduleEpic.d.ts +8 -0
  90. package/lib/view/expenseAutomationView/epics/jeSchedule/newSchedule/searchTransactionsForNewScheduleEpic.js +83 -0
  91. package/lib/view/expenseAutomationView/epics/jeSchedule/oneTimeAccrualActionsEpic.d.ts +13 -0
  92. package/lib/view/expenseAutomationView/epics/jeSchedule/oneTimeAccrualActionsEpic.js +187 -0
  93. package/lib/view/expenseAutomationView/epics/jeSchedule/revertJeScheduleEpic.d.ts +65 -0
  94. package/lib/view/expenseAutomationView/epics/jeSchedule/revertJeScheduleEpic.js +115 -0
  95. package/lib/view/expenseAutomationView/epics/jeSchedule/switchJESchedulesTabEpic.d.ts +6 -0
  96. package/lib/view/expenseAutomationView/epics/jeSchedule/switchJESchedulesTabEpic.js +32 -0
  97. package/lib/view/expenseAutomationView/helpers/newScheduleLocalDataHelper.d.ts +36 -0
  98. package/lib/view/expenseAutomationView/helpers/newScheduleLocalDataHelper.js +145 -0
  99. package/lib/view/expenseAutomationView/helpers/reconciliationHelpers.d.ts +6 -0
  100. package/lib/view/expenseAutomationView/helpers/reconciliationHelpers.js +13 -0
  101. package/lib/view/expenseAutomationView/helpers/transactionCategorizationLocalDataHelper.d.ts +1 -1
  102. package/lib/view/expenseAutomationView/payload/jeSchedulesPayload.d.ts +86 -3
  103. package/lib/view/expenseAutomationView/payload/jeSchedulesPayload.js +58 -1
  104. package/lib/view/expenseAutomationView/payload/reconciliationPayload.d.ts +4 -0
  105. package/lib/view/expenseAutomationView/reducers/jeSchedulesViewReducer.d.ts +93 -12
  106. package/lib/view/expenseAutomationView/reducers/jeSchedulesViewReducer.js +321 -29
  107. package/lib/view/expenseAutomationView/reducers/missingReceiptsViewReducer.d.ts +1 -1
  108. package/lib/view/expenseAutomationView/reducers/reconciliationViewReducer.d.ts +6 -1
  109. package/lib/view/expenseAutomationView/reducers/reconciliationViewReducer.js +22 -4
  110. package/lib/view/expenseAutomationView/reducers/transactionsViewReducer.d.ts +2 -2
  111. package/lib/view/expenseAutomationView/selectorTypes/jeAccountSettingsViewSelectorTypes.d.ts +1 -0
  112. package/lib/view/expenseAutomationView/selectorTypes/jeNewScheduleViewSelectorTypes.d.ts +42 -0
  113. package/lib/view/expenseAutomationView/selectorTypes/jeNewScheduleViewSelectorTypes.js +2 -0
  114. package/lib/view/expenseAutomationView/selectorTypes/jeSchedulesSelectorTypes.d.ts +41 -7
  115. package/lib/view/expenseAutomationView/selectors/jeAccountSettingsViewSelector.js +1 -0
  116. package/lib/view/expenseAutomationView/selectors/jeNewScheduleViewSelector.d.ts +21 -0
  117. package/lib/view/expenseAutomationView/selectors/jeNewScheduleViewSelector.js +112 -0
  118. package/lib/view/expenseAutomationView/selectors/jeSchedulesViewSelector.d.ts +34 -0
  119. package/lib/view/expenseAutomationView/selectors/jeSchedulesViewSelector.js +335 -21
  120. package/lib/view/expenseAutomationView/types/completedSubTab.d.ts +1 -1
  121. package/lib/view/expenseAutomationView/types/jeSchedulesViewState.d.ts +83 -8
  122. package/lib/view/expenseAutomationView/types/jeSchedulesViewState.js +8 -8
  123. package/lib/view/expenseAutomationView/types/reconciliationViewState.d.ts +1 -1
  124. package/lib/view/scheduleView/scheduleListView/epics/fetchAccruedScheduleListEpic.js +1 -1
  125. package/lib/view/scheduleView/scheduleListView/epics/fetchDownloadSchedulesEpic.js +7 -2
  126. package/lib/view/scheduleView/scheduleListView/scheduleListReducer.d.ts +4 -2
  127. package/lib/view/scheduleView/scheduleListView/scheduleListReducer.js +5 -3
  128. package/lib/view/spendManagement/billPay/billPaySetupApproverView/billPaySetupApproverViewSelector.js +20 -1
  129. package/lib/view/spendManagement/billPay/billPaySetupApproverView/billPaySetupApproverViewSelectorTypes.d.ts +3 -0
  130. package/lib/view/spendManagement/reimbursement/remiSetupApproverView/remiSetupApproverViewSelector.js +20 -1
  131. package/lib/view/spendManagement/reimbursement/remiSetupApproverView/remiSetupApproverViewSelectorTypes.d.ts +3 -0
  132. package/package.json +1 -1
@@ -2,9 +2,16 @@ import { createSlice } from '@reduxjs/toolkit';
2
2
  import { geNestedAccountIDHierarchyForReport } from '../../../commonStateTypes/accountView/getNestedAccountIDHierarchyForReport';
3
3
  import { toMonthYearPeriodId, } from '../../../commonStateTypes/timePeriod';
4
4
  import { mapAccountBasePayloadToAccountBase, mapAccountMetadataPayloadToAccountMetadata, } from '../../../entity/account/accountPayload';
5
- import { getJEScheduleTransactionDetailKeyPayload, } from '../../../entity/jeSchedules/jeSchedulesPayload';
5
+ import { generateJEOneTimeAccrualKey } from '../../../entity/jeSchedules/jeScheduleHelper';
6
+ import { getJEScheduleKey, getJEScheduleTransactionDetailKeyPayload, } from '../../../entity/jeSchedules/jeSchedulesPayload';
6
7
  import { clearAll } from '../../../rootActions';
7
8
  import { mapAccountTypeRecommendationPayloadToAccountRecommendationByType, } from '../../accountMappingView/accountTypeRecommendation/accountTypeRecommendationPayload';
9
+ import { MIN_NEW_SCHEDULE_SEARCH_LENGTH, getJESchedulePeriodTabKey, } from '../types/jeSchedulesViewState';
10
+ function removeKeyFromEveryTabSlot(keysByPeriodAndTab, keyToRemove) {
11
+ for (const periodTabKey of Object.keys(keysByPeriodAndTab)) {
12
+ keysByPeriodAndTab[periodTabKey] = keysByPeriodAndTab[periodTabKey].filter((jeScheduleKey) => jeScheduleKey !== keyToRemove);
13
+ }
14
+ }
8
15
  export const accountSettingsInitialState = {
9
16
  localData: {
10
17
  selectedPrepaidExpensesAccountIds: [],
@@ -18,6 +25,7 @@ export const accountSettingsInitialState = {
18
25
  error: undefined,
19
26
  fetchState: 'Not-Started',
20
27
  },
28
+ hasLoadedAccountSettings: false,
21
29
  recommendationFetchState: {
22
30
  error: undefined,
23
31
  fetchState: 'Not-Started',
@@ -36,16 +44,37 @@ export const accountSettingsInitialState = {
36
44
  accruedExpensesNestedAccountListHierarchy: [],
37
45
  accruedExpensesRecommendations: [],
38
46
  };
47
+ export const getBaseNewScheduleLocalData = (scheduleType) => ({
48
+ scheduleType,
49
+ jeScheduleDetails: [],
50
+ });
51
+ export const newScheduleInitialState = {
52
+ fixed_assets: getBaseNewScheduleLocalData('fixed_assets'),
53
+ prepaid_expenses: getBaseNewScheduleLocalData('prepaid_expenses'),
54
+ };
55
+ export const searchTransactionsInitialState = {
56
+ searchResults: [],
57
+ fetchState: 'Not-Started',
58
+ error: undefined,
59
+ };
39
60
  export const initialState = {
40
- jeScheduleTransactionKeysByPeriod: {},
41
- failedJeScheduleTransactionKeysByPeriod: {},
61
+ jeScheduleTransactionKeysByPeriodAndTab: {},
62
+ jeScheduleAccruedKeysByPeriodAndTab: {},
63
+ jeScheduleOneTimeAccrualKeysByPeriodAndTab: {},
64
+ failedJeScheduleTransactionKeysByPeriodAndTab: {},
42
65
  postStatusById: {},
43
66
  ignoreStatusById: {},
67
+ revertStatusById: {},
44
68
  jeScheduleLocalDataById: {},
69
+ oneTimeAccrualActionStatusById: {},
70
+ oneTimeAccrualFetchStatusById: {},
45
71
  uiState: {
46
- searchString: '',
72
+ createdGroupCollapsed: false,
73
+ pendingGroupCollapsed: false,
47
74
  scrollPosition: { scrollTop: 0, scrollLeft: undefined },
48
- selectedMainTab: 'pending_review',
75
+ searchString: '',
76
+ selectedJETypeFilter: null,
77
+ selectedPageTab: 'schedules',
49
78
  sortKey: 'transactionDate',
50
79
  sortOrder: 'descending',
51
80
  totalCount: 0,
@@ -56,6 +85,14 @@ export const initialState = {
56
85
  error: undefined,
57
86
  },
58
87
  accountSettings: accountSettingsInitialState,
88
+ newSchedule: {
89
+ createOneTimeAccrualStatus: { fetchState: 'Not-Started', error: undefined },
90
+ newScheduleState: newScheduleInitialState,
91
+ saveStatus: { fetchState: 'Not-Started', error: undefined },
92
+ searchTransactions: searchTransactionsInitialState,
93
+ fetchState: 'Not-Started',
94
+ error: undefined,
95
+ },
59
96
  fetchState: 'Not-Started',
60
97
  error: undefined,
61
98
  hasValidState() {
@@ -100,9 +137,12 @@ const expenseAutomationJESchedulesView = createSlice({
100
137
  },
101
138
  },
102
139
  fetchJeSchedulesSuccess(draft, action) {
103
- const { jeSchedules, selectedPeriod, failedJeSchedules, refreshViewInBackground, } = action.payload;
140
+ const { jeSchedules, selectedPeriod, selectedPageTab, failedJeSchedules, accruedJeSchedules, oneTimeAccruals, refreshViewInBackground, } = action.payload;
141
+ const periodTabKey = getJESchedulePeriodTabKey(selectedPageTab, toMonthYearPeriodId(selectedPeriod));
104
142
  const jeScheduleTransactionKeys = jeSchedules.map((schedules) => getJEScheduleTransactionDetailKeyPayload(schedules.base_transaction));
105
143
  const failedJeScheduleTransactionKeys = failedJeSchedules.map((schedules) => getJEScheduleTransactionDetailKeyPayload(schedules.base_transaction));
144
+ const jeScheduleAccruedKeys = accruedJeSchedules.map((schedule) => getJEScheduleKey(schedule));
145
+ const jeScheduleOneTimeAccrualKeys = oneTimeAccruals.map((accrual) => generateJEOneTimeAccrualKey(accrual._id));
106
146
  if (refreshViewInBackground === true &&
107
147
  draft.refreshStatus.fetchState === 'In-Progress') {
108
148
  draft.refreshStatus = { fetchState: 'Completed', error: undefined };
@@ -111,19 +151,31 @@ const expenseAutomationJESchedulesView = createSlice({
111
151
  draft.fetchState = 'Completed';
112
152
  draft.error = undefined;
113
153
  }
114
- draft.jeScheduleTransactionKeysByPeriod[toMonthYearPeriodId(selectedPeriod)] = jeScheduleTransactionKeys;
115
- draft.failedJeScheduleTransactionKeysByPeriod[toMonthYearPeriodId(selectedPeriod)] = failedJeScheduleTransactionKeys;
154
+ draft.jeScheduleTransactionKeysByPeriodAndTab[periodTabKey] =
155
+ jeScheduleTransactionKeys;
156
+ draft.jeScheduleAccruedKeysByPeriodAndTab[periodTabKey] =
157
+ jeScheduleAccruedKeys;
158
+ draft.jeScheduleOneTimeAccrualKeysByPeriodAndTab[periodTabKey] =
159
+ jeScheduleOneTimeAccrualKeys;
160
+ draft.failedJeScheduleTransactionKeysByPeriodAndTab[periodTabKey] =
161
+ failedJeScheduleTransactionKeys;
116
162
  },
117
163
  fetchJeSchedulesFailure(draft, action) {
118
- const { status, selectedPeriod } = action.payload;
164
+ const { status, selectedPeriod, selectedPageTab } = action.payload;
165
+ const periodTabKey = getJESchedulePeriodTabKey(selectedPageTab, toMonthYearPeriodId(selectedPeriod));
119
166
  if (draft.refreshStatus.fetchState === 'In-Progress') {
120
167
  draft.refreshStatus = { fetchState: 'Error', error: status };
121
168
  }
122
169
  else {
123
170
  draft.fetchState = 'Error';
124
171
  draft.error = status;
172
+ draft.jeScheduleTransactionKeysByPeriodAndTab[periodTabKey] = [];
173
+ draft.jeScheduleAccruedKeysByPeriodAndTab[periodTabKey] = [];
174
+ draft.jeScheduleOneTimeAccrualKeysByPeriodAndTab[periodTabKey] = [];
175
+ // Cleared with the rest: leaving it behind kept the previous fetch's resolve rows on an
176
+ // otherwise empty errored tab, which reads as "these are all the schedules there are".
177
+ draft.failedJeScheduleTransactionKeysByPeriodAndTab[periodTabKey] = [];
125
178
  }
126
- draft.jeScheduleTransactionKeysByPeriod[toMonthYearPeriodId(selectedPeriod)] = [];
127
179
  },
128
180
  retryJeSchedule(draft, action) {
129
181
  const { scheduledJournalEntryID } = action.payload;
@@ -159,11 +211,13 @@ const expenseAutomationJESchedulesView = createSlice({
159
211
  };
160
212
  },
161
213
  ignoreRecommendedJeSchedule: {
162
- prepare(jeScheduleTransactionKey, scheduleType) {
214
+ prepare(jeScheduleTransactionKey, scheduleType, reason, note) {
163
215
  return {
164
216
  payload: {
165
217
  jeScheduleTransactionKey,
166
218
  scheduleType,
219
+ reason,
220
+ note,
167
221
  },
168
222
  };
169
223
  },
@@ -179,6 +233,41 @@ const expenseAutomationJESchedulesView = createSlice({
179
233
  };
180
234
  },
181
235
  },
236
+ revertJeSchedule: {
237
+ // jeScheduleTransactionKey is a JEScheduleKey for an accrued schedule, which has no base
238
+ // transaction to derive a transaction key from. It is only ever used as an opaque row
239
+ // identifier here -- for the row's spinner and for dropping the row from the list -- so one
240
+ // action serves both shapes rather than two near-identical ones.
241
+ prepare(jeScheduleId, jeScheduleTransactionKey, scheduleType, reason, note) {
242
+ return {
243
+ payload: {
244
+ jeScheduleId,
245
+ jeScheduleTransactionKey,
246
+ scheduleType,
247
+ reason,
248
+ note,
249
+ },
250
+ };
251
+ },
252
+ reducer(draft, action) {
253
+ draft.revertStatusById[action.payload.jeScheduleTransactionKey] = {
254
+ fetchState: 'In-Progress',
255
+ error: undefined,
256
+ };
257
+ },
258
+ },
259
+ revertJeScheduleSuccess(draft, action) {
260
+ draft.revertStatusById[action.payload.jeScheduleTransactionKey] = {
261
+ fetchState: 'Completed',
262
+ error: undefined,
263
+ };
264
+ },
265
+ revertJeScheduleFailure(draft, action) {
266
+ draft.revertStatusById[action.payload.jeScheduleTransactionKey] = {
267
+ fetchState: 'Error',
268
+ error: action.payload.status,
269
+ };
270
+ },
182
271
  ignoreRecommendedJeScheduleSuccess: {
183
272
  reducer(draft, action) {
184
273
  const { jeScheduleTransactionKey } = action.payload;
@@ -211,17 +300,18 @@ const expenseAutomationJESchedulesView = createSlice({
211
300
  };
212
301
  },
213
302
  updateJeScheduleTransactionKeys: {
214
- prepare(jeScheduleKeys, selectedPeriod) {
303
+ prepare(jeScheduleKeys, selectedPeriod, selectedPageTab) {
215
304
  return {
216
305
  payload: {
217
306
  jeScheduleKeys: jeScheduleKeys,
218
307
  selectedPeriod: selectedPeriod,
308
+ selectedPageTab: selectedPageTab,
219
309
  },
220
310
  };
221
311
  },
222
312
  reducer(draft, action) {
223
- const { selectedPeriod, jeScheduleKeys } = action.payload;
224
- draft.jeScheduleTransactionKeysByPeriod[toMonthYearPeriodId(selectedPeriod)] = jeScheduleKeys;
313
+ const { selectedPeriod, selectedPageTab, jeScheduleKeys } = action.payload;
314
+ draft.jeScheduleTransactionKeysByPeriodAndTab[getJESchedulePeriodTabKey(selectedPageTab, toMonthYearPeriodId(selectedPeriod))] = jeScheduleKeys;
225
315
  },
226
316
  },
227
317
  removeJeScheduleTransactionKey: {
@@ -234,12 +324,20 @@ const expenseAutomationJESchedulesView = createSlice({
234
324
  };
235
325
  },
236
326
  reducer(draft, action) {
237
- const { selectedPeriod, jeScheduleKey } = action.payload;
238
- const prevData = [
239
- ...(draft.jeScheduleTransactionKeysByPeriod[toMonthYearPeriodId(selectedPeriod)] ?? []),
240
- ];
241
- const filteredKeys = prevData.filter((jeKey) => jeKey !== jeScheduleKey);
242
- draft.jeScheduleTransactionKeysByPeriod[toMonthYearPeriodId(selectedPeriod)] = filteredKeys;
327
+ const { jeScheduleKey } = action.payload;
328
+ // Dropped from every tab's slot, not just the visible one: once a schedule is ignored or
329
+ // resolved it must not reappear when the user switches tabs and hits a cached list.
330
+ removeKeyFromEveryTabSlot(draft.jeScheduleTransactionKeysByPeriodAndTab, jeScheduleKey);
331
+ },
332
+ },
333
+ removeJeAccruedScheduleKey: {
334
+ prepare(jeAccruedScheduleKey) {
335
+ return { payload: { jeAccruedScheduleKey } };
336
+ },
337
+ reducer(draft, action) {
338
+ // Accrued keys live in their own per-tab map, so removeJeScheduleTransactionKey cannot drop
339
+ // them -- a reverted accrued schedule stayed on the list until the next fetch.
340
+ removeKeyFromEveryTabSlot(draft.jeScheduleAccruedKeysByPeriodAndTab, action.payload.jeAccruedScheduleKey);
243
341
  },
244
342
  },
245
343
  removeFailedJeScheduleTransactionKey: {
@@ -252,12 +350,8 @@ const expenseAutomationJESchedulesView = createSlice({
252
350
  };
253
351
  },
254
352
  reducer(draft, action) {
255
- const { selectedPeriod, failedJeScheduleKey } = action.payload;
256
- const prevData = [
257
- ...(draft.failedJeScheduleTransactionKeysByPeriod[toMonthYearPeriodId(selectedPeriod)] ?? []),
258
- ];
259
- const filteredKeys = prevData.filter((jeKey) => jeKey !== failedJeScheduleKey);
260
- draft.failedJeScheduleTransactionKeysByPeriod[toMonthYearPeriodId(selectedPeriod)] = filteredKeys;
353
+ const { failedJeScheduleKey } = action.payload;
354
+ removeKeyFromEveryTabSlot(draft.failedJeScheduleTransactionKeysByPeriodAndTab, failedJeScheduleKey);
261
355
  },
262
356
  },
263
357
  initializeJeScheduleLocalData: {
@@ -336,6 +430,9 @@ const expenseAutomationJESchedulesView = createSlice({
336
430
  error: status,
337
431
  fetchState: 'Error',
338
432
  };
433
+ // Set on failure too: a tenant whose account list errors must still reach the page rather
434
+ // than sit under a skeleton forever.
435
+ draft.accountSettings.hasLoadedAccountSettings = true;
339
436
  },
340
437
  updateAccountSettingsListForAccountTypes(draft, action) {
341
438
  doUpdateAccountSettingsListForAccountTypes(draft.accountSettings, action.payload.accountPayload);
@@ -369,6 +466,187 @@ const expenseAutomationJESchedulesView = createSlice({
369
466
  clearJeAccountSettingsLocalData(draft) {
370
467
  draft.accountSettings.localData = accountSettingsInitialState.localData;
371
468
  },
469
+ initializeNewSchedule: {
470
+ prepare({ scheduleType, shouldResetEnteredData = true, }) {
471
+ return { payload: { scheduleType, shouldResetEnteredData } };
472
+ },
473
+ reducer() {
474
+ // Purely an epic-trigger action — the epic fans out the account/class
475
+ // list fetches, and clears entered data only when asked to.
476
+ },
477
+ },
478
+ resetNewScheduleLocalData: {
479
+ prepare({ scheduleType, }) {
480
+ return { payload: { scheduleType } };
481
+ },
482
+ reducer(draft, action) {
483
+ const { scheduleType } = action.payload;
484
+ draft.newSchedule.newScheduleState[scheduleType] =
485
+ getBaseNewScheduleLocalData(scheduleType);
486
+ },
487
+ },
488
+ updateNewScheduleLocalData(draft, action) {
489
+ const { scheduleType, localData } = action.payload;
490
+ draft.newSchedule.newScheduleState[scheduleType] = {
491
+ ...draft.newSchedule.newScheduleState[scheduleType],
492
+ ...localData,
493
+ };
494
+ },
495
+ searchTransactionsForNewSchedule: {
496
+ prepare({ query, scheduleType, }) {
497
+ return { payload: { query, scheduleType } };
498
+ },
499
+ reducer(draft, action) {
500
+ const trimmed = action.payload.query.trim();
501
+ // Cleared or too-short query: no API (see epic) — reset immediately.
502
+ if (trimmed.length < MIN_NEW_SCHEDULE_SEARCH_LENGTH) {
503
+ draft.newSchedule.searchTransactions = searchTransactionsInitialState;
504
+ return;
505
+ }
506
+ draft.newSchedule.searchTransactions = {
507
+ ...draft.newSchedule.searchTransactions,
508
+ searchString: action.payload.query,
509
+ fetchState: 'In-Progress',
510
+ };
511
+ },
512
+ },
513
+ searchTransactionsForNewScheduleSuccess(draft, action) {
514
+ draft.newSchedule.searchTransactions = {
515
+ ...draft.newSchedule.searchTransactions,
516
+ searchResults: action.payload.searchResults,
517
+ fetchState: 'Completed',
518
+ error: undefined,
519
+ };
520
+ },
521
+ searchTransactionsForNewScheduleFailure(draft, action) {
522
+ draft.newSchedule.searchTransactions = {
523
+ ...draft.newSchedule.searchTransactions,
524
+ fetchState: 'Error',
525
+ error: action.payload.status,
526
+ };
527
+ },
528
+ clearSearchTransactionsForNewSchedule(draft) {
529
+ draft.newSchedule.searchTransactions = searchTransactionsInitialState;
530
+ },
531
+ saveNewSchedule: {
532
+ prepare({ scheduleType, }) {
533
+ return { payload: { scheduleType } };
534
+ },
535
+ reducer(draft) {
536
+ draft.newSchedule.saveStatus = {
537
+ fetchState: 'In-Progress',
538
+ error: undefined,
539
+ };
540
+ },
541
+ },
542
+ saveNewScheduleSuccess(draft) {
543
+ draft.newSchedule.saveStatus = {
544
+ fetchState: 'Completed',
545
+ error: undefined,
546
+ };
547
+ },
548
+ saveNewScheduleFailure(draft, action) {
549
+ draft.newSchedule.saveStatus = {
550
+ fetchState: 'Error',
551
+ error: action.payload.status,
552
+ };
553
+ },
554
+ createOneTimeAccrual: {
555
+ prepare(localData) {
556
+ return { payload: { localData } };
557
+ },
558
+ reducer(draft) {
559
+ draft.newSchedule.createOneTimeAccrualStatus = {
560
+ fetchState: 'In-Progress',
561
+ error: undefined,
562
+ };
563
+ },
564
+ },
565
+ createOneTimeAccrualSuccess(draft) {
566
+ draft.newSchedule.createOneTimeAccrualStatus = {
567
+ fetchState: 'Completed',
568
+ error: undefined,
569
+ };
570
+ },
571
+ createOneTimeAccrualFailure(draft, action) {
572
+ draft.newSchedule.createOneTimeAccrualStatus = {
573
+ fetchState: 'Error',
574
+ error: action.payload.status,
575
+ };
576
+ },
577
+ /**
578
+ * Promote applies the body and posts in one step, so it carries whatever the user edited on the
579
+ * detail page. `edits` is absent when nothing was changed -- the epic then falls back to the
580
+ * stored accrual, which is what the list's inline Post does.
581
+ */
582
+ promoteOneTimeAccrual: {
583
+ prepare(accrualId, amount, edits) {
584
+ return { payload: { accrualId, amount, edits } };
585
+ },
586
+ reducer(draft, action) {
587
+ draft.oneTimeAccrualActionStatusById[action.payload.accrualId] = {
588
+ fetchState: 'In-Progress',
589
+ error: undefined,
590
+ };
591
+ },
592
+ },
593
+ revertOneTimeAccrual: {
594
+ prepare(accrualId, reason, note) {
595
+ return { payload: { accrualId, reason, note } };
596
+ },
597
+ reducer(draft, action) {
598
+ draft.oneTimeAccrualActionStatusById[action.payload.accrualId] = {
599
+ fetchState: 'In-Progress',
600
+ error: undefined,
601
+ };
602
+ },
603
+ },
604
+ ignoreOneTimeAccrual: {
605
+ prepare(accrualId, reason, note) {
606
+ return { payload: { accrualId, reason, note } };
607
+ },
608
+ reducer(draft, action) {
609
+ draft.oneTimeAccrualActionStatusById[action.payload.accrualId] = {
610
+ fetchState: 'In-Progress',
611
+ error: undefined,
612
+ };
613
+ },
614
+ },
615
+ fetchOneTimeAccrual: {
616
+ prepare(accrualId) {
617
+ return { payload: { accrualId } };
618
+ },
619
+ reducer(draft, action) {
620
+ draft.oneTimeAccrualFetchStatusById[action.payload.accrualId] = {
621
+ fetchState: 'In-Progress',
622
+ error: undefined,
623
+ };
624
+ },
625
+ },
626
+ fetchOneTimeAccrualSuccess(draft, action) {
627
+ draft.oneTimeAccrualFetchStatusById[action.payload.accrualId] = {
628
+ fetchState: 'Completed',
629
+ error: undefined,
630
+ };
631
+ },
632
+ fetchOneTimeAccrualFailure(draft, action) {
633
+ draft.oneTimeAccrualFetchStatusById[action.payload.accrualId] = {
634
+ fetchState: 'Error',
635
+ error: action.payload.status,
636
+ };
637
+ },
638
+ oneTimeAccrualActionSuccess(draft, action) {
639
+ draft.oneTimeAccrualActionStatusById[action.payload.accrualId] = {
640
+ fetchState: 'Completed',
641
+ error: undefined,
642
+ };
643
+ },
644
+ oneTimeAccrualActionFailure(draft, action) {
645
+ draft.oneTimeAccrualActionStatusById[action.payload.accrualId] = {
646
+ fetchState: 'Error',
647
+ error: action.payload.status,
648
+ };
649
+ },
372
650
  updateJESchedulesUIState(draft, action) {
373
651
  if (action.payload.sortKey != null) {
374
652
  draft.uiState.sortKey = action.payload.sortKey;
@@ -382,10 +660,21 @@ const expenseAutomationJESchedulesView = createSlice({
382
660
  if (action.payload.scrollPosition != null) {
383
661
  draft.uiState.scrollPosition = action.payload.scrollPosition;
384
662
  }
385
- if (action.payload.selectedMainTab != null) {
386
- draft.uiState.selectedMainTab = action.payload.selectedMainTab;
663
+ if (action.payload.selectedPageTab != null) {
664
+ draft.uiState.selectedPageTab = action.payload.selectedPageTab;
387
665
  }
388
666
  },
667
+ updateJEScheduleTypeFilter(draft, action) {
668
+ draft.uiState.selectedJETypeFilter = action.payload;
669
+ },
670
+ toggleJEPendingGroupCollapsed(draft) {
671
+ draft.uiState.pendingGroupCollapsed =
672
+ !draft.uiState.pendingGroupCollapsed;
673
+ },
674
+ toggleJECreatedGroupCollapsed(draft) {
675
+ draft.uiState.createdGroupCollapsed =
676
+ !draft.uiState.createdGroupCollapsed;
677
+ },
389
678
  clearExpenseAutomationJESchedulesView(draft) {
390
679
  Object.assign(draft, initialState);
391
680
  },
@@ -396,7 +685,7 @@ const expenseAutomationJESchedulesView = createSlice({
396
685
  });
397
686
  },
398
687
  });
399
- export const { clearExpenseAutomationJESchedulesView, clearJeAccountSettingsLocalData, clearJeScheduleLocalData, fetchAccountSettingsListForAccountTypes, fetchJeSchedules, fetchJeSchedulesFailure, fetchJeSchedulesPage, fetchJeSchedulesSuccess, fetchRecommendationForAccountSettings, ignoreRecommendedJeSchedule, ignoreRecommendedJeScheduleFailure, ignoreRecommendedJeScheduleSuccess, initializeAccountSettingsView, initializeJeScheduleLocalData, removeFailedJeScheduleTransactionKey, removeJeScheduleLocalDataById, removeJeScheduleTransactionKey, retryJeSchedule, retryJeScheduleFailure, retryJeScheduleSuccess, saveAccountSettings, saveAccountSettingsFailure, saveAccountSettingsLocalData, saveAccountSettingsSuccess, updateAccountSettingsListForAccountTypes, updateAccountSettingsListForAccountTypesFailure, updateJESchedulesUIState, updateJeScheduleLocalDataById, updateJeScheduleTransactionKeys, updateRecommendationForAccountSettings, updateRecommendationForAccountSettingsFailure, } = expenseAutomationJESchedulesView.actions;
688
+ export const { clearExpenseAutomationJESchedulesView, clearJeAccountSettingsLocalData, clearJeScheduleLocalData, clearSearchTransactionsForNewSchedule, createOneTimeAccrual, createOneTimeAccrualFailure, createOneTimeAccrualSuccess, ignoreOneTimeAccrual, oneTimeAccrualActionFailure, oneTimeAccrualActionSuccess, promoteOneTimeAccrual, revertJeSchedule, revertJeScheduleFailure, revertJeScheduleSuccess, revertOneTimeAccrual, fetchAccountSettingsListForAccountTypes, fetchJeSchedules, fetchJeSchedulesFailure, fetchJeSchedulesPage, fetchJeSchedulesSuccess, fetchOneTimeAccrual, fetchOneTimeAccrualFailure, fetchOneTimeAccrualSuccess, fetchRecommendationForAccountSettings, ignoreRecommendedJeSchedule, ignoreRecommendedJeScheduleFailure, ignoreRecommendedJeScheduleSuccess, initializeAccountSettingsView, initializeJeScheduleLocalData, initializeNewSchedule, removeFailedJeScheduleTransactionKey, removeJeScheduleLocalDataById, removeJeAccruedScheduleKey, removeJeScheduleTransactionKey, resetNewScheduleLocalData, retryJeSchedule, retryJeScheduleFailure, retryJeScheduleSuccess, saveAccountSettings, saveAccountSettingsFailure, saveAccountSettingsLocalData, saveAccountSettingsSuccess, saveNewSchedule, saveNewScheduleFailure, saveNewScheduleSuccess, searchTransactionsForNewSchedule, searchTransactionsForNewScheduleFailure, searchTransactionsForNewScheduleSuccess, toggleJECreatedGroupCollapsed, toggleJEPendingGroupCollapsed, updateAccountSettingsListForAccountTypes, updateAccountSettingsListForAccountTypesFailure, updateJESchedulesUIState, updateJEScheduleTypeFilter, updateJeScheduleLocalDataById, updateJeScheduleTransactionKeys, updateNewScheduleLocalData, updateRecommendationForAccountSettings, updateRecommendationForAccountSettingsFailure, } = expenseAutomationJESchedulesView.actions;
400
689
  export default expenseAutomationJESchedulesView.reducer;
401
690
  const doUpdateRecommendationForAccountSettings = (draft, payload) => {
402
691
  const { prepaidExpensesRecommendations, fixedAssetsRecommendations, accruedExpensesRecommendations, } = mapAccountTypeRecommendationPayloadToAccountRecommendationByType(payload);
@@ -464,4 +753,5 @@ const doUpdateAccountSettingsListForAccountTypes = (draft, accountPayloadList) =
464
753
  error: undefined,
465
754
  fetchState: 'Completed',
466
755
  };
756
+ draft.hasLoadedAccountSettings = true;
467
757
  };
@@ -502,6 +502,18 @@ const expenseAutomationReconciliationView = createSlice({
502
502
  // Drop sticky parse latch on discard so the drawer shows empty upload UI.
503
503
  accountRecon.statementParseInProgress = false;
504
504
  },
505
+ deleteCombinedStatement: (draft, action) => {
506
+ const { accountId, selectedPeriod } = action.payload;
507
+ const accountRecon = draft.accountReconciliationRecordsBySelectedPeriod[toMonthYearPeriodId(selectedPeriod)]?.reconciliationByAccountID[accountId];
508
+ if (accountRecon == null) {
509
+ return;
510
+ }
511
+ accountRecon.statementDeleteStatus = {
512
+ fetchState: 'In-Progress',
513
+ error: undefined,
514
+ };
515
+ accountRecon.statementParseInProgress = false;
516
+ },
505
517
  deleteAccountStatementSuccess: (draft, action) => {
506
518
  const { accountId, selectedPeriod } = action.payload;
507
519
  const accountRecon = draft.accountReconciliationRecordsBySelectedPeriod[toMonthYearPeriodId(selectedPeriod)]?.reconciliationByAccountID[accountId];
@@ -912,7 +924,7 @@ const expenseAutomationReconciliationView = createSlice({
912
924
  },
913
925
  });
914
926
  // Export actions
915
- export const { fetchReconciliation, fetchReconciliationFailure, fetchReconciliationSuccess, saveReconciliationDetail, saveReconciliationDetailFailure, updateSelectedAccountId, setConnectionInProgressForAccount, setStatementParseInProgress, setStatementProcessingDismissedToBackground, updateStatementProcessingBackgroundCompletedSteps, updateReconcileTabLocalData, updateReconcileTabListSortState, updateReconcileTabListScrollState, saveReconciliationDetailSuccess, updateSelectedTab, updateBalancesLocalData, initialiseLocalDataForSelectedAccountId, clearExpenseAutomationReconciliationView, updateSelectedDrawerAccountId, updateStatementProcessingFailed, updateReviewTabSortState, initializeReconciliationReviewTabLocalData, updateReviewTabLocalData, saveReconciliationReview, updateSaveReconciliationReviewFetchStatus, updateReconListScrollPosition, updateAccountReconciliationLocalData, deleteAccountStatement, deleteAccountStatementSuccess, deleteAccountStatementFailure, excludeAccountFromReconciliation, excludeAccountFromReconciliationSuccess, excludeAccountFromReconciliationFailure, includeAccountInReconciliation, includeAccountInReconciliationSuccess, includeAccountInReconciliationFailure, uploadAccountStatement, uploadAccountStatementSuccess, uploadAccountStatementFailure, parseStatement, parseCombinedStatement, parseStatementSuccess, parseStatementFailure, reparseStatement, reparseStatementSuccess, reparseStatementFailure, resetReparseStatementStatus, updateParsedStatementData, updateStatementUpdateLocalData, submitStatementUpdate, submitCombinedStatementUpdate, submitStatementUpdateSuccess, submitStatementUpdateFailure, clearStatementDateConflict, confirmStatementMapping, confirmStatementMappingSuccess, confirmStatementMappingFailure, updateStatementUploadChosen, updateNodeCollapseState, } = expenseAutomationReconciliationView.actions;
927
+ export const { fetchReconciliation, fetchReconciliationFailure, fetchReconciliationSuccess, saveReconciliationDetail, saveReconciliationDetailFailure, updateSelectedAccountId, setConnectionInProgressForAccount, setStatementParseInProgress, setStatementProcessingDismissedToBackground, updateStatementProcessingBackgroundCompletedSteps, updateReconcileTabLocalData, updateReconcileTabListSortState, updateReconcileTabListScrollState, saveReconciliationDetailSuccess, updateSelectedTab, updateBalancesLocalData, initialiseLocalDataForSelectedAccountId, clearExpenseAutomationReconciliationView, updateSelectedDrawerAccountId, updateStatementProcessingFailed, updateReviewTabSortState, initializeReconciliationReviewTabLocalData, updateReviewTabLocalData, saveReconciliationReview, updateSaveReconciliationReviewFetchStatus, updateReconListScrollPosition, updateAccountReconciliationLocalData, deleteAccountStatement, deleteCombinedStatement, deleteAccountStatementSuccess, deleteAccountStatementFailure, excludeAccountFromReconciliation, excludeAccountFromReconciliationSuccess, excludeAccountFromReconciliationFailure, includeAccountInReconciliation, includeAccountInReconciliationSuccess, includeAccountInReconciliationFailure, uploadAccountStatement, uploadAccountStatementSuccess, uploadAccountStatementFailure, parseStatement, parseCombinedStatement, parseStatementSuccess, parseStatementFailure, reparseStatement, reparseStatementSuccess, reparseStatementFailure, resetReparseStatementStatus, updateParsedStatementData, updateStatementUpdateLocalData, submitStatementUpdate, submitCombinedStatementUpdate, submitStatementUpdateSuccess, submitStatementUpdateFailure, clearStatementDateConflict, confirmStatementMapping, confirmStatementMappingSuccess, confirmStatementMappingFailure, updateStatementUploadChosen, updateNodeCollapseState, } = expenseAutomationReconciliationView.actions;
916
928
  // Export reducer
917
929
  export default expenseAutomationReconciliationView.reducer;
918
930
  function isEntityStatementParsing(reconciliation) {
@@ -1039,7 +1051,13 @@ function updateAllReconciliation(draft, accounts, selectedPeriod, reconciliation
1039
1051
  accountReconciliationRecords.reconciliationByAccountID[reconciliation.account_id] = {
1040
1052
  accountId: reconciliation.account_id,
1041
1053
  reconciliationId: reconciliation.reconciliation_id ?? undefined,
1042
- transactionFetchState: { fetchState: 'Not-Started', error: undefined },
1054
+ // Full list fetch does not load transactions; keep per-account detail
1055
+ // fetch status so an in-flight/completed review load is not reset to
1056
+ // Not-Started (review UI treats that as loading).
1057
+ transactionFetchState: oldRecord?.transactionFetchState ?? {
1058
+ fetchState: 'Not-Started',
1059
+ error: undefined,
1060
+ },
1043
1061
  refreshStatus: { fetchState: 'Not-Started', error: undefined },
1044
1062
  statementDeleteStatus: { fetchState: 'Not-Started', error: undefined },
1045
1063
  statementUploadStatus: preserveStatementUploadStatusAfterFetch(oldRecord),
@@ -22,6 +22,7 @@ export const getJEAccountSettingsView = createSelector((state) => state.expenseA
22
22
  fixedAssetsAccountHierarchy: jeAccountMappingState.fixedAssetsNestedAccountListHierarchy,
23
23
  accruedExpensesAccountHierarchy: jeAccountMappingState.accruedExpensesNestedAccountListHierarchy,
24
24
  fetchState: fetchState.fetchState,
25
+ hasLoaded: jeAccountMappingState.hasLoadedAccountSettings,
25
26
  saveState,
26
27
  };
27
28
  });
@@ -0,0 +1,106 @@
1
+ import { getAccountIdsForLabels, getAccountIdsForTypes, } from '../../../entity/account/accountSelector';
2
+ import { getScheduleTransactionById } from '../../../entity/transaction/transactionSelector';
3
+ import { getAccountIdsForLabel, getAccountList, getNestedAccountListHierarchy, } from '../../accountList/accountListSelector';
4
+ import { getClassList, getNestedClassListHierarchy, } from '../../classList/classListSelector';
5
+ import { getAccountsTypesForScheduleDetails } from '../../scheduleView/scheduleDetailView/scheduleDetailLocalDataHelper';
6
+ import { filterNestedAccountHierarchyById } from '../../scheduleView/scheduleDetailView/scheduleDetailSelector';
7
+ import { getAccountLabelForScheduleType, getAccountsTypesForScheduleEpics, } from '../../scheduleView/scheduleListView/scheduleListHelper';
8
+ /**
9
+ * The Base Transaction search is shared across schedule types (one search
10
+ * box, not one per prepaid_expenses/fixed_assets) — split out from
11
+ * getNewScheduleView so a consumer can read it without supplying an
12
+ * otherwise-irrelevant scheduleType.
13
+ */
14
+ export const getNewScheduleSearchTransactionsView = (state) => {
15
+ const { searchTransactions } = state.expenseAutomationJESchedulesViewState.newSchedule;
16
+ const searchTransactionsResults = searchTransactions.searchResults
17
+ .map((key) => getScheduleTransactionById(state.transactionState, key))
18
+ .filter((transaction) => transaction != null);
19
+ return {
20
+ searchTransactionsResults,
21
+ searchTransactionsFetchState: {
22
+ fetchState: searchTransactions.fetchState,
23
+ error: searchTransactions.error,
24
+ },
25
+ searchTransactionsString: searchTransactions.searchString,
26
+ };
27
+ };
28
+ const ACCRUED_EXPENSE_ACCOUNT_LABELS = ['accrued_expenses'];
29
+ /**
30
+ * Account + class options and request status shared by both accrual creation forms — the one-time
31
+ * accrual and the recurring accrued schedule.
32
+ *
33
+ * getAccountsTypesForScheduleDetails('accrued_expenses') deliberately includes
34
+ * other_current_liabilities, because the accrued liability accounts live there —
35
+ * so the debit list has to subtract them back out, and the credit list keeps only
36
+ * them. Mirrors getScheduleAccruedDetailView, which is the form this one is
37
+ * modelled on.
38
+ */
39
+ export const getNewAccrualAccountsView = (state) => {
40
+ const { accountState, accountListState, classState, classListState } = state;
41
+ const { newSchedule } = state.expenseAutomationJESchedulesViewState;
42
+ const accountType = getAccountsTypesForScheduleEpics();
43
+ const accrualAccountIds = getAccountIdsForTypes(accountState, getAccountsTypesForScheduleDetails('accrued_expenses'));
44
+ const accruedCategoryIds = getAccountIdsForLabels(accountState, ACCRUED_EXPENSE_ACCOUNT_LABELS);
45
+ const allAccountList = getAccountList(accountState, accountListState, accountType.accountListKey);
46
+ const nestedAccountHierarchy = getNestedAccountListHierarchy(accountListState, accountType.accountListKey);
47
+ const debitAccounts = allAccountList.accounts.filter((account) => accrualAccountIds.includes(account.accountId) &&
48
+ !accruedCategoryIds.includes(account.accountId));
49
+ const creditAccounts = allAccountList.accounts.filter((account) => accruedCategoryIds.includes(account.accountId));
50
+ const allClassList = getClassList(classState, classListState);
51
+ return {
52
+ accountListNestedAccountHierarchy: filterNestedAccountHierarchyById(nestedAccountHierarchy, debitAccounts.map((account) => account.accountId)),
53
+ accruedAccountListNestedAccountHierarchy: filterNestedAccountHierarchyById(nestedAccountHierarchy, creditAccounts.map((account) => account.accountId)),
54
+ allAccountList: debitAccounts,
55
+ allAccruedExpenseList: creditAccounts,
56
+ allClassList: allClassList.classes,
57
+ classListNestedAccountHierarchy: getNestedClassListHierarchy(classListState),
58
+ createStatus: newSchedule.createOneTimeAccrualStatus,
59
+ // The recurring accrued schedule saves through the accrued detail epics that the Vendor tab
60
+ // already uses, so its status is that slice's updateStatus rather than anything new here.
61
+ accruedScheduleSaveStatus: state.scheduleAccruedDetailState.updateStatus,
62
+ };
63
+ };
64
+ export const getNewScheduleView = (state, scheduleType) => {
65
+ const { accountState, accountListState, classState, classListState } = state;
66
+ const { newSchedule } = state.expenseAutomationJESchedulesViewState;
67
+ const searchTransactionsView = getNewScheduleSearchTransactionsView(state);
68
+ const accountType = getAccountsTypesForScheduleEpics();
69
+ const newScheduleAccountTypes = getAccountsTypesForScheduleDetails(scheduleType);
70
+ const newScheduleAccountIds = getAccountIdsForTypes(accountState, newScheduleAccountTypes);
71
+ const allAccountList = getAccountList(accountState, accountListState, accountType.accountListKey);
72
+ const filteredAccounts = allAccountList.accounts.filter((account) => newScheduleAccountIds.includes(account.accountId));
73
+ const accountListNestedAccountHierarchy = filterNestedAccountHierarchyById(getNestedAccountListHierarchy(accountListState, accountType.accountListKey), filteredAccounts.map((account) => account.accountId));
74
+ const allClassList = getClassList(classState, classListState);
75
+ const classListNestedAccountHierarchy = getNestedClassListHierarchy(classListState);
76
+ let allDepreciationAccountList;
77
+ let allDepreciationAccountListNestedAccountHierarchy;
78
+ if (scheduleType === 'fixed_assets') {
79
+ const depreciationCategoryIds = getAccountIdsForTypes(accountState, [
80
+ 'fixed_assets',
81
+ 'other_assets',
82
+ ]);
83
+ const accountLabel = getAccountLabelForScheduleType('fixed_assets');
84
+ const fixedAssetLabelAccountIds = accountLabel != null
85
+ ? getAccountIdsForLabel(accountListState, accountType.accountListKey, accountLabel)
86
+ : [];
87
+ allDepreciationAccountList = allAccountList.accounts.filter((account) => depreciationCategoryIds.includes(account.accountId) &&
88
+ !fixedAssetLabelAccountIds.includes(account.accountId));
89
+ allDepreciationAccountListNestedAccountHierarchy =
90
+ filterNestedAccountHierarchyById(getNestedAccountListHierarchy(accountListState, accountType.accountListKey), allDepreciationAccountList.map((account) => account.accountId));
91
+ }
92
+ return {
93
+ scheduleType,
94
+ accountListNestedAccountHierarchy,
95
+ allAccountList: filteredAccounts,
96
+ allClassList: allClassList.classes,
97
+ allDepreciationAccountList,
98
+ allDepreciationAccountListNestedAccountHierarchy,
99
+ classListNestedAccountHierarchy,
100
+ newScheduleLocalData: newSchedule.newScheduleState[scheduleType],
101
+ saveStatus: newSchedule.saveStatus,
102
+ ...searchTransactionsView,
103
+ fetchState: newSchedule.fetchState,
104
+ error: newSchedule.error,
105
+ };
106
+ };