@zeniai/client-epic-state 5.2.22-betaAM1 → 5.2.22-betaRD0
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/jeSchedulesPayload.d.ts +0 -24
- package/lib/entity/jeSchedules/jeSchedulesPayload.js +0 -40
- package/lib/entity/jeSchedules/jeSchedulesState.d.ts +0 -26
- package/lib/epic.d.ts +2 -6
- package/lib/epic.js +2 -10
- package/lib/esm/entity/jeSchedules/jeSchedulesPayload.js +0 -40
- package/lib/esm/epic.js +2 -10
- package/lib/esm/index.js +4 -8
- package/lib/esm/reducer.js +0 -3
- package/lib/esm/view/expenseAutomationView/epics/common/fetchAllExpenseAutomationTabsEpic.js +11 -28
- package/lib/esm/view/expenseAutomationView/epics/common/refreshExpenseAutomationCurrentTabEpic.js +1 -9
- package/lib/esm/view/expenseAutomationView/epics/jeSchedule/fetchJeSchedulesEpic.js +45 -7
- package/lib/esm/view/expenseAutomationView/epics/jeSchedule/oneTimeAccrualActionsEpic.js +13 -6
- package/lib/esm/view/expenseAutomationView/epics/jeSchedule/prefetchOtherJeSchedulesTabEpic.js +35 -0
- package/lib/esm/view/expenseAutomationView/epics/jeSchedule/switchJESchedulesTabEpic.js +0 -5
- package/lib/esm/view/expenseAutomationView/expenseAutomationViewSelector.js +7 -22
- package/lib/esm/view/expenseAutomationView/payload/jeSchedulesPayload.js +1 -1
- package/lib/esm/view/expenseAutomationView/reducers/jeSchedulesViewReducer.js +31 -7
- package/lib/esm/view/expenseAutomationView/selectors/jeSchedulesViewSelector.js +1 -3
- package/lib/esm/view/expenseAutomationView/types/jeSchedulesViewState.js +1 -5
- package/lib/index.d.ts +6 -11
- package/lib/index.js +49 -73
- package/lib/reducer.d.ts +0 -1
- package/lib/reducer.js +0 -3
- package/lib/rootStateTypes.d.ts +0 -2
- package/lib/view/expenseAutomationView/epics/common/fetchAllExpenseAutomationTabsEpic.d.ts +1 -2
- package/lib/view/expenseAutomationView/epics/common/fetchAllExpenseAutomationTabsEpic.js +11 -28
- package/lib/view/expenseAutomationView/epics/common/refreshExpenseAutomationCurrentTabEpic.d.ts +1 -2
- package/lib/view/expenseAutomationView/epics/common/refreshExpenseAutomationCurrentTabEpic.js +1 -9
- package/lib/view/expenseAutomationView/epics/jeSchedule/fetchJeSchedulesEpic.d.ts +1 -1
- package/lib/view/expenseAutomationView/epics/jeSchedule/fetchJeSchedulesEpic.js +45 -7
- package/lib/view/expenseAutomationView/epics/jeSchedule/oneTimeAccrualActionsEpic.d.ts +2 -2
- package/lib/view/expenseAutomationView/epics/jeSchedule/oneTimeAccrualActionsEpic.js +12 -5
- package/lib/view/expenseAutomationView/epics/jeSchedule/prefetchOtherJeSchedulesTabEpic.d.ts +12 -0
- package/lib/view/expenseAutomationView/epics/jeSchedule/prefetchOtherJeSchedulesTabEpic.js +39 -0
- package/lib/view/expenseAutomationView/epics/jeSchedule/switchJESchedulesTabEpic.d.ts +1 -2
- package/lib/view/expenseAutomationView/epics/jeSchedule/switchJESchedulesTabEpic.js +0 -5
- package/lib/view/expenseAutomationView/expenseAutomationViewSelector.js +7 -22
- package/lib/view/expenseAutomationView/payload/jeSchedulesPayload.d.ts +54 -1
- package/lib/view/expenseAutomationView/payload/jeSchedulesPayload.js +3 -3
- package/lib/view/expenseAutomationView/reducers/jeSchedulesViewReducer.d.ts +13 -8
- package/lib/view/expenseAutomationView/reducers/jeSchedulesViewReducer.js +33 -9
- package/lib/view/expenseAutomationView/selectorTypes/expenseAutomationViewSelectorTypes.d.ts +0 -2
- package/lib/view/expenseAutomationView/selectors/jeSchedulesViewSelector.d.ts +2 -0
- package/lib/view/expenseAutomationView/selectors/jeSchedulesViewSelector.js +1 -3
- package/lib/view/expenseAutomationView/types/jeSchedulesViewState.d.ts +3 -1
- package/lib/view/expenseAutomationView/types/jeSchedulesViewState.js +1 -5
- package/package.json +1 -1
- package/lib/esm/view/expenseAutomationView/epics/actualMatching/fetchActualMatchingEpic.js +0 -46
- package/lib/esm/view/expenseAutomationView/epics/actualMatching/fetchActualMatchingPageEpic.js +0 -7
- package/lib/esm/view/expenseAutomationView/epics/actualMatching/matchAndReverseAccrualsEpic.js +0 -50
- package/lib/esm/view/expenseAutomationView/epics/actualMatching/searchMatchAccrualsEpic.js +0 -44
- package/lib/esm/view/expenseAutomationView/epics/actualMatching/searchMatchTransactionsEpic.js +0 -44
- package/lib/esm/view/expenseAutomationView/payload/actualMatchingPayload.js +0 -60
- package/lib/esm/view/expenseAutomationView/reducers/actualMatchingViewReducer.js +0 -260
- package/lib/esm/view/expenseAutomationView/selectorTypes/actualMatchingViewSelectorTypes.js +0 -1
- package/lib/esm/view/expenseAutomationView/selectors/actualMatchingViewSelector.js +0 -200
- package/lib/esm/view/expenseAutomationView/types/actualMatchingViewState.js +0 -22
- package/lib/view/expenseAutomationView/epics/actualMatching/fetchActualMatchingEpic.d.ts +0 -9
- package/lib/view/expenseAutomationView/epics/actualMatching/fetchActualMatchingEpic.js +0 -50
- package/lib/view/expenseAutomationView/epics/actualMatching/fetchActualMatchingPageEpic.d.ts +0 -5
- package/lib/view/expenseAutomationView/epics/actualMatching/fetchActualMatchingPageEpic.js +0 -11
- package/lib/view/expenseAutomationView/epics/actualMatching/matchAndReverseAccrualsEpic.d.ts +0 -8
- package/lib/view/expenseAutomationView/epics/actualMatching/matchAndReverseAccrualsEpic.js +0 -54
- package/lib/view/expenseAutomationView/epics/actualMatching/searchMatchAccrualsEpic.d.ts +0 -8
- package/lib/view/expenseAutomationView/epics/actualMatching/searchMatchAccrualsEpic.js +0 -48
- package/lib/view/expenseAutomationView/epics/actualMatching/searchMatchTransactionsEpic.d.ts +0 -8
- package/lib/view/expenseAutomationView/epics/actualMatching/searchMatchTransactionsEpic.js +0 -48
- package/lib/view/expenseAutomationView/payload/actualMatchingPayload.d.ts +0 -72
- package/lib/view/expenseAutomationView/payload/actualMatchingPayload.js +0 -65
- package/lib/view/expenseAutomationView/reducers/actualMatchingViewReducer.d.ts +0 -53
- package/lib/view/expenseAutomationView/reducers/actualMatchingViewReducer.js +0 -264
- package/lib/view/expenseAutomationView/selectorTypes/actualMatchingViewSelectorTypes.d.ts +0 -59
- package/lib/view/expenseAutomationView/selectorTypes/actualMatchingViewSelectorTypes.js +0 -2
- package/lib/view/expenseAutomationView/selectors/actualMatchingViewSelector.d.ts +0 -11
- package/lib/view/expenseAutomationView/selectors/actualMatchingViewSelector.js +0 -212
- package/lib/view/expenseAutomationView/types/actualMatchingViewState.d.ts +0 -81
- package/lib/view/expenseAutomationView/types/actualMatchingViewState.js +0 -27
package/lib/esm/view/expenseAutomationView/epics/common/fetchAllExpenseAutomationTabsEpic.js
CHANGED
|
@@ -3,7 +3,6 @@ import { filter, switchMap } from 'rxjs/operators';
|
|
|
3
3
|
import { convertToPeriod, toAbsoluteDay, toMonthYearPeriodId, } from '../../../../commonStateTypes/timePeriod';
|
|
4
4
|
import { getCurrentTenant } from '../../../../entity/tenant/tenantSelector';
|
|
5
5
|
import { fetchAllExpenseAutomationTabs } from '../../expenseAutomationViewReducer';
|
|
6
|
-
import { fetchActualMatchingPage } from '../../reducers/actualMatchingViewReducer';
|
|
7
6
|
import { fetchFluxAnalysisView } from '../../reducers/fluxAnalysisViewReducer';
|
|
8
7
|
import { fetchJeSchedulesPage } from '../../reducers/jeSchedulesViewReducer';
|
|
9
8
|
import { fetchMissingReceipts } from '../../reducers/missingReceiptsViewReducer';
|
|
@@ -32,14 +31,11 @@ export const fetchAllExpenseAutomationTabsEpic = (actions$, state$) => actions$.
|
|
|
32
31
|
}
|
|
33
32
|
if (cacheOverride === true) {
|
|
34
33
|
const actions = [];
|
|
35
|
-
const selectedPageTab = state.expenseAutomationJESchedulesViewState.uiState.selectedPageTab;
|
|
36
34
|
actions.push(fetchTransactionCategorizationView(selectedTransactionCategorizationTab, { start: timePeriodStart, end: timePeriodEnd }, cacheOverride, false, undefined, undefined, refreshViewInBackground, false), fetchMissingReceipts({ start: timePeriodStart, end: timePeriodEnd }, {
|
|
37
35
|
amount: 75.0,
|
|
38
36
|
currencyCode: 'USD',
|
|
39
37
|
currencySymbol: '$',
|
|
40
|
-
}, cacheOverride, refreshViewInBackground), fetchFluxAnalysisView(selectedPeriod, cacheOverride, refreshViewInBackground, null),
|
|
41
|
-
? fetchActualMatchingPage({ start: timePeriodStart, end: timePeriodEnd }, cacheOverride)
|
|
42
|
-
: fetchJeSchedulesPage({ start: timePeriodStart, end: timePeriodEnd }, cacheOverride));
|
|
38
|
+
}, cacheOverride, refreshViewInBackground), fetchFluxAnalysisView(selectedPeriod, cacheOverride, refreshViewInBackground, null), fetchJeSchedulesPage({ start: timePeriodStart, end: timePeriodEnd }, cacheOverride));
|
|
43
39
|
if (reconciliationEnabled) {
|
|
44
40
|
actions.push(fetchReconciliation(selectedPeriod, undefined, cacheOverride, refreshViewInBackground));
|
|
45
41
|
}
|
|
@@ -65,29 +61,16 @@ export const fetchAllExpenseAutomationTabsEpic = (actions$, state$) => actions$.
|
|
|
65
61
|
fetchActions.push(fetchFluxAnalysisView(selectedPeriod, cacheOverride, refreshViewInBackground, null));
|
|
66
62
|
}
|
|
67
63
|
// The two JE tabs cache separately, so only the tab actually being shown decides whether a
|
|
68
|
-
// fetch is still needed.
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
}
|
|
79
|
-
}
|
|
80
|
-
else {
|
|
81
|
-
const jeSchedulesPeriodTabKey = getJESchedulePeriodTabKey(selectedPageTab, monthYearPeriodId);
|
|
82
|
-
if (state.expenseAutomationJESchedulesViewState.fetchState !==
|
|
83
|
-
'In-Progress' &&
|
|
84
|
-
(!state.expenseAutomationJESchedulesViewState.hasValidState() ||
|
|
85
|
-
state.expenseAutomationJESchedulesViewState
|
|
86
|
-
.jeScheduleTransactionKeysByPeriodAndTab[jeSchedulesPeriodTabKey] == null ||
|
|
87
|
-
state.expenseAutomationJESchedulesViewState
|
|
88
|
-
.failedJeScheduleTransactionKeysByPeriodAndTab[jeSchedulesPeriodTabKey] == null)) {
|
|
89
|
-
fetchActions.push(fetchJeSchedulesPage({ start: timePeriodStart, end: timePeriodEnd }, cacheOverride));
|
|
90
|
-
}
|
|
64
|
+
// fetch is still needed.
|
|
65
|
+
const jeSchedulesPeriodTabKey = getJESchedulePeriodTabKey(state.expenseAutomationJESchedulesViewState.uiState.selectedPageTab, monthYearPeriodId);
|
|
66
|
+
if (state.expenseAutomationJESchedulesViewState.fetchState !==
|
|
67
|
+
'In-Progress' &&
|
|
68
|
+
(!state.expenseAutomationJESchedulesViewState.hasValidState() ||
|
|
69
|
+
state.expenseAutomationJESchedulesViewState
|
|
70
|
+
.jeScheduleTransactionKeysByPeriodAndTab[jeSchedulesPeriodTabKey] == null ||
|
|
71
|
+
state.expenseAutomationJESchedulesViewState
|
|
72
|
+
.failedJeScheduleTransactionKeysByPeriodAndTab[jeSchedulesPeriodTabKey] == null)) {
|
|
73
|
+
fetchActions.push(fetchJeSchedulesPage({ start: timePeriodStart, end: timePeriodEnd }, cacheOverride));
|
|
91
74
|
}
|
|
92
75
|
if (state.expenseAutomationReconciliationViewState.fetchState !==
|
|
93
76
|
'In-Progress' &&
|
package/lib/esm/view/expenseAutomationView/epics/common/refreshExpenseAutomationCurrentTabEpic.js
CHANGED
|
@@ -4,7 +4,6 @@ import { convertToPeriod, toAbsoluteDay, } from '../../../../commonStateTypes/ti
|
|
|
4
4
|
import { getCurrentTenant } from '../../../../entity/tenant/tenantSelector';
|
|
5
5
|
import { fetchCompanyMonthEndReportTemplates, fetchCompanyMonthEndReportView, } from '../../../companyMonthEndReportView/companyMonthEndReportViewReducer';
|
|
6
6
|
import { refreshExpenseAutomationCurrentTab } from '../../expenseAutomationViewReducer';
|
|
7
|
-
import { fetchActualMatchingPage } from '../../reducers/actualMatchingViewReducer';
|
|
8
7
|
import { fetchFluxAnalysisView } from '../../reducers/fluxAnalysisViewReducer';
|
|
9
8
|
import { fetchJeSchedulesPage } from '../../reducers/jeSchedulesViewReducer';
|
|
10
9
|
import { fetchMissingReceipts } from '../../reducers/missingReceiptsViewReducer';
|
|
@@ -39,17 +38,10 @@ export const refreshExpenseAutomationCurrentTabEpic = (actions$, state$) => acti
|
|
|
39
38
|
return from([
|
|
40
39
|
fetchFluxAnalysisView(selectedPeriod, true, true, null),
|
|
41
40
|
]);
|
|
42
|
-
case 'je_schedules':
|
|
43
|
-
const selectedPageTab = state.expenseAutomationJESchedulesViewState.uiState.selectedPageTab;
|
|
44
|
-
if (selectedPageTab === 'actual_matching') {
|
|
45
|
-
return from([
|
|
46
|
-
fetchActualMatchingPage({ start: timePeriodStart, end: timePeriodEnd }, true),
|
|
47
|
-
]);
|
|
48
|
-
}
|
|
41
|
+
case 'je_schedules':
|
|
49
42
|
return from([
|
|
50
43
|
fetchJeSchedulesPage({ start: timePeriodStart, end: timePeriodEnd }, true),
|
|
51
44
|
]);
|
|
52
|
-
}
|
|
53
45
|
case 'month_end_insights':
|
|
54
46
|
return from([
|
|
55
47
|
fetchCompanyMonthEndReportView(true, companyId, currentTenant.tenantId, period.end, true),
|
|
@@ -7,6 +7,7 @@ import { getCurrentTenant } from '../../../../entity/tenant/tenantSelector';
|
|
|
7
7
|
import { createZeniAPIStatus, isSuccessResponse, } from '../../../../responsePayload';
|
|
8
8
|
import { clearAll } from '../../../../rootActions';
|
|
9
9
|
import { date } from '../../../../zeniDayJS';
|
|
10
|
+
import { SERVICE_MONTH_FORMAT, } from '../../payload/jeSchedulesPayload';
|
|
10
11
|
import { fetchJeSchedules, fetchJeSchedulesFailure, fetchJeSchedulesSuccess, initializeJeScheduleLocalData, } from '../../reducers/jeSchedulesViewReducer';
|
|
11
12
|
export const fetchJeSchedulesEpic = (actions$, state$, zeniAPI) => actions$.pipe(filter(fetchJeSchedules.match), mergeMap((action) => {
|
|
12
13
|
const state = state$.value;
|
|
@@ -14,21 +15,58 @@ export const fetchJeSchedulesEpic = (actions$, state$, zeniAPI) => actions$.pipe
|
|
|
14
15
|
const { period, refreshViewInBackground } = action.payload;
|
|
15
16
|
const currentTenant = getCurrentTenant(state);
|
|
16
17
|
const selectedPeriod = selectedPeriodByTenantId[currentTenant.tenantId];
|
|
17
|
-
|
|
18
|
+
// The prefetch names the tab it is warming; everything else means the visible one. Reading
|
|
19
|
+
// this from state unconditionally would make the prefetch fetch the visible tab's window and
|
|
20
|
+
// then overwrite its cache with the result.
|
|
21
|
+
const selectedPageTab = action.payload.selectedPageTab ??
|
|
22
|
+
state.expenseAutomationJESchedulesViewState.uiState.selectedPageTab;
|
|
18
23
|
const isClosePeriodTab = selectedPageTab === 'schedules';
|
|
19
24
|
const existingEndDate = toAbsoluteDay(date(toString(period.start))
|
|
20
25
|
.subtract(1, 'month')
|
|
21
26
|
.endOf('month')
|
|
22
27
|
.format(DEFAULT_DATE_FORMAT));
|
|
28
|
+
// Existing Schedules looks at months already closed, so it stops at the previous month end;
|
|
29
|
+
// Review Schedules is closing the selected month and runs to its end.
|
|
30
|
+
const endDate = isClosePeriodTab || existingEndDate == null
|
|
31
|
+
? toString(period.end)
|
|
32
|
+
: toString(existingEndDate);
|
|
33
|
+
// Accrued rows are windowed on the schedule's own start_date rather than a transaction date,
|
|
34
|
+
// so they get their own bounds. Review wants the month being closed; Existing wants the year
|
|
35
|
+
// up to endDate, snapped to the 1st — the same window the server used to compute for itself.
|
|
36
|
+
const accruedStartDate = isClosePeriodTab
|
|
37
|
+
? toString(period.start)
|
|
38
|
+
: date(endDate)
|
|
39
|
+
.subtract(1, 'year')
|
|
40
|
+
.startOf('month')
|
|
41
|
+
.format(DEFAULT_DATE_FORMAT);
|
|
23
42
|
const queryParam = {
|
|
24
|
-
|
|
25
|
-
end_date:
|
|
26
|
-
|
|
27
|
-
|
|
43
|
+
base_transaction_end_date: endDate,
|
|
44
|
+
end_date: endDate,
|
|
45
|
+
accrued_start_date: accruedStartDate,
|
|
46
|
+
accrued_end_date: endDate,
|
|
28
47
|
include_accrued: true,
|
|
29
48
|
...(isClosePeriodTab
|
|
30
|
-
? {
|
|
31
|
-
|
|
49
|
+
? {
|
|
50
|
+
// Both types share the close month, so one bound covers them. Existing sends none,
|
|
51
|
+
// which is what keeps the differing server defaults — a year back for prepaid, five
|
|
52
|
+
// for fixed assets.
|
|
53
|
+
base_transaction_start_date: toString(period.start),
|
|
54
|
+
close_period_start_date: toString(period.start),
|
|
55
|
+
one_time_accrual_service_month: date(toString(period.start)).format(SERVICE_MONTH_FORMAT),
|
|
56
|
+
// Empty means no status filter: the month being closed is reviewed whatever state
|
|
57
|
+
// each accrual is in.
|
|
58
|
+
one_time_accrual_statuses: [],
|
|
59
|
+
filter_failed_je_postings_by_date: true,
|
|
60
|
+
}
|
|
61
|
+
: {
|
|
62
|
+
one_time_accrual_service_month_start: date(accruedStartDate).format(SERVICE_MONTH_FORMAT),
|
|
63
|
+
one_time_accrual_service_month_end: date(endDate).format(SERVICE_MONTH_FORMAT),
|
|
64
|
+
// Existing lists what actually reached the books.
|
|
65
|
+
one_time_accrual_statuses: ['posted'],
|
|
66
|
+
// A failed posting from an earlier month still needs to surface here, so this list
|
|
67
|
+
// is deliberately not windowed.
|
|
68
|
+
filter_failed_je_postings_by_date: false,
|
|
69
|
+
}),
|
|
32
70
|
};
|
|
33
71
|
return zeniAPI
|
|
34
72
|
.getJSON(`${zeniAPI.apiEndPoints.accountMicroServiceBaseUrl}/1.0/expenses_automation/je_schedules?query=${encodeURIComponent(JSON.stringify(queryParam))}`)
|
|
@@ -6,9 +6,9 @@ import { updateJEOneTimeAccruals } from '../../../../entity/jeSchedules/jeSchedu
|
|
|
6
6
|
import { getJEOneTimeAccrualByKey } from '../../../../entity/jeSchedules/jeSchedulesSelector';
|
|
7
7
|
import { openSnackbar } from '../../../../entity/snackbar/snackbarReducer';
|
|
8
8
|
import { getCurrentTenant } from '../../../../entity/tenant/tenantSelector';
|
|
9
|
-
import { clearAll } from '../../../../rootActions';
|
|
10
9
|
import { createZeniAPIStatus, isSuccessResponse, } from '../../../../responsePayload';
|
|
11
|
-
import {
|
|
10
|
+
import { clearAll } from '../../../../rootActions';
|
|
11
|
+
import { fetchJeSchedules, ignoreOneTimeAccrual, oneTimeAccrualActionFailure, oneTimeAccrualActionSuccess, promoteOneTimeAccrual, removeJeOneTimeAccrualLocalData, revertOneTimeAccrual, } from '../../reducers/jeSchedulesViewReducer';
|
|
12
12
|
/**
|
|
13
13
|
* The page the accrual came from, so a promoted or ignored row lands in the right bucket. Guarded
|
|
14
14
|
* because convertToPeriod destructures: an unset period would throw and take the epic subscription
|
|
@@ -50,8 +50,11 @@ messageSection, accrualId, message, status) {
|
|
|
50
50
|
}
|
|
51
51
|
export const promoteOneTimeAccrualEpic = (actions$, state$, zeniAPI) => actions$.pipe(filter(promoteOneTimeAccrual.match), mergeMap((action) => {
|
|
52
52
|
const state = state$.value;
|
|
53
|
-
const { accrualId, amount
|
|
53
|
+
const { accrualId, amount } = action.payload;
|
|
54
54
|
const accrual = getJEOneTimeAccrualByKey(generateJEOneTimeAccrualKey(accrualId), state.jeSchedulesState);
|
|
55
|
+
// The detail form writes what the user changed here as they change it. The list's inline
|
|
56
|
+
// Post has no form, so it finds nothing and every value below falls back to the stored draft.
|
|
57
|
+
const edits = state.expenseAutomationJESchedulesViewState.oneTimeAccrualLocalDataById[accrualId];
|
|
55
58
|
// An edited value wins; anything untouched falls back to the stored draft, which is what the
|
|
56
59
|
// list's inline Post sends.
|
|
57
60
|
const debitAccountId = edits?.jeDebitAccountId ?? accrual?.jeDebitAccountId;
|
|
@@ -65,8 +68,7 @@ export const promoteOneTimeAccrualEpic = (actions$, state$, zeniAPI) => actions$
|
|
|
65
68
|
// that never happens.
|
|
66
69
|
// Untouched falls back to the stored policy, so posting without editing cannot silently
|
|
67
70
|
// flip a scheduled reversal to on-bill-match.
|
|
68
|
-
const reverseNextMonth = edits?.reverseNextMonth ??
|
|
69
|
-
accrual?.reversalPolicy === 'scheduled_date';
|
|
71
|
+
const reverseNextMonth = edits?.reverseNextMonth ?? accrual?.reversalPolicy === 'scheduled_date';
|
|
70
72
|
const expectedReversalDate = edits?.expectedReversalDate ?? accrual?.expectedReversalDate;
|
|
71
73
|
const debitClassId = edits?.jeDebitAccountingClassId ?? accrual?.jeDebitAccountingClassId;
|
|
72
74
|
const debitClassName = edits?.jeDebitAccountingClassName ??
|
|
@@ -76,7 +78,9 @@ export const promoteOneTimeAccrualEpic = (actions$, state$, zeniAPI) => actions$
|
|
|
76
78
|
memo: edits?.memo ?? accrual?.memo ?? '',
|
|
77
79
|
je_debit_account_id: debitAccountId,
|
|
78
80
|
je_credit_account_id: creditAccountId,
|
|
79
|
-
...(debitClassId != null
|
|
81
|
+
...(debitClassId != null
|
|
82
|
+
? { je_debit_accounting_class_id: debitClassId }
|
|
83
|
+
: {}),
|
|
80
84
|
...(debitClassName != null
|
|
81
85
|
? { je_debit_accounting_class_name: debitClassName }
|
|
82
86
|
: {}),
|
|
@@ -96,6 +100,9 @@ export const promoteOneTimeAccrualEpic = (actions$, state$, zeniAPI) => actions$
|
|
|
96
100
|
return from([
|
|
97
101
|
updateJEOneTimeAccruals([response.data.accrual]),
|
|
98
102
|
oneTimeAccrualActionSuccess({ accrualId }),
|
|
103
|
+
// The edits are now on the server copy; leaving them would re-apply them to a
|
|
104
|
+
// later promote of the same accrual.
|
|
105
|
+
removeJeOneTimeAccrualLocalData({ accrualId }),
|
|
99
106
|
openSnackbar({
|
|
100
107
|
messageSection: 'save_schedule',
|
|
101
108
|
messageText: 'success',
|
package/lib/esm/view/expenseAutomationView/epics/jeSchedule/prefetchOtherJeSchedulesTabEpic.js
ADDED
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { EMPTY, of } from 'rxjs';
|
|
2
|
+
import { filter, mergeMap } from 'rxjs/operators';
|
|
3
|
+
import { toMonthYearPeriodId } from '../../../../commonStateTypes/timePeriod';
|
|
4
|
+
import { getCurrentTenant } from '../../../../entity/tenant/tenantSelector';
|
|
5
|
+
import { fetchJeSchedules, fetchJeSchedulesPage, } from '../../reducers/jeSchedulesViewReducer';
|
|
6
|
+
import { ALL_JE_PAGE_TABS, getJESchedulePeriodTabKey, } from '../../types/jeSchedulesViewState';
|
|
7
|
+
/**
|
|
8
|
+
* Warms the tab the user is not looking at, so switching to it renders rows instead of a skeleton.
|
|
9
|
+
*
|
|
10
|
+
* Listens for `fetchJeSchedulesPage` rather than `fetchJeSchedules` on purpose: the prefetch emits
|
|
11
|
+
* `fetchJeSchedules`, so listening for that would make this epic feed itself.
|
|
12
|
+
*/
|
|
13
|
+
export const prefetchOtherJeSchedulesTabEpic = (actions$, state$) => actions$.pipe(filter(fetchJeSchedulesPage.match), mergeMap((action) => {
|
|
14
|
+
const state = state$.value;
|
|
15
|
+
const { period } = action.payload;
|
|
16
|
+
const { selectedPageTab } = state.expenseAutomationJESchedulesViewState.uiState;
|
|
17
|
+
const otherPageTab = ALL_JE_PAGE_TABS.find((pageTab) => pageTab !== selectedPageTab);
|
|
18
|
+
if (otherPageTab == null) {
|
|
19
|
+
return EMPTY;
|
|
20
|
+
}
|
|
21
|
+
const currentTenant = getCurrentTenant(state);
|
|
22
|
+
const selectedPeriod = state.expenseAutomationViewState.selectedPeriodByTenantId[currentTenant.tenantId];
|
|
23
|
+
if (selectedPeriod == null) {
|
|
24
|
+
return EMPTY;
|
|
25
|
+
}
|
|
26
|
+
// Already warm for this period: without this check every tab switch would refetch the tab
|
|
27
|
+
// just left, since a switch also fires fetchJeSchedulesPage.
|
|
28
|
+
const otherPeriodTabKey = getJESchedulePeriodTabKey(otherPageTab, toMonthYearPeriodId(selectedPeriod));
|
|
29
|
+
const isOtherTabAlreadyLoaded = state.expenseAutomationJESchedulesViewState
|
|
30
|
+
.jeScheduleTransactionKeysByPeriodAndTab[otherPeriodTabKey] != null;
|
|
31
|
+
if (isOtherTabAlreadyLoaded) {
|
|
32
|
+
return EMPTY;
|
|
33
|
+
}
|
|
34
|
+
return of(fetchJeSchedules(period, true, otherPageTab));
|
|
35
|
+
}));
|
|
@@ -2,7 +2,6 @@ import { EMPTY, of } from 'rxjs';
|
|
|
2
2
|
import { filter, mergeMap } from 'rxjs/operators';
|
|
3
3
|
import { convertToPeriod, toAbsoluteDay, } from '../../../../commonStateTypes/timePeriod';
|
|
4
4
|
import { getCurrentTenant } from '../../../../entity/tenant/tenantSelector';
|
|
5
|
-
import { fetchActualMatchingPage } from '../../reducers/actualMatchingViewReducer';
|
|
6
5
|
import { fetchJeSchedulesPage, updateJESchedulesUIState, } from '../../reducers/jeSchedulesViewReducer';
|
|
7
6
|
export const switchJESchedulesTabEpic = (actions$, state$) => actions$.pipe(filter(updateJESchedulesUIState.match), filter((action) => action.payload.selectedPageTab != null), mergeMap(() => {
|
|
8
7
|
const state = state$.value;
|
|
@@ -25,9 +24,5 @@ export const switchJESchedulesTabEpic = (actions$, state$) => actions$.pipe(filt
|
|
|
25
24
|
if (timePeriodStart == null || timePeriodEnd == null) {
|
|
26
25
|
return EMPTY;
|
|
27
26
|
}
|
|
28
|
-
const { selectedPageTab } = state.expenseAutomationJESchedulesViewState.uiState;
|
|
29
|
-
if (selectedPageTab === 'actual_matching') {
|
|
30
|
-
return of(fetchActualMatchingPage({ start: timePeriodStart, end: timePeriodEnd }, true));
|
|
31
|
-
}
|
|
32
27
|
return of(fetchJeSchedulesPage({ start: timePeriodStart, end: timePeriodEnd }, true));
|
|
33
28
|
}));
|
|
@@ -4,7 +4,6 @@ import { getMonthEndCloseChecksForATenantForSelectedPeriod } from '../../entity/
|
|
|
4
4
|
import { getCurrentTenant, } from '../../entity/tenant/tenantSelector';
|
|
5
5
|
import { getCompanyMonthEndReportSelectorView } from '../companyMonthEndReportView/companyMonthEndReportViewSelector';
|
|
6
6
|
import { getMonthEndCloseChecksViewByTenantId, isMonthEndInsightDisabled, } from '../monthEndCloseChecksView/monthEndCloseChecksViewSelector';
|
|
7
|
-
import { getExpenseAutomationActualMatchingView } from './selectors/actualMatchingViewSelector';
|
|
8
7
|
import { getExpenseAutomationFluxAnalysisView } from './selectors/fluxAnalysisViewSelector';
|
|
9
8
|
import { getAllSteps } from './selectors/getAllStepsHelper';
|
|
10
9
|
import { getExpenseAutomationJESchedulesView } from './selectors/jeSchedulesViewSelector';
|
|
@@ -22,7 +21,7 @@ const isPreviousStepDisabled = (selectedTransactionCategorizationTab, allSteps,
|
|
|
22
21
|
return allSteps[stepIndex - 1].isDisabled;
|
|
23
22
|
};
|
|
24
23
|
export function getExpenseAutomationView(state) {
|
|
25
|
-
const { expenseAutomationViewState, tenantState, expenseAutomationMissingReceiptsViewState, expenseAutomationJESchedulesViewState,
|
|
24
|
+
const { expenseAutomationViewState, tenantState, expenseAutomationMissingReceiptsViewState, expenseAutomationJESchedulesViewState, expenseAutomationTransactionsViewState, expenseAutomationReconciliationViewState, monthEndCloseChecksState, companyState, } = state;
|
|
26
25
|
const { loggedInUser, currentTenantId } = tenantState;
|
|
27
26
|
const currentTenant = getCurrentTenant(state);
|
|
28
27
|
const { currentSelectedView, selectedPeriodByTenantId } = expenseAutomationViewState;
|
|
@@ -43,7 +42,6 @@ export function getExpenseAutomationView(state) {
|
|
|
43
42
|
const reconciliation = getExpenseAutomationReconciliationView(state);
|
|
44
43
|
const expenseAutomationTransactionsView = getExpenseAutomationTransactionView(state);
|
|
45
44
|
const jeSchedules = getExpenseAutomationJESchedulesView(state);
|
|
46
|
-
const actualMatching = getExpenseAutomationActualMatchingView(state);
|
|
47
45
|
switch (currentSelectedView) {
|
|
48
46
|
case 'reconciliation':
|
|
49
47
|
currentSelectedViewFetchState = reconciliation.fetchStatus;
|
|
@@ -56,23 +54,12 @@ export function getExpenseAutomationView(state) {
|
|
|
56
54
|
fluxAnalysis.refreshStatus;
|
|
57
55
|
break;
|
|
58
56
|
case 'je_schedules':
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
currentSelectedViewBackgroundRefreshFetchState =
|
|
66
|
-
actualMatching.refreshStatus;
|
|
67
|
-
}
|
|
68
|
-
else {
|
|
69
|
-
currentSelectedViewFetchState = {
|
|
70
|
-
fetchState: jeSchedules.fetchState,
|
|
71
|
-
error: jeSchedules.error,
|
|
72
|
-
};
|
|
73
|
-
currentSelectedViewBackgroundRefreshFetchState =
|
|
74
|
-
jeSchedules.refreshStatus;
|
|
75
|
-
}
|
|
57
|
+
currentSelectedViewFetchState = {
|
|
58
|
+
fetchState: jeSchedules.fetchState,
|
|
59
|
+
error: jeSchedules.error,
|
|
60
|
+
};
|
|
61
|
+
currentSelectedViewBackgroundRefreshFetchState =
|
|
62
|
+
jeSchedules.refreshStatus;
|
|
76
63
|
break;
|
|
77
64
|
case 'missing_receipts':
|
|
78
65
|
currentSelectedViewFetchState = {
|
|
@@ -104,7 +91,6 @@ export function getExpenseAutomationView(state) {
|
|
|
104
91
|
const fetchStateVariables = [
|
|
105
92
|
expenseAutomationMissingReceiptsViewState,
|
|
106
93
|
expenseAutomationJESchedulesViewState,
|
|
107
|
-
expenseAutomationActualMatchingViewState,
|
|
108
94
|
expenseAutomationTransactionsView,
|
|
109
95
|
expenseAutomationReconciliationViewState,
|
|
110
96
|
];
|
|
@@ -190,7 +176,6 @@ export function getExpenseAutomationView(state) {
|
|
|
190
176
|
]);
|
|
191
177
|
return {
|
|
192
178
|
jeSchedules,
|
|
193
|
-
actualMatching,
|
|
194
179
|
transactionView: expenseAutomationTransactionsView,
|
|
195
180
|
missingReceipts,
|
|
196
181
|
reconciliation,
|
|
@@ -2,7 +2,7 @@ import { DEFAULT_DATE_FORMAT } from '../../../commonStateTypes/timePeriod';
|
|
|
2
2
|
import { getClassList } from '../../classList/classListSelector';
|
|
3
3
|
import { mapScheduleTransactionToBaseScheduleTransactionPayload, mapVendorToVendorPayload, } from '../../scheduleView/scheduleDetailView/scheduleDetailPayload';
|
|
4
4
|
const BALANCE_SHEET_CLASS_LABEL = 'balance_sheet';
|
|
5
|
-
const SERVICE_MONTH_FORMAT = 'YYYY-MM';
|
|
5
|
+
export const SERVICE_MONTH_FORMAT = 'YYYY-MM';
|
|
6
6
|
/**
|
|
7
7
|
* The credit line is the accrued liability, which always sits on the balance sheet — the
|
|
8
8
|
* recurring accrued path resolves the same class the same way (see
|
|
@@ -66,6 +66,7 @@ export const initialState = {
|
|
|
66
66
|
ignoreStatusById: {},
|
|
67
67
|
revertStatusById: {},
|
|
68
68
|
jeScheduleLocalDataById: {},
|
|
69
|
+
oneTimeAccrualLocalDataById: {},
|
|
69
70
|
oneTimeAccrualActionStatusById: {},
|
|
70
71
|
oneTimeAccrualFetchStatusById: {},
|
|
71
72
|
uiState: {
|
|
@@ -127,11 +128,15 @@ const expenseAutomationJESchedulesView = createSlice({
|
|
|
127
128
|
draft.error = undefined;
|
|
128
129
|
}
|
|
129
130
|
},
|
|
130
|
-
|
|
131
|
+
// `selectedPageTab` is for the prefetch, which fetches the tab the user is NOT on. Everyone
|
|
132
|
+
// else omits it and the epic uses the selected tab -- passing the visible tab explicitly
|
|
133
|
+
// would be the same thing.
|
|
134
|
+
prepare(period, refreshViewInBackground = false, selectedPageTab) {
|
|
131
135
|
return {
|
|
132
136
|
payload: {
|
|
133
137
|
period,
|
|
134
138
|
refreshViewInBackground,
|
|
139
|
+
selectedPageTab,
|
|
135
140
|
},
|
|
136
141
|
};
|
|
137
142
|
},
|
|
@@ -399,6 +404,24 @@ const expenseAutomationJESchedulesView = createSlice({
|
|
|
399
404
|
const { scheduledJournalEntryID } = action.payload;
|
|
400
405
|
delete draft.jeScheduleLocalDataById[scheduledJournalEntryID];
|
|
401
406
|
},
|
|
407
|
+
/**
|
|
408
|
+
* Merge, not replace: the detail form reports one field at a time, so a full overwrite would
|
|
409
|
+
* drop every other edit on each keystroke.
|
|
410
|
+
*/
|
|
411
|
+
updateJeOneTimeAccrualLocalData(draft, action) {
|
|
412
|
+
const { accrualId, localData } = action.payload;
|
|
413
|
+
draft.oneTimeAccrualLocalDataById = {
|
|
414
|
+
...draft.oneTimeAccrualLocalDataById,
|
|
415
|
+
[accrualId]: {
|
|
416
|
+
...draft.oneTimeAccrualLocalDataById[accrualId],
|
|
417
|
+
...localData,
|
|
418
|
+
},
|
|
419
|
+
};
|
|
420
|
+
},
|
|
421
|
+
/** Called when the detail page unmounts and after a successful promote. */
|
|
422
|
+
removeJeOneTimeAccrualLocalData(draft, action) {
|
|
423
|
+
delete draft.oneTimeAccrualLocalDataById[action.payload.accrualId];
|
|
424
|
+
},
|
|
402
425
|
initializeAccountSettingsView(draft) {
|
|
403
426
|
draft.accountSettings.localData = accountSettingsInitialState.localData;
|
|
404
427
|
},
|
|
@@ -575,13 +598,14 @@ const expenseAutomationJESchedulesView = createSlice({
|
|
|
575
598
|
};
|
|
576
599
|
},
|
|
577
600
|
/**
|
|
578
|
-
* Promote applies the body and posts in one step
|
|
579
|
-
*
|
|
580
|
-
*
|
|
601
|
+
* Promote applies the body and posts in one step. The edits it applies come from
|
|
602
|
+
* `oneTimeAccrualLocalDataById`, not from this action -- the list's inline Post has no form, so
|
|
603
|
+
* it writes no local data and the epic falls back to the stored accrual. `amount` stays on the
|
|
604
|
+
* action because both callers already have it and `OneTimeAccrualEdits` has no slot for it.
|
|
581
605
|
*/
|
|
582
606
|
promoteOneTimeAccrual: {
|
|
583
|
-
prepare(accrualId, amount
|
|
584
|
-
return { payload: { accrualId, amount
|
|
607
|
+
prepare(accrualId, amount) {
|
|
608
|
+
return { payload: { accrualId, amount } };
|
|
585
609
|
},
|
|
586
610
|
reducer(draft, action) {
|
|
587
611
|
draft.oneTimeAccrualActionStatusById[action.payload.accrualId] = {
|
|
@@ -685,7 +709,7 @@ const expenseAutomationJESchedulesView = createSlice({
|
|
|
685
709
|
});
|
|
686
710
|
},
|
|
687
711
|
});
|
|
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;
|
|
712
|
+
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, removeJeOneTimeAccrualLocalData, removeJeScheduleLocalDataById, removeJeAccruedScheduleKey, removeJeScheduleTransactionKey, resetNewScheduleLocalData, retryJeSchedule, retryJeScheduleFailure, retryJeScheduleSuccess, saveAccountSettings, saveAccountSettingsFailure, saveAccountSettingsLocalData, saveAccountSettingsSuccess, saveNewSchedule, saveNewScheduleFailure, saveNewScheduleSuccess, searchTransactionsForNewSchedule, searchTransactionsForNewScheduleFailure, searchTransactionsForNewScheduleSuccess, toggleJECreatedGroupCollapsed, toggleJEPendingGroupCollapsed, updateAccountSettingsListForAccountTypes, updateAccountSettingsListForAccountTypesFailure, updateJESchedulesUIState, updateJEScheduleTypeFilter, updateJeOneTimeAccrualLocalData, updateJeScheduleLocalDataById, updateJeScheduleTransactionKeys, updateNewScheduleLocalData, updateRecommendationForAccountSettings, updateRecommendationForAccountSettingsFailure, } = expenseAutomationJESchedulesView.actions;
|
|
689
713
|
export default expenseAutomationJESchedulesView.reducer;
|
|
690
714
|
const doUpdateRecommendationForAccountSettings = (draft, payload) => {
|
|
691
715
|
const { prepaidExpensesRecommendations, fixedAssetsRecommendations, accruedExpensesRecommendations, } = mapAccountTypeRecommendationPayloadToAccountRecommendationByType(payload);
|
|
@@ -367,9 +367,6 @@ export function getExpenseAutomationJESchedulesView(state) {
|
|
|
367
367
|
// reports undefined rather than 0, so the UI can hide the badge instead of asserting "none".
|
|
368
368
|
const scheduleCountsByTab = {};
|
|
369
369
|
ALL_JE_PAGE_TABS.forEach((pageTab) => {
|
|
370
|
-
if (pageTab === 'actual_matching') {
|
|
371
|
-
return;
|
|
372
|
-
}
|
|
373
370
|
const periodTabKey = monthYearPeriodId != null
|
|
374
371
|
? getJESchedulePeriodTabKey(pageTab, monthYearPeriodId)
|
|
375
372
|
: null;
|
|
@@ -477,5 +474,6 @@ export function getExpenseAutomationJEOneTimeAccrualDetailView(state, accrualId)
|
|
|
477
474
|
fetchState: 'Not-Started',
|
|
478
475
|
error: undefined,
|
|
479
476
|
},
|
|
477
|
+
localData: state.expenseAutomationJESchedulesViewState.oneTimeAccrualLocalDataById[accrualId],
|
|
480
478
|
};
|
|
481
479
|
}
|
|
@@ -16,11 +16,7 @@ const JE_SCHEDULE_SORT_KEYS = [
|
|
|
16
16
|
'memo',
|
|
17
17
|
];
|
|
18
18
|
export const toJEScheduleSortKey = (v) => stringToUnion(v, JE_SCHEDULE_SORT_KEYS);
|
|
19
|
-
const JE_PAGE_TABS = [
|
|
20
|
-
'schedules',
|
|
21
|
-
'actual_matching',
|
|
22
|
-
'existing_schedules',
|
|
23
|
-
];
|
|
19
|
+
const JE_PAGE_TABS = ['schedules', 'existing_schedules'];
|
|
24
20
|
export const toJEPageTab = (v) => stringToUnion(v, JE_PAGE_TABS);
|
|
25
21
|
export const ALL_JE_PAGE_TABS = JE_PAGE_TABS;
|
|
26
22
|
export const getJESchedulePeriodTabKey = (selectedPageTab, monthYearPeriodId) => `${selectedPageTab}_${monthYearPeriodId}`;
|