@zeniai/client-epic-state 5.2.50 → 5.2.52-betaRD1
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.
- package/lib/entity/jeSchedules/jeSchedulesReducer.d.ts +4 -1
- package/lib/entity/jeSchedules/jeSchedulesReducer.js +47 -5
- package/lib/epic.d.ts +2 -1
- package/lib/epic.js +6 -4
- package/lib/esm/entity/jeSchedules/jeSchedulesReducer.js +46 -4
- package/lib/esm/epic.js +6 -4
- package/lib/esm/index.js +3 -3
- package/lib/esm/view/expenseAutomationView/epics/jeSchedule/fetchFailedJePostingsEpic.js +40 -0
- package/lib/esm/view/expenseAutomationView/epics/jeSchedule/fetchJeSchedulePageEpic.js +9 -1
- package/lib/esm/view/expenseAutomationView/epics/jeSchedule/fetchJeSchedulesEpic.js +10 -13
- package/lib/esm/view/expenseAutomationView/epics/jeSchedule/initializeJeScheduleLocalDataEpic.js +34 -15
- package/lib/esm/view/expenseAutomationView/epics/jeSchedule/retryJeSchedulesEpic.js +12 -1
- package/lib/esm/view/expenseAutomationView/reducers/jeSchedulesViewReducer.js +60 -1
- package/lib/esm/view/expenseAutomationView/selectors/jeSchedulesViewSelector.js +20 -12
- package/lib/index.d.ts +3 -3
- package/lib/index.js +50 -49
- package/lib/tsconfig.mocks.tsbuildinfo +1 -0
- package/lib/view/expenseAutomationView/epics/jeSchedule/fetchFailedJePostingsEpic.d.ts +20 -0
- package/lib/view/expenseAutomationView/epics/jeSchedule/fetchFailedJePostingsEpic.js +44 -0
- package/lib/view/expenseAutomationView/epics/jeSchedule/fetchJeSchedulePageEpic.d.ts +2 -2
- package/lib/view/expenseAutomationView/epics/jeSchedule/fetchJeSchedulePageEpic.js +8 -0
- package/lib/view/expenseAutomationView/epics/jeSchedule/fetchJeSchedulesEpic.js +8 -11
- package/lib/view/expenseAutomationView/epics/jeSchedule/initializeJeScheduleLocalDataEpic.js +34 -15
- package/lib/view/expenseAutomationView/epics/jeSchedule/retryJeSchedulesEpic.d.ts +2 -2
- package/lib/view/expenseAutomationView/epics/jeSchedule/retryJeSchedulesEpic.js +12 -1
- package/lib/view/expenseAutomationView/payload/jeSchedulesPayload.d.ts +18 -0
- package/lib/view/expenseAutomationView/reducers/jeSchedulesViewReducer.d.ts +8 -2
- package/lib/view/expenseAutomationView/reducers/jeSchedulesViewReducer.js +62 -3
- package/lib/view/expenseAutomationView/selectorTypes/jeSchedulesSelectorTypes.d.ts +2 -0
- package/lib/view/expenseAutomationView/selectors/jeSchedulesViewSelector.js +20 -12
- package/lib/view/expenseAutomationView/types/jeSchedulesViewState.d.ts +15 -0
- package/package.json +1 -1
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { ActionsObservable, StateObservable } from 'redux-observable';
|
|
2
|
+
import { Observable } from 'rxjs';
|
|
3
|
+
import { updateJESchedules, updateJESchedulesDetails } from '../../../../entity/jeSchedules/jeSchedulesReducer';
|
|
4
|
+
import { clearAll } from '../../../../rootActions';
|
|
5
|
+
import { RootState } from '../../../../rootStateTypes';
|
|
6
|
+
import { ZeniAPI } from '../../../../zeniAPI';
|
|
7
|
+
import { fetchFailedJePostings, fetchFailedJePostingsFailure, fetchFailedJePostingsSuccess, initializeJeScheduleLocalData } from '../../reducers/jeSchedulesViewReducer';
|
|
8
|
+
export type ActionType = ReturnType<typeof clearAll> | ReturnType<typeof fetchFailedJePostings> | ReturnType<typeof fetchFailedJePostingsFailure> | ReturnType<typeof fetchFailedJePostingsSuccess> | ReturnType<typeof initializeJeScheduleLocalData> | ReturnType<typeof updateJESchedules> | ReturnType<typeof updateJESchedulesDetails>;
|
|
9
|
+
/**
|
|
10
|
+
* Fetches every currently-failing posting for the tenant, on its own endpoint and with no window.
|
|
11
|
+
*
|
|
12
|
+
* Sends no query at all. The endpoint takes an optional `expected_post_start_date` floor and the
|
|
13
|
+
* client deliberately omits it: a failure is outstanding work until someone resolves it, whatever
|
|
14
|
+
* month it belongs to, and windowing this list is exactly what kept older failures off the only
|
|
15
|
+
* screen that can resolve them.
|
|
16
|
+
*
|
|
17
|
+
* `switchMap`, not `mergeMap`: there is one list per tenant, so a second trigger supersedes the
|
|
18
|
+
* first rather than racing it.
|
|
19
|
+
*/
|
|
20
|
+
export declare const fetchFailedJePostingsEpic: (actions$: ActionsObservable<ActionType>, _state$: StateObservable<RootState>, zeniAPI: ZeniAPI) => Observable<ActionType>;
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.fetchFailedJePostingsEpic = void 0;
|
|
4
|
+
const rxjs_1 = require("rxjs");
|
|
5
|
+
const operators_1 = require("rxjs/operators");
|
|
6
|
+
const jeSchedulesReducer_1 = require("../../../../entity/jeSchedules/jeSchedulesReducer");
|
|
7
|
+
const responsePayload_1 = require("../../../../responsePayload");
|
|
8
|
+
const rootActions_1 = require("../../../../rootActions");
|
|
9
|
+
const jeSchedulesViewReducer_1 = require("../../reducers/jeSchedulesViewReducer");
|
|
10
|
+
/**
|
|
11
|
+
* Fetches every currently-failing posting for the tenant, on its own endpoint and with no window.
|
|
12
|
+
*
|
|
13
|
+
* Sends no query at all. The endpoint takes an optional `expected_post_start_date` floor and the
|
|
14
|
+
* client deliberately omits it: a failure is outstanding work until someone resolves it, whatever
|
|
15
|
+
* month it belongs to, and windowing this list is exactly what kept older failures off the only
|
|
16
|
+
* screen that can resolve them.
|
|
17
|
+
*
|
|
18
|
+
* `switchMap`, not `mergeMap`: there is one list per tenant, so a second trigger supersedes the
|
|
19
|
+
* first rather than racing it.
|
|
20
|
+
*/
|
|
21
|
+
const fetchFailedJePostingsEpic = (actions$, _state$, zeniAPI) => actions$.pipe((0, operators_1.filter)(jeSchedulesViewReducer_1.fetchFailedJePostings.match), (0, operators_1.switchMap)(() => zeniAPI
|
|
22
|
+
.getJSON(`${zeniAPI.apiEndPoints.accountMicroServiceBaseUrl}/1.0/expenses_automation/failed_je_postings`)
|
|
23
|
+
.pipe((0, operators_1.switchMap)((response) => {
|
|
24
|
+
if (!(0, responsePayload_1.isSuccessResponse)(response) || response.data == null) {
|
|
25
|
+
return (0, rxjs_1.of)((0, jeSchedulesViewReducer_1.fetchFailedJePostingsFailure)(response.status));
|
|
26
|
+
}
|
|
27
|
+
const failedJeSchedules = response.data.failed_je_postings?.je_schedules ?? [];
|
|
28
|
+
const failedScheduledJournalEntries = response.data.failed_je_postings?.scheduled_journal_entries ?? [];
|
|
29
|
+
// Order matters and matches fetchJeSchedulesEpic: updateJESchedules fans out to the
|
|
30
|
+
// vendor / account / class / user entities, updateJESchedulesDetails then attaches the
|
|
31
|
+
// journal entries, and only then can initializeJeScheduleLocalData read them back.
|
|
32
|
+
return (0, rxjs_1.from)([
|
|
33
|
+
(0, jeSchedulesReducer_1.updateJESchedules)(failedJeSchedules),
|
|
34
|
+
(0, jeSchedulesReducer_1.updateJESchedulesDetails)(failedJeSchedules, failedScheduledJournalEntries),
|
|
35
|
+
(0, jeSchedulesViewReducer_1.initializeJeScheduleLocalData)(failedJeSchedules),
|
|
36
|
+
(0, jeSchedulesViewReducer_1.fetchFailedJePostingsSuccess)(failedJeSchedules),
|
|
37
|
+
]);
|
|
38
|
+
}), (0, operators_1.catchError)((error) => (0, rxjs_1.of)((0, jeSchedulesViewReducer_1.fetchFailedJePostingsFailure)((0, responsePayload_1.createZeniAPIStatus)('Unexpected Error', 'fetch failed JE postings REST API call errored out' +
|
|
39
|
+
JSON.stringify(error))))),
|
|
40
|
+
// A tenant switch clears the store while this request is still in flight. Without this
|
|
41
|
+
// the old tenant's rows are written back into the freshly cleared store and stay on
|
|
42
|
+
// screen under the new tenant until a manual refresh.
|
|
43
|
+
(0, operators_1.takeUntil)(actions$.pipe((0, operators_1.filter)(rootActions_1.clearAll.match))))));
|
|
44
|
+
exports.fetchFailedJePostingsEpic = fetchFailedJePostingsEpic;
|
|
@@ -3,6 +3,6 @@ import { Observable } from 'rxjs';
|
|
|
3
3
|
import { RootState } from '../../../../rootStateTypes';
|
|
4
4
|
import { fetchAccountList } from '../../../accountList/accountListReducer';
|
|
5
5
|
import { fetchActualMatchingPage } from '../../reducers/actualMatchingViewReducer';
|
|
6
|
-
import { fetchJeSchedules, fetchJeSchedulesPage, initializeAccountSettingsView } from '../../reducers/jeSchedulesViewReducer';
|
|
7
|
-
export type ActionType = ReturnType<typeof fetchAccountList> | ReturnType<typeof fetchActualMatchingPage> | ReturnType<typeof fetchJeSchedules> | ReturnType<typeof fetchJeSchedulesPage> | ReturnType<typeof initializeAccountSettingsView>;
|
|
6
|
+
import { fetchFailedJePostings, fetchJeSchedules, fetchJeSchedulesPage, initializeAccountSettingsView } from '../../reducers/jeSchedulesViewReducer';
|
|
7
|
+
export type ActionType = ReturnType<typeof fetchAccountList> | ReturnType<typeof fetchActualMatchingPage> | ReturnType<typeof fetchFailedJePostings> | ReturnType<typeof fetchJeSchedules> | ReturnType<typeof fetchJeSchedulesPage> | ReturnType<typeof initializeAccountSettingsView>;
|
|
8
8
|
export declare const fetchJeSchedulesPageEpic: (actions$: ActionsObservable<ActionType>, state$: StateObservable<RootState>) => Observable<ActionType>;
|
|
@@ -27,6 +27,14 @@ const fetchJeSchedulesPageEpic = (actions$, state$) => actions$.pipe((0, operato
|
|
|
27
27
|
else {
|
|
28
28
|
jeSchedulePageActions.push((0, jeSchedulesViewReducer_1.fetchJeSchedules)(period, refreshViewInBackground));
|
|
29
29
|
}
|
|
30
|
+
// Failed postings are tenant-wide and carry no period, so a period change or a tab switch
|
|
31
|
+
// cannot invalidate them -- fetch once and let retry keep the list current from then on.
|
|
32
|
+
// Refreshes still refetch, silently, so a failure resolved elsewhere leaves eventually.
|
|
33
|
+
const { fetchState: failedPostingsFetchState } = state.expenseAutomationJESchedulesViewState.failedJePostings.fetchState;
|
|
34
|
+
const isBackgroundRefresh = refreshViewInBackground === true;
|
|
35
|
+
if (failedPostingsFetchState === 'Not-Started' || isBackgroundRefresh) {
|
|
36
|
+
jeSchedulePageActions.push((0, jeSchedulesViewReducer_1.fetchFailedJePostings)(isBackgroundRefresh));
|
|
37
|
+
}
|
|
30
38
|
// Only on the first page load. Account settings cannot change from a tab switch or a
|
|
31
39
|
// refresh, and re-initializing puts accountSettingsView back to 'In-Progress' -- which the
|
|
32
40
|
// page reads as "still loading" and answers with a full skeleton over rows it already has.
|
|
@@ -84,8 +84,9 @@ const fetchJeSchedulesEpic = (actions$, state$, zeniAPI) => actions$.pipe((0, op
|
|
|
84
84
|
one_time_accrual_service_month_end: parsedEndDate.format(jeSchedulesPayload_1.SERVICE_MONTH_FORMAT),
|
|
85
85
|
// Existing lists what actually reached the books.
|
|
86
86
|
one_time_accrual_statuses: ['posted'],
|
|
87
|
-
//
|
|
88
|
-
//
|
|
87
|
+
// Kept only so this tab's response shape is unchanged. Nothing reads the failed
|
|
88
|
+
// postings it returns any more -- they have their own endpoint and their own group
|
|
89
|
+
// on Review. Dropping the key from the response is a server-side follow-up.
|
|
89
90
|
filter_failed_je_postings_by_date: false,
|
|
90
91
|
}),
|
|
91
92
|
};
|
|
@@ -96,12 +97,10 @@ const fetchJeSchedulesEpic = (actions$, state$, zeniAPI) => actions$.pipe((0, op
|
|
|
96
97
|
const updateActions = [];
|
|
97
98
|
const accruedJeSchedules = response.data.accrued_je_schedules?.je_schedules ?? [];
|
|
98
99
|
const oneTimeAccruals = response.data.one_time_accruals ?? [];
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
...response.data.failed_je_postings.je_schedules,
|
|
104
|
-
]));
|
|
100
|
+
// failed_je_postings is deliberately ignored. This endpoint windows it to the close
|
|
101
|
+
// month, which is what hid older failures; fetchFailedJePostingsEpic owns that list
|
|
102
|
+
// now and fetches it unwindowed.
|
|
103
|
+
updateActions.push((0, jeSchedulesReducer_1.updateJESchedules)([...response.data.je_schedules]));
|
|
105
104
|
if (accruedJeSchedules.length > 0) {
|
|
106
105
|
updateActions.push((0, jeSchedulesReducer_1.updateAccruedJESchedules)(accruedJeSchedules), (0, jeSchedulesReducer_1.updateAccruedJESchedulesDetails)(accruedJeSchedules, response.data.accrued_je_schedules
|
|
107
106
|
?.scheduled_journal_entries));
|
|
@@ -114,9 +113,7 @@ const fetchJeSchedulesEpic = (actions$, state$, zeniAPI) => actions$.pipe((0, op
|
|
|
114
113
|
}
|
|
115
114
|
updateActions.push((0, jeSchedulesViewReducer_1.fetchJeSchedulesSuccess)({
|
|
116
115
|
jeSchedules: [...response.data.je_schedules],
|
|
117
|
-
failedJeSchedules: [
|
|
118
|
-
...response.data.failed_je_postings.je_schedules,
|
|
119
|
-
],
|
|
116
|
+
failedJeSchedules: [],
|
|
120
117
|
accruedJeSchedules: accruedJeSchedules,
|
|
121
118
|
oneTimeAccruals: oneTimeAccruals,
|
|
122
119
|
selectedPeriod: selectedPeriod,
|
package/lib/view/expenseAutomationView/epics/jeSchedule/initializeJeScheduleLocalDataEpic.js
CHANGED
|
@@ -10,22 +10,41 @@ const initializeJeScheduleLocalDataEpic = (actions$, state$) => actions$.pipe((0
|
|
|
10
10
|
const actions = [];
|
|
11
11
|
const { jeScheduleTransactionKeys } = action.payload;
|
|
12
12
|
jeScheduleTransactionKeys.forEach((jeScheduleTransactionKey) => {
|
|
13
|
+
// Checked before the selector runs, not after: the selector destructures the record it
|
|
14
|
+
// looks up, so a key that is not in the store throws a TypeError rather than returning
|
|
15
|
+
// undefined. This epic is a mergeMap with no catchError, so that throw would take its
|
|
16
|
+
// subscription down for the rest of the session and silently stop local-data
|
|
17
|
+
// initialisation everywhere -- not just for this row.
|
|
18
|
+
if (state.jeSchedulesState.schedulesByTransactionKey[jeScheduleTransactionKey] == null) {
|
|
19
|
+
return;
|
|
20
|
+
}
|
|
13
21
|
const jeScheduledTransaction = (0, jeSchedulesSelector_1.getJEScheduledTransactionByJEScheduleTransactionKey)(jeScheduleTransactionKey, state);
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
scheduledJournalEntryID
|
|
27
|
-
|
|
28
|
-
|
|
22
|
+
// One record per journal entry, not per schedule. A schedule that failed in two months is
|
|
23
|
+
// two rows and each needs its own vendor / category edits -- keying only the first left
|
|
24
|
+
// every later row without local data, which the list renders read-only and without a
|
|
25
|
+
// Retry button. An empty array is possible when details have not landed yet; it must not
|
|
26
|
+
// throw, because this runs in a mergeMap with no catchError and the throw would take the
|
|
27
|
+
// epic's subscription down for the rest of the session.
|
|
28
|
+
// Filtered on `error` for the same reason the selector is: this array is shared state, and
|
|
29
|
+
// a schedule whose detail page has been opened holds every month it has, posted ones
|
|
30
|
+
// included. The seeding and the rows must agree on which entries are failed postings.
|
|
31
|
+
jeScheduledTransaction.scheduledJournalEntry
|
|
32
|
+
.filter((journalEntry) => journalEntry.error.length > 0)
|
|
33
|
+
.forEach((journalEntry) => {
|
|
34
|
+
const { scheduledJournalEntryID } = journalEntry;
|
|
35
|
+
actions.push((0, jeSchedulesViewReducer_1.updateJeScheduleLocalDataById)({
|
|
36
|
+
localData: {
|
|
37
|
+
jeScheduleType: jeScheduledTransaction.jeScheduleType,
|
|
38
|
+
jeScheduleID: jeScheduledTransaction.jeScheduleId,
|
|
39
|
+
scheduledJournalEntryID,
|
|
40
|
+
updatedVendor: undefined,
|
|
41
|
+
updatedCategoryId: undefined,
|
|
42
|
+
updatedAccumulatedDepreciationCategoryID: undefined,
|
|
43
|
+
updatedClassId: undefined,
|
|
44
|
+
},
|
|
45
|
+
scheduledJournalEntryID,
|
|
46
|
+
}));
|
|
47
|
+
});
|
|
29
48
|
});
|
|
30
49
|
return (0, rxjs_1.from)(actions);
|
|
31
50
|
}));
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import { ActionsObservable, StateObservable } from 'redux-observable';
|
|
2
2
|
import { Observable } from 'rxjs';
|
|
3
|
-
import { updateJESchedules, updateJESchedulesDetails } from '../../../../entity/jeSchedules/jeSchedulesReducer';
|
|
3
|
+
import { removeScheduledJournalEntryFromJESchedule, updateJESchedules, updateJESchedulesDetails } from '../../../../entity/jeSchedules/jeSchedulesReducer';
|
|
4
4
|
import { openSnackbar } from '../../../../entity/snackbar/snackbarReducer';
|
|
5
5
|
import { RootState } from '../../../../rootStateTypes';
|
|
6
6
|
import { ZeniAPI } from '../../../../zeniAPI';
|
|
7
7
|
import { fetchMonthEndCloseChecks } from '../../../monthEndCloseChecksView/monthEndCloseChecksViewReducer';
|
|
8
8
|
import { removeFailedJeScheduleTransactionKey, removeJeScheduleLocalDataById, retryJeSchedule, retryJeScheduleFailure, retryJeScheduleSuccess, updateJeScheduleTransactionKeys } from '../../reducers/jeSchedulesViewReducer';
|
|
9
|
-
export type ActionType = ReturnType<typeof fetchMonthEndCloseChecks> | ReturnType<typeof openSnackbar> | ReturnType<typeof removeFailedJeScheduleTransactionKey> | ReturnType<typeof removeJeScheduleLocalDataById> | ReturnType<typeof retryJeSchedule> | ReturnType<typeof retryJeScheduleFailure> | ReturnType<typeof retryJeScheduleSuccess> | ReturnType<typeof updateJESchedules> | ReturnType<typeof updateJESchedulesDetails> | ReturnType<typeof updateJeScheduleTransactionKeys>;
|
|
9
|
+
export type ActionType = ReturnType<typeof fetchMonthEndCloseChecks> | ReturnType<typeof openSnackbar> | ReturnType<typeof removeFailedJeScheduleTransactionKey> | ReturnType<typeof removeJeScheduleLocalDataById> | ReturnType<typeof removeScheduledJournalEntryFromJESchedule> | ReturnType<typeof retryJeSchedule> | ReturnType<typeof retryJeScheduleFailure> | ReturnType<typeof retryJeScheduleSuccess> | ReturnType<typeof updateJESchedules> | ReturnType<typeof updateJESchedulesDetails> | ReturnType<typeof updateJeScheduleTransactionKeys>;
|
|
10
10
|
export declare const retryJeScheduleEpic: (actions$: ActionsObservable<ActionType>, state$: StateObservable<RootState>, zeniAPI: ZeniAPI) => Observable<ActionType>;
|
|
@@ -3,6 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.retryJeScheduleEpic = void 0;
|
|
4
4
|
const rxjs_1 = require("rxjs");
|
|
5
5
|
const operators_1 = require("rxjs/operators");
|
|
6
|
+
const jeSchedulesReducer_1 = require("../../../../entity/jeSchedules/jeSchedulesReducer");
|
|
6
7
|
const snackbarReducer_1 = require("../../../../entity/snackbar/snackbarReducer");
|
|
7
8
|
const tenantSelector_1 = require("../../../../entity/tenant/tenantSelector");
|
|
8
9
|
const responsePayload_1 = require("../../../../responsePayload");
|
|
@@ -25,9 +26,16 @@ const retryJeScheduleEpic = (actions$, state$, zeniAPI) => actions$.pipe((0, ope
|
|
|
25
26
|
.pipe((0, operators_1.mergeMap)((response) => {
|
|
26
27
|
if ((0, responsePayload_1.isSuccessStatus)(response)) {
|
|
27
28
|
const updateActions = [];
|
|
29
|
+
// Retire this entry, and the schedule itself only when this was its last failed
|
|
30
|
+
// one. A schedule that failed in several months is several rows sharing one
|
|
31
|
+
// schedule key, so dropping the key outright took the still-failing months off the
|
|
32
|
+
// list with it and nothing would have surfaced them again.
|
|
33
|
+
const failedEntriesForSchedule = state.jeSchedulesState.schedulesByTransactionKey[jeScheduleTransactionKey]?.scheduledJournalEntry ?? [];
|
|
34
|
+
const wasLastFailedEntryForSchedule = failedEntriesForSchedule.filter((journalEntry) => journalEntry.scheduledJournalEntryID !==
|
|
35
|
+
scheduledJournalEntryID).length === 0;
|
|
28
36
|
updateActions.push((0, jeSchedulesViewReducer_1.retryJeScheduleSuccess)({
|
|
29
37
|
scheduledJournalEntryID,
|
|
30
|
-
}), (0,
|
|
38
|
+
}), (0, jeSchedulesReducer_1.removeScheduledJournalEntryFromJESchedule)(jeScheduleTransactionKey, scheduledJournalEntryID), (0, jeSchedulesViewReducer_1.removeJeScheduleLocalDataById)({ scheduledJournalEntryID }), // Important to remove localdata after success.
|
|
31
39
|
(0, monthEndCloseChecksViewReducer_1.fetchMonthEndCloseChecks)({
|
|
32
40
|
tenantId: currentTenant.tenantId,
|
|
33
41
|
period: selectedPeriod,
|
|
@@ -37,6 +45,9 @@ const retryJeScheduleEpic = (actions$, state$, zeniAPI) => actions$.pipe((0, ope
|
|
|
37
45
|
messageText: 'success',
|
|
38
46
|
type: 'success',
|
|
39
47
|
}));
|
|
48
|
+
if (wasLastFailedEntryForSchedule) {
|
|
49
|
+
updateActions.push((0, jeSchedulesViewReducer_1.removeFailedJeScheduleTransactionKey)(jeScheduleTransactionKey, selectedPeriod));
|
|
50
|
+
}
|
|
40
51
|
return (0, rxjs_1.from)(updateActions);
|
|
41
52
|
}
|
|
42
53
|
else {
|
|
@@ -78,6 +78,24 @@ interface ExpenseAutomationJESchedulesPayload {
|
|
|
78
78
|
};
|
|
79
79
|
}
|
|
80
80
|
export type ExpenseAutomationJESchedulesResponse = ZeniAPIResponse<ExpenseAutomationJESchedulesPayload>;
|
|
81
|
+
/**
|
|
82
|
+
* `GET /1.0/expenses_automation/failed_je_postings`.
|
|
83
|
+
*
|
|
84
|
+
* Deliberately the same `failed_je_postings` shape the schedules endpoint sends under that key, so
|
|
85
|
+
* both responses feed the same mappers. The difference is what the server does before answering:
|
|
86
|
+
* this endpoint applies no date window, so a posting that failed months ago still comes back.
|
|
87
|
+
*/
|
|
88
|
+
export interface FailedJePostingsPayload {
|
|
89
|
+
je_schedules: JEScheduledTransactionPayload[];
|
|
90
|
+
scheduled_journal_entries: ScheduledJournalEntryPayload[];
|
|
91
|
+
}
|
|
92
|
+
interface ExpenseAutomationFailedJePostingsPayload {
|
|
93
|
+
failed_je_postings: FailedJePostingsPayload;
|
|
94
|
+
query?: {
|
|
95
|
+
expected_post_start_date: string | null;
|
|
96
|
+
};
|
|
97
|
+
}
|
|
98
|
+
export type ExpenseAutomationFailedJePostingsResponse = ZeniAPIResponse<ExpenseAutomationFailedJePostingsPayload>;
|
|
81
99
|
export declare const SERVICE_MONTH_FORMAT = "YYYY-MM";
|
|
82
100
|
export interface CreateOneTimeAccrualPayload {
|
|
83
101
|
amount: number;
|
|
@@ -47,7 +47,13 @@ export declare const clearExpenseAutomationJESchedulesView: import("@reduxjs/too
|
|
|
47
47
|
period: TimePeriod;
|
|
48
48
|
refreshViewInBackground: any;
|
|
49
49
|
selectedPageTab: "schedules" | "actual_matching" | "existing_schedules" | undefined;
|
|
50
|
-
}, "expenseAutomationJESchedulesView/fetchJeSchedules", never, never>,
|
|
50
|
+
}, "expenseAutomationJESchedulesView/fetchJeSchedules", never, never>, fetchFailedJePostings: import("@reduxjs/toolkit").ActionCreatorWithPreparedPayload<[refreshInBackground?: any], {
|
|
51
|
+
refreshInBackground: any;
|
|
52
|
+
}, "expenseAutomationJESchedulesView/fetchFailedJePostings", never, never>, fetchFailedJePostingsFailure: import("@reduxjs/toolkit").ActionCreatorWithPreparedPayload<[status: ZeniAPIStatus<Record<string, unknown>>], {
|
|
53
|
+
status: ZeniAPIStatus<Record<string, unknown>>;
|
|
54
|
+
}, "expenseAutomationJESchedulesView/fetchFailedJePostingsFailure", never, never>, fetchFailedJePostingsSuccess: import("@reduxjs/toolkit").ActionCreatorWithPreparedPayload<[failedJeSchedules: JEScheduledTransactionPayload[]], {
|
|
55
|
+
failedJeSchedules: JEScheduledTransactionPayload[];
|
|
56
|
+
}, "expenseAutomationJESchedulesView/fetchFailedJePostingsSuccess", never, never>, fetchJeSchedulesFailure: import("@reduxjs/toolkit").ActionCreatorWithPayload<{
|
|
51
57
|
selectedPageTab: JEPageTab;
|
|
52
58
|
selectedPeriod: MonthYearPeriod;
|
|
53
59
|
status: ZeniAPIStatus;
|
|
@@ -132,7 +138,7 @@ export declare const clearExpenseAutomationJESchedulesView: import("@reduxjs/too
|
|
|
132
138
|
status: ZeniAPIStatus;
|
|
133
139
|
}, "expenseAutomationJESchedulesView/searchTransactionsForNewScheduleFailure">, searchTransactionsForNewScheduleSuccess: import("@reduxjs/toolkit").ActionCreatorWithPayload<{
|
|
134
140
|
searchResults: JEScheduleTransactionKey[];
|
|
135
|
-
}, "expenseAutomationJESchedulesView/searchTransactionsForNewScheduleSuccess">, toggleJECreatedGroupCollapsed: import("@reduxjs/toolkit").ActionCreatorWithoutPayload<"expenseAutomationJESchedulesView/toggleJECreatedGroupCollapsed">, toggleJEPendingGroupCollapsed: import("@reduxjs/toolkit").ActionCreatorWithoutPayload<"expenseAutomationJESchedulesView/toggleJEPendingGroupCollapsed">, updateAccountSettingsListForAccountTypes: import("@reduxjs/toolkit").ActionCreatorWithPayload<{
|
|
141
|
+
}, "expenseAutomationJESchedulesView/searchTransactionsForNewScheduleSuccess">, toggleJECreatedGroupCollapsed: import("@reduxjs/toolkit").ActionCreatorWithoutPayload<"expenseAutomationJESchedulesView/toggleJECreatedGroupCollapsed">, toggleJEFailedGroupCollapsed: import("@reduxjs/toolkit").ActionCreatorWithoutPayload<"expenseAutomationJESchedulesView/toggleJEFailedGroupCollapsed">, toggleJEPendingGroupCollapsed: import("@reduxjs/toolkit").ActionCreatorWithoutPayload<"expenseAutomationJESchedulesView/toggleJEPendingGroupCollapsed">, updateAccountSettingsListForAccountTypes: import("@reduxjs/toolkit").ActionCreatorWithPayload<{
|
|
136
142
|
accountPayload: AccountMetadataPayload[];
|
|
137
143
|
}, "expenseAutomationJESchedulesView/updateAccountSettingsListForAccountTypes">, updateAccountSettingsListForAccountTypesFailure: import("@reduxjs/toolkit").ActionCreatorWithPayload<{
|
|
138
144
|
status: ZeniAPIStatus;
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
var _a;
|
|
3
3
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
4
|
-
exports.
|
|
5
|
-
exports.updateRecommendationForAccountSettingsFailure = exports.updateRecommendationForAccountSettings = exports.updateNewScheduleLocalData = exports.updateJeScheduleTransactionKeys = exports.updateJeScheduleLocalDataById = exports.updateJeOneTimeAccrualLocalData = exports.updateJEScheduleTypeFilter = exports.updateJESchedulesUIState = exports.updateAccountSettingsListForAccountTypesFailure = exports.updateAccountSettingsListForAccountTypes = exports.toggleJEPendingGroupCollapsed = exports.toggleJECreatedGroupCollapsed = exports.searchTransactionsForNewScheduleSuccess = exports.searchTransactionsForNewScheduleFailure = exports.searchTransactionsForNewSchedule = exports.saveNewScheduleSuccess = void 0;
|
|
4
|
+
exports.saveAccountSettingsLocalData = exports.saveAccountSettingsFailure = exports.saveAccountSettings = exports.retryJeScheduleSuccess = exports.retryJeScheduleFailure = exports.retryJeSchedule = exports.resetNewScheduleLocalData = exports.removeJeScheduleTransactionKey = exports.removeJeAccruedScheduleKey = exports.removeJeScheduleLocalDataById = exports.removeJeOneTimeAccrualLocalData = exports.removeFailedJeScheduleTransactionKey = exports.initializeNewSchedule = exports.initializeJeScheduleLocalData = exports.initializeAccountSettingsView = exports.ignoreRecommendedJeScheduleSuccess = exports.ignoreRecommendedJeScheduleFailure = exports.ignoreRecommendedJeSchedule = exports.fetchRecommendationForAccountSettings = exports.fetchOneTimeAccrualSuccess = exports.fetchOneTimeAccrualFailure = exports.fetchOneTimeAccrual = exports.fetchJeSchedulesSuccess = exports.fetchJeSchedulesPage = exports.fetchJeSchedulesFailure = exports.fetchFailedJePostingsSuccess = exports.fetchFailedJePostingsFailure = exports.fetchFailedJePostings = exports.fetchJeSchedules = exports.fetchAccountSettingsListForAccountTypes = exports.revertOneTimeAccrual = exports.revertJeScheduleSuccess = exports.revertJeScheduleFailure = exports.revertJeSchedule = exports.promoteOneTimeAccrual = exports.oneTimeAccrualActionSuccess = exports.oneTimeAccrualActionFailure = exports.ignoreOneTimeAccrual = exports.createOneTimeAccrualSuccess = exports.createOneTimeAccrualFailure = exports.createOneTimeAccrual = exports.clearSearchTransactionsForNewSchedule = exports.clearJeScheduleLocalData = exports.clearJeAccountSettingsLocalData = exports.clearExpenseAutomationJESchedulesView = exports.initialState = exports.searchTransactionsInitialState = exports.newScheduleInitialState = exports.getBaseNewScheduleLocalData = exports.accountSettingsInitialState = void 0;
|
|
5
|
+
exports.updateRecommendationForAccountSettingsFailure = exports.updateRecommendationForAccountSettings = exports.updateNewScheduleLocalData = exports.updateJeScheduleTransactionKeys = exports.updateJeScheduleLocalDataById = exports.updateJeOneTimeAccrualLocalData = exports.updateJEScheduleTypeFilter = exports.updateJESchedulesUIState = exports.updateAccountSettingsListForAccountTypesFailure = exports.updateAccountSettingsListForAccountTypes = exports.toggleJEPendingGroupCollapsed = exports.toggleJEFailedGroupCollapsed = exports.toggleJECreatedGroupCollapsed = exports.searchTransactionsForNewScheduleSuccess = exports.searchTransactionsForNewScheduleFailure = exports.searchTransactionsForNewSchedule = exports.saveNewScheduleSuccess = exports.saveNewScheduleFailure = exports.saveNewSchedule = exports.saveAccountSettingsSuccess = void 0;
|
|
6
6
|
const toolkit_1 = require("@reduxjs/toolkit");
|
|
7
7
|
const getNestedAccountIDHierarchyForReport_1 = require("../../../commonStateTypes/accountView/getNestedAccountIDHierarchyForReport");
|
|
8
8
|
const timePeriod_1 = require("../../../commonStateTypes/timePeriod");
|
|
@@ -68,6 +68,10 @@ exports.initialState = {
|
|
|
68
68
|
jeScheduleAccruedKeysByPeriodAndTab: {},
|
|
69
69
|
jeScheduleOneTimeAccrualKeysByPeriodAndTab: {},
|
|
70
70
|
failedJeScheduleTransactionKeysByPeriodAndTab: {},
|
|
71
|
+
failedJePostings: {
|
|
72
|
+
fetchState: { fetchState: 'Not-Started', error: undefined },
|
|
73
|
+
jeScheduleTransactionKeys: [],
|
|
74
|
+
},
|
|
71
75
|
postStatusById: {},
|
|
72
76
|
ignoreStatusById: {},
|
|
73
77
|
revertStatusById: {},
|
|
@@ -77,6 +81,9 @@ exports.initialState = {
|
|
|
77
81
|
oneTimeAccrualFetchStatusById: {},
|
|
78
82
|
uiState: {
|
|
79
83
|
createdGroupCollapsed: false,
|
|
84
|
+
// Expanded, like the other two. A failed posting is the only thing on this page that is
|
|
85
|
+
// actively wrong, so folding it away by default would hide the reason to open the tab.
|
|
86
|
+
failedGroupCollapsed: false,
|
|
80
87
|
pendingGroupCollapsed: false,
|
|
81
88
|
scrollPosition: { scrollTop: 0, scrollLeft: undefined },
|
|
82
89
|
searchString: '',
|
|
@@ -148,6 +155,53 @@ const expenseAutomationJESchedulesView = (0, toolkit_1.createSlice)({
|
|
|
148
155
|
};
|
|
149
156
|
},
|
|
150
157
|
},
|
|
158
|
+
/**
|
|
159
|
+
* The Failed Postings list, fetched separately from the schedules it belongs to.
|
|
160
|
+
*
|
|
161
|
+
* No period and no tab in any of these three: the endpoint applies no date window, so there is
|
|
162
|
+
* one list per tenant and one slot to hold it. `refreshInBackground` keeps a silent refetch
|
|
163
|
+
* from dropping a skeleton over rows already on screen, the same way refreshStatus does for
|
|
164
|
+
* the schedules list.
|
|
165
|
+
*/
|
|
166
|
+
fetchFailedJePostings: {
|
|
167
|
+
reducer(draft, action) {
|
|
168
|
+
if (!action.payload.refreshInBackground) {
|
|
169
|
+
draft.failedJePostings.fetchState = {
|
|
170
|
+
fetchState: 'In-Progress',
|
|
171
|
+
error: undefined,
|
|
172
|
+
};
|
|
173
|
+
}
|
|
174
|
+
},
|
|
175
|
+
prepare(refreshInBackground = false) {
|
|
176
|
+
return { payload: { refreshInBackground } };
|
|
177
|
+
},
|
|
178
|
+
},
|
|
179
|
+
fetchFailedJePostingsSuccess: {
|
|
180
|
+
reducer(draft, action) {
|
|
181
|
+
draft.failedJePostings = {
|
|
182
|
+
fetchState: { fetchState: 'Completed', error: undefined },
|
|
183
|
+
jeScheduleTransactionKeys: action.payload.failedJeSchedules.map((schedule) => (0, jeSchedulesPayload_1.getJEScheduleTransactionDetailKeyPayload)(schedule.base_transaction)),
|
|
184
|
+
};
|
|
185
|
+
},
|
|
186
|
+
prepare(failedJeSchedules) {
|
|
187
|
+
return { payload: { failedJeSchedules } };
|
|
188
|
+
},
|
|
189
|
+
},
|
|
190
|
+
fetchFailedJePostingsFailure: {
|
|
191
|
+
reducer(draft, action) {
|
|
192
|
+
// Keys are deliberately left alone. The schedules list clears its buckets on failure so an
|
|
193
|
+
// errored tab cannot read as "these are all the schedules there are", but this list is a
|
|
194
|
+
// set of outstanding problems -- showing the last known ones beside an error beats
|
|
195
|
+
// implying there are none.
|
|
196
|
+
draft.failedJePostings.fetchState = {
|
|
197
|
+
fetchState: 'Error',
|
|
198
|
+
error: action.payload.status,
|
|
199
|
+
};
|
|
200
|
+
},
|
|
201
|
+
prepare(status) {
|
|
202
|
+
return { payload: { status } };
|
|
203
|
+
},
|
|
204
|
+
},
|
|
151
205
|
fetchJeSchedulesSuccess(draft, action) {
|
|
152
206
|
const { jeSchedules, selectedPeriod, selectedPageTab, failedJeSchedules, accruedJeSchedules, oneTimeAccruals, refreshViewInBackground, } = action.payload;
|
|
153
207
|
const periodTabKey = (0, jeSchedulesViewState_1.getJESchedulePeriodTabKey)(selectedPageTab, (0, timePeriod_1.toMonthYearPeriodId)(selectedPeriod));
|
|
@@ -364,6 +418,8 @@ const expenseAutomationJESchedulesView = (0, toolkit_1.createSlice)({
|
|
|
364
418
|
reducer(draft, action) {
|
|
365
419
|
const { failedJeScheduleKey } = action.payload;
|
|
366
420
|
removeKeyFromEveryTabSlot(draft.failedJeScheduleTransactionKeysByPeriodAndTab, failedJeScheduleKey);
|
|
421
|
+
draft.failedJePostings.jeScheduleTransactionKeys =
|
|
422
|
+
draft.failedJePostings.jeScheduleTransactionKeys.filter((jeScheduleKey) => jeScheduleKey !== failedJeScheduleKey);
|
|
367
423
|
},
|
|
368
424
|
},
|
|
369
425
|
initializeJeScheduleLocalData: {
|
|
@@ -706,6 +762,9 @@ const expenseAutomationJESchedulesView = (0, toolkit_1.createSlice)({
|
|
|
706
762
|
draft.uiState.createdGroupCollapsed =
|
|
707
763
|
!draft.uiState.createdGroupCollapsed;
|
|
708
764
|
},
|
|
765
|
+
toggleJEFailedGroupCollapsed(draft) {
|
|
766
|
+
draft.uiState.failedGroupCollapsed = !draft.uiState.failedGroupCollapsed;
|
|
767
|
+
},
|
|
709
768
|
clearExpenseAutomationJESchedulesView(draft) {
|
|
710
769
|
Object.assign(draft, exports.initialState);
|
|
711
770
|
},
|
|
@@ -716,7 +775,7 @@ const expenseAutomationJESchedulesView = (0, toolkit_1.createSlice)({
|
|
|
716
775
|
});
|
|
717
776
|
},
|
|
718
777
|
});
|
|
719
|
-
_a = expenseAutomationJESchedulesView.actions, exports.clearExpenseAutomationJESchedulesView = _a.clearExpenseAutomationJESchedulesView, exports.clearJeAccountSettingsLocalData = _a.clearJeAccountSettingsLocalData, exports.clearJeScheduleLocalData = _a.clearJeScheduleLocalData, exports.clearSearchTransactionsForNewSchedule = _a.clearSearchTransactionsForNewSchedule, exports.createOneTimeAccrual = _a.createOneTimeAccrual, exports.createOneTimeAccrualFailure = _a.createOneTimeAccrualFailure, exports.createOneTimeAccrualSuccess = _a.createOneTimeAccrualSuccess, exports.ignoreOneTimeAccrual = _a.ignoreOneTimeAccrual, exports.oneTimeAccrualActionFailure = _a.oneTimeAccrualActionFailure, exports.oneTimeAccrualActionSuccess = _a.oneTimeAccrualActionSuccess, exports.promoteOneTimeAccrual = _a.promoteOneTimeAccrual, exports.revertJeSchedule = _a.revertJeSchedule, exports.revertJeScheduleFailure = _a.revertJeScheduleFailure, exports.revertJeScheduleSuccess = _a.revertJeScheduleSuccess, exports.revertOneTimeAccrual = _a.revertOneTimeAccrual, exports.fetchAccountSettingsListForAccountTypes = _a.fetchAccountSettingsListForAccountTypes, exports.fetchJeSchedules = _a.fetchJeSchedules, exports.fetchJeSchedulesFailure = _a.fetchJeSchedulesFailure, exports.fetchJeSchedulesPage = _a.fetchJeSchedulesPage, exports.fetchJeSchedulesSuccess = _a.fetchJeSchedulesSuccess, exports.fetchOneTimeAccrual = _a.fetchOneTimeAccrual, exports.fetchOneTimeAccrualFailure = _a.fetchOneTimeAccrualFailure, exports.fetchOneTimeAccrualSuccess = _a.fetchOneTimeAccrualSuccess, exports.fetchRecommendationForAccountSettings = _a.fetchRecommendationForAccountSettings, exports.ignoreRecommendedJeSchedule = _a.ignoreRecommendedJeSchedule, exports.ignoreRecommendedJeScheduleFailure = _a.ignoreRecommendedJeScheduleFailure, exports.ignoreRecommendedJeScheduleSuccess = _a.ignoreRecommendedJeScheduleSuccess, exports.initializeAccountSettingsView = _a.initializeAccountSettingsView, exports.initializeJeScheduleLocalData = _a.initializeJeScheduleLocalData, exports.initializeNewSchedule = _a.initializeNewSchedule, exports.removeFailedJeScheduleTransactionKey = _a.removeFailedJeScheduleTransactionKey, exports.removeJeOneTimeAccrualLocalData = _a.removeJeOneTimeAccrualLocalData, exports.removeJeScheduleLocalDataById = _a.removeJeScheduleLocalDataById, exports.removeJeAccruedScheduleKey = _a.removeJeAccruedScheduleKey, exports.removeJeScheduleTransactionKey = _a.removeJeScheduleTransactionKey, exports.resetNewScheduleLocalData = _a.resetNewScheduleLocalData, exports.retryJeSchedule = _a.retryJeSchedule, exports.retryJeScheduleFailure = _a.retryJeScheduleFailure, exports.retryJeScheduleSuccess = _a.retryJeScheduleSuccess, exports.saveAccountSettings = _a.saveAccountSettings, exports.saveAccountSettingsFailure = _a.saveAccountSettingsFailure, exports.saveAccountSettingsLocalData = _a.saveAccountSettingsLocalData, exports.saveAccountSettingsSuccess = _a.saveAccountSettingsSuccess, exports.saveNewSchedule = _a.saveNewSchedule, exports.saveNewScheduleFailure = _a.saveNewScheduleFailure, exports.saveNewScheduleSuccess = _a.saveNewScheduleSuccess, exports.searchTransactionsForNewSchedule = _a.searchTransactionsForNewSchedule, exports.searchTransactionsForNewScheduleFailure = _a.searchTransactionsForNewScheduleFailure, exports.searchTransactionsForNewScheduleSuccess = _a.searchTransactionsForNewScheduleSuccess, exports.toggleJECreatedGroupCollapsed = _a.toggleJECreatedGroupCollapsed, exports.toggleJEPendingGroupCollapsed = _a.toggleJEPendingGroupCollapsed, exports.updateAccountSettingsListForAccountTypes = _a.updateAccountSettingsListForAccountTypes, exports.updateAccountSettingsListForAccountTypesFailure = _a.updateAccountSettingsListForAccountTypesFailure, exports.updateJESchedulesUIState = _a.updateJESchedulesUIState, exports.updateJEScheduleTypeFilter = _a.updateJEScheduleTypeFilter, exports.updateJeOneTimeAccrualLocalData = _a.updateJeOneTimeAccrualLocalData, exports.updateJeScheduleLocalDataById = _a.updateJeScheduleLocalDataById, exports.updateJeScheduleTransactionKeys = _a.updateJeScheduleTransactionKeys, exports.updateNewScheduleLocalData = _a.updateNewScheduleLocalData, exports.updateRecommendationForAccountSettings = _a.updateRecommendationForAccountSettings, exports.updateRecommendationForAccountSettingsFailure = _a.updateRecommendationForAccountSettingsFailure;
|
|
778
|
+
_a = expenseAutomationJESchedulesView.actions, exports.clearExpenseAutomationJESchedulesView = _a.clearExpenseAutomationJESchedulesView, exports.clearJeAccountSettingsLocalData = _a.clearJeAccountSettingsLocalData, exports.clearJeScheduleLocalData = _a.clearJeScheduleLocalData, exports.clearSearchTransactionsForNewSchedule = _a.clearSearchTransactionsForNewSchedule, exports.createOneTimeAccrual = _a.createOneTimeAccrual, exports.createOneTimeAccrualFailure = _a.createOneTimeAccrualFailure, exports.createOneTimeAccrualSuccess = _a.createOneTimeAccrualSuccess, exports.ignoreOneTimeAccrual = _a.ignoreOneTimeAccrual, exports.oneTimeAccrualActionFailure = _a.oneTimeAccrualActionFailure, exports.oneTimeAccrualActionSuccess = _a.oneTimeAccrualActionSuccess, exports.promoteOneTimeAccrual = _a.promoteOneTimeAccrual, exports.revertJeSchedule = _a.revertJeSchedule, exports.revertJeScheduleFailure = _a.revertJeScheduleFailure, exports.revertJeScheduleSuccess = _a.revertJeScheduleSuccess, exports.revertOneTimeAccrual = _a.revertOneTimeAccrual, exports.fetchAccountSettingsListForAccountTypes = _a.fetchAccountSettingsListForAccountTypes, exports.fetchJeSchedules = _a.fetchJeSchedules, exports.fetchFailedJePostings = _a.fetchFailedJePostings, exports.fetchFailedJePostingsFailure = _a.fetchFailedJePostingsFailure, exports.fetchFailedJePostingsSuccess = _a.fetchFailedJePostingsSuccess, exports.fetchJeSchedulesFailure = _a.fetchJeSchedulesFailure, exports.fetchJeSchedulesPage = _a.fetchJeSchedulesPage, exports.fetchJeSchedulesSuccess = _a.fetchJeSchedulesSuccess, exports.fetchOneTimeAccrual = _a.fetchOneTimeAccrual, exports.fetchOneTimeAccrualFailure = _a.fetchOneTimeAccrualFailure, exports.fetchOneTimeAccrualSuccess = _a.fetchOneTimeAccrualSuccess, exports.fetchRecommendationForAccountSettings = _a.fetchRecommendationForAccountSettings, exports.ignoreRecommendedJeSchedule = _a.ignoreRecommendedJeSchedule, exports.ignoreRecommendedJeScheduleFailure = _a.ignoreRecommendedJeScheduleFailure, exports.ignoreRecommendedJeScheduleSuccess = _a.ignoreRecommendedJeScheduleSuccess, exports.initializeAccountSettingsView = _a.initializeAccountSettingsView, exports.initializeJeScheduleLocalData = _a.initializeJeScheduleLocalData, exports.initializeNewSchedule = _a.initializeNewSchedule, exports.removeFailedJeScheduleTransactionKey = _a.removeFailedJeScheduleTransactionKey, exports.removeJeOneTimeAccrualLocalData = _a.removeJeOneTimeAccrualLocalData, exports.removeJeScheduleLocalDataById = _a.removeJeScheduleLocalDataById, exports.removeJeAccruedScheduleKey = _a.removeJeAccruedScheduleKey, exports.removeJeScheduleTransactionKey = _a.removeJeScheduleTransactionKey, exports.resetNewScheduleLocalData = _a.resetNewScheduleLocalData, exports.retryJeSchedule = _a.retryJeSchedule, exports.retryJeScheduleFailure = _a.retryJeScheduleFailure, exports.retryJeScheduleSuccess = _a.retryJeScheduleSuccess, exports.saveAccountSettings = _a.saveAccountSettings, exports.saveAccountSettingsFailure = _a.saveAccountSettingsFailure, exports.saveAccountSettingsLocalData = _a.saveAccountSettingsLocalData, exports.saveAccountSettingsSuccess = _a.saveAccountSettingsSuccess, exports.saveNewSchedule = _a.saveNewSchedule, exports.saveNewScheduleFailure = _a.saveNewScheduleFailure, exports.saveNewScheduleSuccess = _a.saveNewScheduleSuccess, exports.searchTransactionsForNewSchedule = _a.searchTransactionsForNewSchedule, exports.searchTransactionsForNewScheduleFailure = _a.searchTransactionsForNewScheduleFailure, exports.searchTransactionsForNewScheduleSuccess = _a.searchTransactionsForNewScheduleSuccess, exports.toggleJECreatedGroupCollapsed = _a.toggleJECreatedGroupCollapsed, exports.toggleJEFailedGroupCollapsed = _a.toggleJEFailedGroupCollapsed, exports.toggleJEPendingGroupCollapsed = _a.toggleJEPendingGroupCollapsed, exports.updateAccountSettingsListForAccountTypes = _a.updateAccountSettingsListForAccountTypes, exports.updateAccountSettingsListForAccountTypesFailure = _a.updateAccountSettingsListForAccountTypesFailure, exports.updateJESchedulesUIState = _a.updateJESchedulesUIState, exports.updateJEScheduleTypeFilter = _a.updateJEScheduleTypeFilter, exports.updateJeOneTimeAccrualLocalData = _a.updateJeOneTimeAccrualLocalData, exports.updateJeScheduleLocalDataById = _a.updateJeScheduleLocalDataById, exports.updateJeScheduleTransactionKeys = _a.updateJeScheduleTransactionKeys, exports.updateNewScheduleLocalData = _a.updateNewScheduleLocalData, exports.updateRecommendationForAccountSettings = _a.updateRecommendationForAccountSettings, exports.updateRecommendationForAccountSettingsFailure = _a.updateRecommendationForAccountSettingsFailure;
|
|
720
779
|
exports.default = expenseAutomationJESchedulesView.reducer;
|
|
721
780
|
const doUpdateRecommendationForAccountSettings = (draft, payload) => {
|
|
722
781
|
const { prepaidExpensesRecommendations, fixedAssetsRecommendations, accruedExpensesRecommendations, } = (0, accountTypeRecommendationPayload_1.mapAccountTypeRecommendationPayloadToAccountRecommendationByType)(payload);
|
|
@@ -47,6 +47,7 @@ export interface ExpenseAutomationJESchedulesViewSelector extends SelectorView {
|
|
|
47
47
|
completionStatus: CompletionStatusType;
|
|
48
48
|
createdSchedules: JEScheduleRow[];
|
|
49
49
|
createdTotal: number;
|
|
50
|
+
failedPostings: JEScheduledTransactionWithFailedEntries[];
|
|
50
51
|
hasLoadedForSelectedTab: boolean;
|
|
51
52
|
ignoreStatusById: Record<JEScheduleTransactionKey, FetchStateAndError>;
|
|
52
53
|
jeScheduleLocalDataById: Record<ID, JEScheduleLocalData>;
|
|
@@ -61,6 +62,7 @@ export interface ExpenseAutomationJESchedulesViewSelector extends SelectorView {
|
|
|
61
62
|
pendingReviewTotal: number;
|
|
62
63
|
postStatusById: Record<ID, FetchStateAndError>;
|
|
63
64
|
refreshStatus: FetchStateAndError;
|
|
65
|
+
/** @deprecated Alias of `failedPostings`. Remove once webc and app-ui are repointed. */
|
|
64
66
|
resolveSchedules: JEScheduledTransactionWithFailedEntries[];
|
|
65
67
|
revertStatusById: Record<JEScheduleKey | JEScheduleTransactionKey, FetchStateAndError>;
|
|
66
68
|
scheduleCountsByTab: Partial<Record<JEPageTab, number>>;
|
|
@@ -225,7 +225,7 @@ function getExpenseAutomationJESchedulesView(state) {
|
|
|
225
225
|
const accruedSchedules = [];
|
|
226
226
|
const oneTimeAccruals = [];
|
|
227
227
|
const { accountState, accountListState, classState, classListState, expenseAutomationJESchedulesViewState, expenseAutomationViewState, monthEndCloseChecksState, } = state;
|
|
228
|
-
const { jeScheduleTransactionKeysByPeriodAndTab, jeScheduleAccruedKeysByPeriodAndTab, jeScheduleOneTimeAccrualKeysByPeriodAndTab,
|
|
228
|
+
const { jeScheduleTransactionKeysByPeriodAndTab, jeScheduleAccruedKeysByPeriodAndTab, jeScheduleOneTimeAccrualKeysByPeriodAndTab, failedJePostings, jeScheduleLocalDataById, postStatusById, ignoreStatusById, revertStatusById, oneTimeAccrualActionStatusById, uiState, error, fetchState, refreshStatus, newSchedule, } = expenseAutomationJESchedulesViewState;
|
|
229
229
|
const accountSettingsView = (0, jeAccountSettingsViewSelector_1.getJEAccountSettingsView)(state);
|
|
230
230
|
const newScheduleView = newSchedule.selectedDetailScheduleType === 'fixed_assets' ||
|
|
231
231
|
newSchedule.selectedDetailScheduleType === 'prepaid_expenses'
|
|
@@ -264,15 +264,11 @@ function getExpenseAutomationJESchedulesView(state) {
|
|
|
264
264
|
const jeScheduleTransactionKeysForSelectedTab = selectedPeriodTabKey != null
|
|
265
265
|
? jeScheduleTransactionKeysByPeriodAndTab[selectedPeriodTabKey]
|
|
266
266
|
: undefined;
|
|
267
|
-
const failedJeScheduleTransactionKeysForSelectedTab = selectedPeriodTabKey != null
|
|
268
|
-
? failedJeScheduleTransactionKeysByPeriodAndTab[selectedPeriodTabKey]
|
|
269
|
-
: undefined;
|
|
270
267
|
// Distinguishes "this tab has never been fetched for this period" from "fetched and genuinely
|
|
271
268
|
// empty". Without it the page cannot tell a first visit from a real empty state, and renders an
|
|
272
269
|
// empty table where it should render a skeleton.
|
|
273
270
|
const hasLoadedForSelectedTab = jeScheduleTransactionKeysForSelectedTab != null;
|
|
274
271
|
const jeScheduleTransactionKeys = jeScheduleTransactionKeysForSelectedTab ?? [];
|
|
275
|
-
const failedJeScheduleTransactionKeys = failedJeScheduleTransactionKeysForSelectedTab ?? [];
|
|
276
272
|
const jeScheduleAccruedKeys = (selectedPeriodTabKey != null
|
|
277
273
|
? jeScheduleAccruedKeysByPeriodAndTab[selectedPeriodTabKey]
|
|
278
274
|
: undefined) ?? [];
|
|
@@ -295,24 +291,34 @@ function getExpenseAutomationJESchedulesView(state) {
|
|
|
295
291
|
accruedSchedules.push(accruedScheduleDetails);
|
|
296
292
|
}
|
|
297
293
|
});
|
|
298
|
-
|
|
294
|
+
// Sourced from the tenant-wide bucket, not the per-period one: a failed posting belongs to no
|
|
295
|
+
// close month, and windowing it is what kept older failures off the only tab that can resolve
|
|
296
|
+
// them.
|
|
297
|
+
failedJePostings.jeScheduleTransactionKeys.forEach((jeScheduleKey) => {
|
|
299
298
|
const jeScheduleDetails = (0, jeSchedulesSelector_1.getJEScheduledTransactionByJEScheduleTransactionKey)(jeScheduleKey, state);
|
|
300
299
|
failedJeScheduledTransaction.push(jeScheduleDetails);
|
|
301
300
|
});
|
|
302
301
|
const { sortKey, sortOrder, selectedJETypeFilter } = uiState;
|
|
302
|
+
const matchesTypeFilter = (schedule) => selectedJETypeFilter == null ||
|
|
303
|
+
getJEScheduleRowType(schedule) === selectedJETypeFilter;
|
|
303
304
|
const unsortedResolveSchedules = [];
|
|
304
305
|
failedJeScheduledTransaction.forEach((schedule) => {
|
|
305
|
-
|
|
306
|
+
// Only the entries that actually carry an error. The schedule's entry array is shared state:
|
|
307
|
+
// opening a schedule's detail page or Quick View replaces it with every month the schedule
|
|
308
|
+
// has, posted ones included, so fanning out over all of them turned one failed posting into a
|
|
309
|
+
// row per month -- and a month that never failed has nothing to resolve, so it rendered with
|
|
310
|
+
// an empty action column. Keying on `error` also makes the list self-correcting: an entry the
|
|
311
|
+
// server no longer reports as failing drops out on the next fetch.
|
|
312
|
+
schedule.scheduledJournalEntry
|
|
313
|
+
.filter((journalEntry) => journalEntry.error.length > 0)
|
|
314
|
+
.forEach((journalEntry) => {
|
|
306
315
|
unsortedResolveSchedules.push({
|
|
307
316
|
...schedule,
|
|
308
317
|
scheduledJournalEntry: journalEntry,
|
|
309
318
|
});
|
|
310
319
|
});
|
|
311
320
|
});
|
|
312
|
-
const resolveSchedules = sortJEScheduledTransactions(unsortedResolveSchedules, sortKey, sortOrder);
|
|
313
|
-
const validResolveForPending = unsortedResolveSchedules.filter((r) => jeScheduleLocalDataById[r.scheduledJournalEntry.scheduledJournalEntryID] != null);
|
|
314
|
-
const matchesTypeFilter = (schedule) => selectedJETypeFilter == null ||
|
|
315
|
-
getJEScheduleRowType(schedule) === selectedJETypeFilter;
|
|
321
|
+
const resolveSchedules = sortJEScheduledTransactions(unsortedResolveSchedules.filter(matchesTypeFilter), sortKey, sortOrder);
|
|
316
322
|
const isCreatedStatus = (schedule) => {
|
|
317
323
|
// An accrual is "created" once it is not review work: posted, reversing, reversed, or in a
|
|
318
324
|
// transient posting claim.
|
|
@@ -330,7 +336,6 @@ function getExpenseAutomationJESchedulesView(state) {
|
|
|
330
336
|
];
|
|
331
337
|
const pendingReviewSchedules = sortJEScheduledTransactions([
|
|
332
338
|
...allScheduleRows.filter((schedule) => isPendingReviewRow(schedule) && matchesTypeFilter(schedule)),
|
|
333
|
-
...validResolveForPending,
|
|
334
339
|
], sortKey, sortOrder);
|
|
335
340
|
const createdSchedules = sortJEScheduledTransactions(allScheduleRows.filter((schedule) => isCreatedStatus(schedule) && matchesTypeFilter(schedule)), sortKey, sortOrder);
|
|
336
341
|
// KPI summary — derived from unfiltered schedules so counts are always accurate
|
|
@@ -449,6 +454,9 @@ function getExpenseAutomationJESchedulesView(state) {
|
|
|
449
454
|
kpiSummary,
|
|
450
455
|
pendingReviewSchedules,
|
|
451
456
|
pendingReviewTotal,
|
|
457
|
+
failedPostings: resolveSchedules,
|
|
458
|
+
// Deprecated alias of failedPostings. Still read by the section's footer-form effect and by
|
|
459
|
+
// app-ui analytics; remove once both are repointed.
|
|
452
460
|
resolveSchedules: resolveSchedules,
|
|
453
461
|
accountSettingsView,
|
|
454
462
|
newScheduleView,
|
|
@@ -19,6 +19,7 @@ export type JESchedulePeriodTabKey = `${JEPageTab}_${MonthYearPeriodId}`;
|
|
|
19
19
|
export declare const getJESchedulePeriodTabKey: (selectedPageTab: JEPageTab, monthYearPeriodId: MonthYearPeriodId) => JESchedulePeriodTabKey;
|
|
20
20
|
export interface JESchedulesViewUIState {
|
|
21
21
|
createdGroupCollapsed: boolean;
|
|
22
|
+
failedGroupCollapsed: boolean;
|
|
22
23
|
pendingGroupCollapsed: boolean;
|
|
23
24
|
scrollPosition: {
|
|
24
25
|
scrollTop: number;
|
|
@@ -41,8 +42,22 @@ export interface JEScheduleLocalData {
|
|
|
41
42
|
updatedClassId?: ID;
|
|
42
43
|
updatedVendor?: VendorBase;
|
|
43
44
|
}
|
|
45
|
+
/**
|
|
46
|
+
* The Failed Postings bucket, and the only list on this page that is not scoped to a period.
|
|
47
|
+
*
|
|
48
|
+
* A failed posting is broken until someone resolves it, whatever month it belongs to, so windowing
|
|
49
|
+
* it the way the schedule lists are windowed is what hid a March failure from the September close.
|
|
50
|
+
* It therefore has no period-tab key, and its own fetch state rather than the slice's: the list is
|
|
51
|
+
* fetched separately from `/1.0/expenses_automation/failed_je_postings`, so a slow or failing
|
|
52
|
+
* lookup here must not blank the schedules table, or vice versa.
|
|
53
|
+
*/
|
|
54
|
+
export interface FailedJePostingsState {
|
|
55
|
+
fetchState: FetchStateAndError;
|
|
56
|
+
jeScheduleTransactionKeys: JEScheduleTransactionKey[];
|
|
57
|
+
}
|
|
44
58
|
export interface JESchedulesViewState extends FetchedState {
|
|
45
59
|
accountSettings: AccountSettingsState;
|
|
60
|
+
failedJePostings: FailedJePostingsState;
|
|
46
61
|
failedJeScheduleTransactionKeysByPeriodAndTab: Record<JESchedulePeriodTabKey, JEScheduleTransactionKey[]>;
|
|
47
62
|
ignoreStatusById: Record<JEScheduleTransactionKey, FetchStateAndError>;
|
|
48
63
|
jeScheduleAccruedKeysByPeriodAndTab: Record<JESchedulePeriodTabKey, JEScheduleKey[]>;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@zeniai/client-epic-state",
|
|
3
|
-
"version": "5.2.
|
|
3
|
+
"version": "5.2.52-betaRD1",
|
|
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",
|