@zeniai/client-epic-state 5.2.30-betaRD0 → 5.2.31
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/commonStateTypes/coaBalance/classBalances/getSumOfBalancesGroupedByPeriod.js +16 -3
- package/lib/commonStateTypes/viewAndReport/reportIDHelper.d.ts +6 -0
- package/lib/commonStateTypes/viewAndReport/reportIDHelper.js +12 -1
- package/lib/commonStateTypes/viewAndReport/viewAndReport.d.ts +2 -2
- package/lib/commonStateTypes/viewAndReport/viewAndReport.js +2 -0
- package/lib/entity/accountGroup/accountGroupState.d.ts +1 -1
- package/lib/entity/class/classReducer.d.ts +4 -4
- package/lib/entity/class/classState.d.ts +1 -1
- package/lib/entity/forecast/forecastState.d.ts +1 -1
- package/lib/entity/sectionAccountsView/sectionAccountsView.d.ts +1 -1
- package/lib/entity/sectionClassesViewV2/sectionClassesView.d.ts +1 -1
- package/lib/entity/sectionClassesViewV2/sectionClassesViewEpic.js +2 -1
- package/lib/entity/sectionClassesViewV2/sectionClassesViewReducer.d.ts +2 -2
- package/lib/entity/sectionProjectView/sectionProjectView.d.ts +1 -1
- package/lib/entity/sectionProjectView/sectionProjectViewReducer.d.ts +2 -2
- package/lib/epic.d.ts +5 -1
- package/lib/epic.js +8 -0
- package/lib/esm/commonStateTypes/coaBalance/classBalances/getSumOfBalancesGroupedByPeriod.js +16 -3
- package/lib/esm/commonStateTypes/viewAndReport/reportIDHelper.js +7 -0
- package/lib/esm/commonStateTypes/viewAndReport/viewAndReport.js +2 -0
- package/lib/esm/entity/sectionClassesViewV2/sectionClassesViewEpic.js +2 -1
- package/lib/esm/epic.js +8 -0
- package/lib/esm/index.js +7 -3
- package/lib/esm/reducer.js +6 -0
- package/lib/esm/view/cashFlow/cashFlowGroupedSectionOrder.js +47 -0
- package/lib/esm/view/cashFlowClassesView/cashFlowClassesViewEpic.js +30 -0
- package/lib/esm/view/cashFlowClassesView/cashFlowClassesViewPayload.js +1 -0
- package/lib/esm/view/cashFlowClassesView/cashFlowClassesViewReducer.js +129 -0
- package/lib/esm/view/cashFlowClassesView/cashFlowClassesViewSelector.js +53 -0
- package/lib/esm/view/cashFlowClassesView/cashFlowClassesViewSelectorTypes.js +1 -0
- package/lib/esm/view/cashFlowClassesView/cashFlowClassesViewState.js +1 -0
- package/lib/esm/view/cashFlowClassesView/cashFlowForTimeframeClassesViewEpic.js +55 -0
- package/lib/esm/view/cashFlowProjectView/cashFlowForTimeframeProjectViewEpic.js +57 -0
- package/lib/esm/view/cashFlowProjectView/cashFlowProjectViewEpic.js +30 -0
- package/lib/esm/view/cashFlowProjectView/cashFlowProjectViewPayload.js +1 -0
- package/lib/esm/view/cashFlowProjectView/cashFlowProjectViewReducer.js +125 -0
- package/lib/esm/view/cashFlowProjectView/cashFlowProjectViewSelector.js +54 -0
- package/lib/esm/view/cashFlowProjectView/cashFlowProjectViewSelectorTypes.js +1 -0
- package/lib/esm/view/cashFlowProjectView/cashFlowProjectViewState.js +1 -0
- package/lib/esm/view/expenseAutomationView/epics/jeSchedule/fetchJeSchedulesEpic.js +11 -29
- package/lib/esm/view/financeStatement/financeStatementSelector.js +21 -1
- package/lib/index.d.ts +11 -3
- package/lib/index.js +71 -48
- package/lib/reducer.d.ts +2 -0
- package/lib/reducer.js +6 -0
- package/lib/rootStateTypes.d.ts +4 -0
- package/lib/view/auditReportView/auditReportViewState.d.ts +1 -1
- package/lib/view/billPayCard/billPayCardSelector.d.ts +1 -1
- package/lib/view/cardBalance/cardBalanceSelector.d.ts +1 -1
- package/lib/view/cashBalance/cashBalanceSelector.d.ts +1 -1
- package/lib/view/cashFlow/cashFlowGroupedSectionOrder.d.ts +15 -0
- package/lib/view/cashFlow/cashFlowGroupedSectionOrder.js +50 -0
- package/lib/view/cashFlowClassesView/cashFlowClassesViewEpic.d.ts +6 -0
- package/lib/view/cashFlowClassesView/cashFlowClassesViewEpic.js +34 -0
- package/lib/view/cashFlowClassesView/cashFlowClassesViewPayload.d.ts +14 -0
- package/lib/view/cashFlowClassesView/cashFlowClassesViewPayload.js +2 -0
- package/lib/view/cashFlowClassesView/cashFlowClassesViewReducer.d.ts +34 -0
- package/lib/view/cashFlowClassesView/cashFlowClassesViewReducer.js +133 -0
- package/lib/view/cashFlowClassesView/cashFlowClassesViewSelector.d.ts +7 -0
- package/lib/view/cashFlowClassesView/cashFlowClassesViewSelector.js +57 -0
- package/lib/view/cashFlowClassesView/cashFlowClassesViewSelectorTypes.d.ts +15 -0
- package/lib/view/cashFlowClassesView/cashFlowClassesViewSelectorTypes.js +2 -0
- package/lib/view/cashFlowClassesView/cashFlowClassesViewState.d.ts +23 -0
- package/lib/view/cashFlowClassesView/cashFlowClassesViewState.js +2 -0
- package/lib/view/cashFlowClassesView/cashFlowForTimeframeClassesViewEpic.d.ts +9 -0
- package/lib/view/cashFlowClassesView/cashFlowForTimeframeClassesViewEpic.js +60 -0
- package/lib/view/cashFlowProjectView/cashFlowForTimeframeProjectViewEpic.d.ts +10 -0
- package/lib/view/cashFlowProjectView/cashFlowForTimeframeProjectViewEpic.js +62 -0
- package/lib/view/cashFlowProjectView/cashFlowProjectViewEpic.d.ts +6 -0
- package/lib/view/cashFlowProjectView/cashFlowProjectViewEpic.js +34 -0
- package/lib/view/cashFlowProjectView/cashFlowProjectViewPayload.d.ts +14 -0
- package/lib/view/cashFlowProjectView/cashFlowProjectViewPayload.js +2 -0
- package/lib/view/cashFlowProjectView/cashFlowProjectViewReducer.d.ts +33 -0
- package/lib/view/cashFlowProjectView/cashFlowProjectViewReducer.js +129 -0
- package/lib/view/cashFlowProjectView/cashFlowProjectViewSelector.d.ts +7 -0
- package/lib/view/cashFlowProjectView/cashFlowProjectViewSelector.js +58 -0
- package/lib/view/cashFlowProjectView/cashFlowProjectViewSelectorTypes.d.ts +19 -0
- package/lib/view/cashFlowProjectView/cashFlowProjectViewSelectorTypes.js +2 -0
- package/lib/view/cashFlowProjectView/cashFlowProjectViewState.d.ts +22 -0
- package/lib/view/cashFlowProjectView/cashFlowProjectViewState.js +2 -0
- package/lib/view/cashInCashOut/cashInCashOutSelector.d.ts +1 -1
- package/lib/view/cashPosition/cashPositionSelector.d.ts +1 -1
- package/lib/view/dashboard/dashboardReducer.d.ts +2 -2
- package/lib/view/expenseAutomationView/epics/jeSchedule/fetchJeSchedulesEpic.js +11 -29
- package/lib/view/financeStatement/financeStatementReducer.d.ts +1 -1
- package/lib/view/financeStatement/financeStatementSelector.d.ts +4 -0
- package/lib/view/financeStatement/financeStatementSelector.js +21 -1
- package/lib/view/globalMerchantView/globalMerchantViewReducer.d.ts +2 -2
- package/lib/view/reimbursementCard/reimbursementCardSelector.d.ts +1 -1
- package/lib/view/reportsResync/reportsResyncReducer.d.ts +2 -2
- package/lib/view/tasksCard/tasksCardSelector.d.ts +1 -1
- package/lib/view/topEx/topExSelector.d.ts +1 -1
- package/package.json +1 -1
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
import { createSlice } from '@reduxjs/toolkit';
|
|
2
|
+
import { mapReportPayloadV2ToReportV2 } from '../../commonPayloadTypes/v2/viewAndReportPayloadv2';
|
|
3
|
+
import { geNestedClassIDHierarchyForReport } from '../../commonStateTypes/classesView/getNestedClassIDHierarchyForReport';
|
|
4
|
+
import { toClassMetadata } from '../../entity/class/classPayload';
|
|
5
|
+
import { clearAll } from '../../rootActions';
|
|
6
|
+
export const initialState = {
|
|
7
|
+
classHierarchy: [],
|
|
8
|
+
bookCloseDate: undefined,
|
|
9
|
+
fetchState: {
|
|
10
|
+
month: {
|
|
11
|
+
fetchState: 'Not-Started',
|
|
12
|
+
error: undefined,
|
|
13
|
+
},
|
|
14
|
+
quarter: {
|
|
15
|
+
fetchState: 'Not-Started',
|
|
16
|
+
error: undefined,
|
|
17
|
+
},
|
|
18
|
+
year: {
|
|
19
|
+
fetchState: 'Not-Started',
|
|
20
|
+
error: undefined,
|
|
21
|
+
},
|
|
22
|
+
},
|
|
23
|
+
uiState: {
|
|
24
|
+
nodeCollapseState: {},
|
|
25
|
+
scrollPosition: undefined,
|
|
26
|
+
accountViewMode: 'account_group',
|
|
27
|
+
classesToFilterOut: [],
|
|
28
|
+
},
|
|
29
|
+
firstMonthOfFY: 1,
|
|
30
|
+
reportId: 'cash_flow_by_classes',
|
|
31
|
+
reportTitle: 'cash_flow_by_classes',
|
|
32
|
+
};
|
|
33
|
+
const cashFlowClassesView = createSlice({
|
|
34
|
+
name: 'cashFlowClassesView',
|
|
35
|
+
initialState,
|
|
36
|
+
reducers: {
|
|
37
|
+
fetchCashFlowClassesView: {
|
|
38
|
+
prepare(cacheOverride = false) {
|
|
39
|
+
return { payload: { cacheOverride } };
|
|
40
|
+
},
|
|
41
|
+
reducer(
|
|
42
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
43
|
+
_draft,
|
|
44
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
45
|
+
_action) {
|
|
46
|
+
// nothing to do here
|
|
47
|
+
},
|
|
48
|
+
},
|
|
49
|
+
fetchCashFlowForTimeframeClassesView: {
|
|
50
|
+
prepare(timeframe, cacheOverride = false) {
|
|
51
|
+
return { payload: { timeframe, cacheOverride } };
|
|
52
|
+
},
|
|
53
|
+
reducer(draft, action) {
|
|
54
|
+
const timeframe = action.payload.timeframe;
|
|
55
|
+
draft.fetchState[timeframe].fetchState = 'In-Progress';
|
|
56
|
+
draft.fetchState[timeframe].error = undefined;
|
|
57
|
+
},
|
|
58
|
+
},
|
|
59
|
+
updateCashFlowForTimeframeClassesView(draft, action) {
|
|
60
|
+
doUpdateCashFlowClassesView(draft, action.payload.timeframe, action.payload.report);
|
|
61
|
+
},
|
|
62
|
+
updateCashFlowForTimeframeClassesViewFailure: {
|
|
63
|
+
prepare(error, timeframe) {
|
|
64
|
+
return {
|
|
65
|
+
payload: {
|
|
66
|
+
error,
|
|
67
|
+
timeframe,
|
|
68
|
+
},
|
|
69
|
+
};
|
|
70
|
+
},
|
|
71
|
+
reducer(draft, action) {
|
|
72
|
+
draft.fetchState[action.payload.timeframe] = {
|
|
73
|
+
fetchState: 'Error',
|
|
74
|
+
error: action.payload.error,
|
|
75
|
+
};
|
|
76
|
+
},
|
|
77
|
+
},
|
|
78
|
+
updateCashFlowClassesToFilterOut(draft, action) {
|
|
79
|
+
draft.uiState.classesToFilterOut = action.payload.classesToFilterOut;
|
|
80
|
+
},
|
|
81
|
+
updateCashFlowClassesViewUIState(draft, action) {
|
|
82
|
+
const { nodeCollapseState, scrollPosition, resetLeftScroll } = action.payload;
|
|
83
|
+
if (nodeCollapseState != null) {
|
|
84
|
+
draft.uiState.nodeCollapseState = Object.assign({}, draft.uiState.nodeCollapseState, {
|
|
85
|
+
[nodeCollapseState.nodeId]: nodeCollapseState.isCollapsed,
|
|
86
|
+
});
|
|
87
|
+
}
|
|
88
|
+
// Mutually exclusive: resetLeftScroll clears only scrollLeft from the
|
|
89
|
+
// recorded position, scrollPosition replaces the whole record.
|
|
90
|
+
if (resetLeftScroll === true && draft.uiState.scrollPosition != null) {
|
|
91
|
+
draft.uiState.scrollPosition.scrollLeft = undefined;
|
|
92
|
+
}
|
|
93
|
+
else if (scrollPosition != null) {
|
|
94
|
+
draft.uiState.scrollPosition = scrollPosition;
|
|
95
|
+
}
|
|
96
|
+
},
|
|
97
|
+
updateCashFlowClassesViewAccountViewMode(draft, action) {
|
|
98
|
+
draft.uiState.accountViewMode = action.payload.viewMode;
|
|
99
|
+
},
|
|
100
|
+
resetCashFlowClassesNodeCollapseState(draft) {
|
|
101
|
+
draft.uiState.nodeCollapseState = {};
|
|
102
|
+
},
|
|
103
|
+
},
|
|
104
|
+
extraReducers: (builder) => {
|
|
105
|
+
builder.addCase(clearAll, (draft) => {
|
|
106
|
+
Object.assign(draft, initialState);
|
|
107
|
+
});
|
|
108
|
+
},
|
|
109
|
+
});
|
|
110
|
+
export const { fetchCashFlowClassesView, fetchCashFlowForTimeframeClassesView, updateCashFlowForTimeframeClassesView, updateCashFlowForTimeframeClassesViewFailure, updateCashFlowClassesToFilterOut, updateCashFlowClassesViewUIState, updateCashFlowClassesViewAccountViewMode, resetCashFlowClassesNodeCollapseState, } = cashFlowClassesView.actions;
|
|
111
|
+
export default cashFlowClassesView.reducer;
|
|
112
|
+
const doUpdateCashFlowClassesView = (draft, timeframe, cashFlowReport) => {
|
|
113
|
+
const report = mapReportPayloadV2ToReportV2(cashFlowReport.report);
|
|
114
|
+
draft.currency = report.currency;
|
|
115
|
+
draft.dataAvailable = report.dataAvailable;
|
|
116
|
+
draft.firstMonthOfFY = report.firstMonthOfFY;
|
|
117
|
+
draft.bookCloseDate = report.bookCloseDate;
|
|
118
|
+
draft.status = report.status;
|
|
119
|
+
draft.fetchState[timeframe].fetchState = 'Completed';
|
|
120
|
+
draft.fetchState[timeframe].error = undefined;
|
|
121
|
+
const classMetadata = cashFlowReport.report.classes.map((eachClass) => toClassMetadata(eachClass));
|
|
122
|
+
// Populated once and then left alone, so a per-timeframe response cannot
|
|
123
|
+
// clobber a hierarchy built from a full one. A class added mid-session is
|
|
124
|
+
// therefore not picked up until the store is cleared, even by a hard refresh —
|
|
125
|
+
// the same trade-off profitAndLossClassesViewReducer makes.
|
|
126
|
+
if (draft.classHierarchy.length <= 0) {
|
|
127
|
+
draft.classHierarchy = geNestedClassIDHierarchyForReport(classMetadata);
|
|
128
|
+
}
|
|
129
|
+
};
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import { getCOABalances } from '../../commonStateTypes/coaBalance/getCOABalancesSlice';
|
|
2
|
+
import { reduceFetchStateParallelTimeframes } from '../../commonStateTypes/reduceFetchState';
|
|
3
|
+
import { getSectionClassesViewReport } from '../../entity/sectionClassesViewV2/sectionClassesViewSelector';
|
|
4
|
+
import { CASH_FLOW_GROUPED_BREAKDOWN_IDS, CASH_FLOW_GROUPED_CALCULATED_IDS, CASH_FLOW_GROUPED_FINANCING_IDS_IN_ORDER, CASH_FLOW_GROUPED_IDS_IN_ORDER, CASH_FLOW_GROUPED_INVESTING_IDS_IN_ORDER, CASH_FLOW_GROUPED_OPERATING_IDS_IN_ORDER, } from '../cashFlow/cashFlowGroupedSectionOrder';
|
|
5
|
+
export const getCashFlowClassesView = (filter, accountState, classState, sectionsState, cashFlowClassesViewState) => {
|
|
6
|
+
const fetchState = reduceFetchStateParallelTimeframes([
|
|
7
|
+
cashFlowClassesViewState.fetchState.month,
|
|
8
|
+
cashFlowClassesViewState.fetchState.quarter,
|
|
9
|
+
cashFlowClassesViewState.fetchState.year,
|
|
10
|
+
]);
|
|
11
|
+
const reportId = 'cash_flow_by_classes';
|
|
12
|
+
const sections = {};
|
|
13
|
+
const calculatedSections = {};
|
|
14
|
+
if (fetchState.fetchState === 'Completed') {
|
|
15
|
+
CASH_FLOW_GROUPED_BREAKDOWN_IDS.forEach((sectionId) => {
|
|
16
|
+
sections[sectionId] = getSectionClassesViewReport(accountState, classState, sectionsState, { reportId, sectionId }, filter);
|
|
17
|
+
});
|
|
18
|
+
// These come back grouped, so each figure is read through the section layer
|
|
19
|
+
// and arrives already pruned by the class/project picker — the same source
|
|
20
|
+
// the breakdown rows above render from, so the two can never disagree.
|
|
21
|
+
CASH_FLOW_GROUPED_CALCULATED_IDS.forEach((calculatedSectionId) => {
|
|
22
|
+
calculatedSections[calculatedSectionId] = getCOABalances(
|
|
23
|
+
// Already built by the breakdown loop above; rebuilding it would repeat
|
|
24
|
+
// the whole section walk on every recompute.
|
|
25
|
+
sections[calculatedSectionId].sectionBalancesTotalByPeriod, filter);
|
|
26
|
+
});
|
|
27
|
+
calculatedSections['investingActivitiesTotal'] = getCOABalances(sections['investingActivities'].sectionBalancesTotalByPeriod, filter);
|
|
28
|
+
calculatedSections['financingActivitiesTotal'] = getCOABalances(sections['financingActivities'].sectionBalancesTotalByPeriod, filter);
|
|
29
|
+
}
|
|
30
|
+
return {
|
|
31
|
+
sections,
|
|
32
|
+
calculatedSections,
|
|
33
|
+
fetchState: fetchState.fetchState,
|
|
34
|
+
error: fetchState.error,
|
|
35
|
+
filter,
|
|
36
|
+
uiState: cashFlowClassesViewState.uiState,
|
|
37
|
+
classHierarchy: cashFlowClassesViewState.classHierarchy,
|
|
38
|
+
classesToFilterOut: cashFlowClassesViewState.uiState.classesToFilterOut,
|
|
39
|
+
reportId: cashFlowClassesViewState.reportId,
|
|
40
|
+
reportTitle: cashFlowClassesViewState.reportTitle,
|
|
41
|
+
firstMonthOfFY: cashFlowClassesViewState.firstMonthOfFY,
|
|
42
|
+
dataAvailable: cashFlowClassesViewState.dataAvailable,
|
|
43
|
+
bookCloseDate: cashFlowClassesViewState.bookCloseDate,
|
|
44
|
+
version: cashFlowClassesViewState.version,
|
|
45
|
+
status: cashFlowClassesViewState.status,
|
|
46
|
+
idsInOrder: CASH_FLOW_GROUPED_IDS_IN_ORDER,
|
|
47
|
+
rootSectionsWithSubSectionIds: {
|
|
48
|
+
operatingActivities: CASH_FLOW_GROUPED_OPERATING_IDS_IN_ORDER,
|
|
49
|
+
investingActivities: CASH_FLOW_GROUPED_INVESTING_IDS_IN_ORDER,
|
|
50
|
+
financingActivities: CASH_FLOW_GROUPED_FINANCING_IDS_IN_ORDER,
|
|
51
|
+
},
|
|
52
|
+
};
|
|
53
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import { from, of } from 'rxjs';
|
|
2
|
+
import { catchError, filter, mergeMap } from 'rxjs/operators';
|
|
3
|
+
import { updateSectionClassesView } from '../../entity/sectionClassesViewV2/sectionClassesViewReducer';
|
|
4
|
+
import { createZeniAPIStatus, isSuccessResponse } from '../../responsePayload';
|
|
5
|
+
import { toCashFlowReportViewID } from '../cashFlow/cashFlowPayload';
|
|
6
|
+
import { fetchCashFlowForTimeframeClassesView, updateCashFlowForTimeframeClassesView, updateCashFlowForTimeframeClassesViewFailure, } from './cashFlowClassesViewReducer';
|
|
7
|
+
const getTimeSeriesGroup = (timeframe) => {
|
|
8
|
+
switch (timeframe) {
|
|
9
|
+
case 'month':
|
|
10
|
+
return 'months';
|
|
11
|
+
case 'quarter':
|
|
12
|
+
return 'quarters';
|
|
13
|
+
case 'year':
|
|
14
|
+
return 'years';
|
|
15
|
+
}
|
|
16
|
+
};
|
|
17
|
+
export const reportIdUniqueKey = () => 'cash_flow_by_classes';
|
|
18
|
+
export const fetchCashFlowForTimeframeClassesViewEpic = (actions$, _, zeniAPI) => actions$.pipe(filter(fetchCashFlowForTimeframeClassesView.match), mergeMap((action) => {
|
|
19
|
+
const queryValue = {
|
|
20
|
+
is_full_response: true,
|
|
21
|
+
time_series_groups: [getTimeSeriesGroup(action.payload.timeframe)],
|
|
22
|
+
is_group_by_class: true,
|
|
23
|
+
// Only sent when refreshing: the flag makes the backend bypass its saved
|
|
24
|
+
// report and regenerate, so a normal lookup must not carry it.
|
|
25
|
+
...(action.payload.cacheOverride === true
|
|
26
|
+
? { is_hard_refresh: true }
|
|
27
|
+
: {}),
|
|
28
|
+
};
|
|
29
|
+
return zeniAPI
|
|
30
|
+
.getJSON(`${zeniAPI.apiEndPoints.accountMicroServiceBaseUrl}/2.0/reports/cash_flow?query=${encodeURIComponent(JSON.stringify(queryValue))}`)
|
|
31
|
+
.pipe(mergeMap((response) => {
|
|
32
|
+
if (response.data != null && isSuccessResponse(response)) {
|
|
33
|
+
const actions = [];
|
|
34
|
+
const { report } = response.data;
|
|
35
|
+
const currency = report.currency;
|
|
36
|
+
actions.push(updateSectionClassesView(action.payload.timeframe, toCashFlowReportViewID('adjustments'), reportIdUniqueKey(), report.operating_activities.adjustments, report.classes, report.accounts, currency));
|
|
37
|
+
actions.push(updateSectionClassesView(action.payload.timeframe, toCashFlowReportViewID('investing_activities'), reportIdUniqueKey(), report.investing_activities, report.classes, report.accounts, currency));
|
|
38
|
+
actions.push(updateSectionClassesView(action.payload.timeframe, toCashFlowReportViewID('financing_activities'), reportIdUniqueKey(), report.financing_activities, report.classes, report.accounts, currency));
|
|
39
|
+
actions.push(updateSectionClassesView(action.payload.timeframe, toCashFlowReportViewID('net_income'), reportIdUniqueKey(), report.operating_activities.net_income, report.classes, report.accounts, currency));
|
|
40
|
+
actions.push(updateSectionClassesView(action.payload.timeframe, toCashFlowReportViewID('operating_activities'), reportIdUniqueKey(), report.operating_activities, report.classes, report.accounts, currency));
|
|
41
|
+
actions.push(updateSectionClassesView(action.payload.timeframe, toCashFlowReportViewID('change_in_cash_and_equivalents'), reportIdUniqueKey(), report.change_in_cash_and_equivalents, report.classes, report.accounts, currency));
|
|
42
|
+
actions.push(updateCashFlowForTimeframeClassesView({
|
|
43
|
+
timeframe: action.payload.timeframe,
|
|
44
|
+
report: response.data,
|
|
45
|
+
}));
|
|
46
|
+
return from(actions);
|
|
47
|
+
}
|
|
48
|
+
else {
|
|
49
|
+
return of(updateCashFlowForTimeframeClassesViewFailure(response.status, action.payload.timeframe));
|
|
50
|
+
}
|
|
51
|
+
}), catchError((error) => of(updateCashFlowForTimeframeClassesViewFailure(createZeniAPIStatus('Unexpected Error', 'Cash Flow by Class REST API call errored out: ' +
|
|
52
|
+
(error instanceof Error
|
|
53
|
+
? error.message
|
|
54
|
+
: JSON.stringify(error))), action.payload.timeframe))));
|
|
55
|
+
}));
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import { from, of } from 'rxjs';
|
|
2
|
+
import { catchError, filter, mergeMap } from 'rxjs/operators';
|
|
3
|
+
import { updateProjects } from '../../entity/project/projectReducer';
|
|
4
|
+
import { updateSectionProjectView } from '../../entity/sectionProjectView/sectionProjectViewReducer';
|
|
5
|
+
import { createZeniAPIStatus, isSuccessResponse } from '../../responsePayload';
|
|
6
|
+
import { toCashFlowReportViewID } from '../cashFlow/cashFlowPayload';
|
|
7
|
+
import { fetchCashFlowForTimeframeProjectView, updateCashFlowForTimeframeProjectView, updateCashFlowForTimeframeProjectViewFailure, } from './cashFlowProjectViewReducer';
|
|
8
|
+
const getTimeSeriesGroup = (timeframe) => {
|
|
9
|
+
switch (timeframe) {
|
|
10
|
+
case 'month':
|
|
11
|
+
return 'months';
|
|
12
|
+
case 'quarter':
|
|
13
|
+
return 'quarters';
|
|
14
|
+
case 'year':
|
|
15
|
+
return 'years';
|
|
16
|
+
}
|
|
17
|
+
};
|
|
18
|
+
export const reportIdUniqueKey = () => 'cash_flow_by_projects';
|
|
19
|
+
export const fetchCashFlowForTimeframeProjectViewEpic = (actions$, _, zeniAPI) => actions$.pipe(filter(fetchCashFlowForTimeframeProjectView.match), mergeMap((action) => {
|
|
20
|
+
const queryValue = {
|
|
21
|
+
is_full_response: true,
|
|
22
|
+
time_series_groups: [getTimeSeriesGroup(action.payload.timeframe)],
|
|
23
|
+
is_group_by_project: true,
|
|
24
|
+
// Only sent when refreshing: the flag makes the backend bypass its saved
|
|
25
|
+
// report and regenerate, so a normal lookup must not carry it.
|
|
26
|
+
...(action.payload.cacheOverride === true
|
|
27
|
+
? { is_hard_refresh: true }
|
|
28
|
+
: {}),
|
|
29
|
+
};
|
|
30
|
+
return zeniAPI
|
|
31
|
+
.getJSON(`${zeniAPI.apiEndPoints.accountMicroServiceBaseUrl}/2.0/reports/cash_flow?query=${encodeURIComponent(JSON.stringify(queryValue))}`)
|
|
32
|
+
.pipe(mergeMap((response) => {
|
|
33
|
+
if (response.data != null && isSuccessResponse(response)) {
|
|
34
|
+
const actions = [];
|
|
35
|
+
const { report } = response.data;
|
|
36
|
+
const currency = report.currency;
|
|
37
|
+
actions.push(updateProjects(report.projects));
|
|
38
|
+
actions.push(updateSectionProjectView(action.payload.timeframe, toCashFlowReportViewID('adjustments'), reportIdUniqueKey(), report.operating_activities.adjustments, report.accounts, currency));
|
|
39
|
+
actions.push(updateSectionProjectView(action.payload.timeframe, toCashFlowReportViewID('investing_activities'), reportIdUniqueKey(), report.investing_activities, report.accounts, currency));
|
|
40
|
+
actions.push(updateSectionProjectView(action.payload.timeframe, toCashFlowReportViewID('financing_activities'), reportIdUniqueKey(), report.financing_activities, report.accounts, currency));
|
|
41
|
+
actions.push(updateSectionProjectView(action.payload.timeframe, toCashFlowReportViewID('net_income'), reportIdUniqueKey(), report.operating_activities.net_income, report.accounts, currency));
|
|
42
|
+
actions.push(updateSectionProjectView(action.payload.timeframe, toCashFlowReportViewID('operating_activities'), reportIdUniqueKey(), report.operating_activities, report.accounts, currency));
|
|
43
|
+
actions.push(updateSectionProjectView(action.payload.timeframe, toCashFlowReportViewID('change_in_cash_and_equivalents'), reportIdUniqueKey(), report.change_in_cash_and_equivalents, report.accounts, currency));
|
|
44
|
+
actions.push(updateCashFlowForTimeframeProjectView({
|
|
45
|
+
timeframe: action.payload.timeframe,
|
|
46
|
+
report: response.data,
|
|
47
|
+
}));
|
|
48
|
+
return from(actions);
|
|
49
|
+
}
|
|
50
|
+
else {
|
|
51
|
+
return of(updateCashFlowForTimeframeProjectViewFailure(response.status, action.payload.timeframe));
|
|
52
|
+
}
|
|
53
|
+
}), catchError((error) => of(updateCashFlowForTimeframeProjectViewFailure(createZeniAPIStatus('Unexpected Error', 'Cash Flow by Project REST API call errored out: ' +
|
|
54
|
+
(error instanceof Error
|
|
55
|
+
? error.message
|
|
56
|
+
: JSON.stringify(error))), action.payload.timeframe))));
|
|
57
|
+
}));
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { from } from 'rxjs';
|
|
2
|
+
import { filter, switchMap } from 'rxjs/operators';
|
|
3
|
+
import { fetchCashFlowForTimeframeProjectView, fetchCashFlowProjectView, } from './cashFlowProjectViewReducer';
|
|
4
|
+
export const fetchCashFlowProjectViewEpic = (actions$, state) => actions$.pipe(filter(fetchCashFlowProjectView.match), switchMap((action) => {
|
|
5
|
+
const { cacheOverride } = action.payload;
|
|
6
|
+
if (cacheOverride === true) {
|
|
7
|
+
return from([
|
|
8
|
+
fetchCashFlowForTimeframeProjectView('month', true),
|
|
9
|
+
fetchCashFlowForTimeframeProjectView('quarter', true),
|
|
10
|
+
fetchCashFlowForTimeframeProjectView('year', true),
|
|
11
|
+
]);
|
|
12
|
+
}
|
|
13
|
+
else {
|
|
14
|
+
const fetchActions = [];
|
|
15
|
+
const projectFetchState = state.value.cashFlowProjectViewState.fetchState;
|
|
16
|
+
if (projectFetchState['month'].fetchState !== 'In-Progress' &&
|
|
17
|
+
projectFetchState['month'].fetchState !== 'Completed') {
|
|
18
|
+
fetchActions.push(fetchCashFlowForTimeframeProjectView('month'));
|
|
19
|
+
}
|
|
20
|
+
if (projectFetchState['quarter'].fetchState !== 'In-Progress' &&
|
|
21
|
+
projectFetchState['quarter'].fetchState !== 'Completed') {
|
|
22
|
+
fetchActions.push(fetchCashFlowForTimeframeProjectView('quarter'));
|
|
23
|
+
}
|
|
24
|
+
if (projectFetchState['year'].fetchState !== 'In-Progress' &&
|
|
25
|
+
projectFetchState['year'].fetchState !== 'Completed') {
|
|
26
|
+
fetchActions.push(fetchCashFlowForTimeframeProjectView('year'));
|
|
27
|
+
}
|
|
28
|
+
return from(fetchActions);
|
|
29
|
+
}
|
|
30
|
+
}));
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
import { createSlice } from '@reduxjs/toolkit';
|
|
2
|
+
import { mapReportPayloadV2ToReportV2 } from '../../commonPayloadTypes/v2/viewAndReportPayloadv2';
|
|
3
|
+
import { clearAll } from '../../rootActions';
|
|
4
|
+
export const initialState = {
|
|
5
|
+
bookCloseDate: undefined,
|
|
6
|
+
fetchState: {
|
|
7
|
+
month: {
|
|
8
|
+
fetchState: 'Not-Started',
|
|
9
|
+
error: undefined,
|
|
10
|
+
},
|
|
11
|
+
quarter: {
|
|
12
|
+
fetchState: 'Not-Started',
|
|
13
|
+
error: undefined,
|
|
14
|
+
},
|
|
15
|
+
year: {
|
|
16
|
+
fetchState: 'Not-Started',
|
|
17
|
+
error: undefined,
|
|
18
|
+
},
|
|
19
|
+
},
|
|
20
|
+
firstMonthOfFY: 1,
|
|
21
|
+
projectIds: [],
|
|
22
|
+
reportId: 'cash_flow_by_projects',
|
|
23
|
+
reportTitle: 'cash_flow_by_projects',
|
|
24
|
+
uiState: {
|
|
25
|
+
accountViewMode: 'account_group',
|
|
26
|
+
nodeCollapseState: {},
|
|
27
|
+
projectsToFilterOut: [],
|
|
28
|
+
scrollPosition: undefined,
|
|
29
|
+
},
|
|
30
|
+
};
|
|
31
|
+
const cashFlowProjectView = createSlice({
|
|
32
|
+
name: 'cashFlowProjectView',
|
|
33
|
+
initialState,
|
|
34
|
+
reducers: {
|
|
35
|
+
fetchCashFlowProjectView: {
|
|
36
|
+
prepare(cacheOverride = false) {
|
|
37
|
+
return { payload: { cacheOverride } };
|
|
38
|
+
},
|
|
39
|
+
reducer(
|
|
40
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
41
|
+
_draft,
|
|
42
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
43
|
+
_action) {
|
|
44
|
+
// nothing to do here
|
|
45
|
+
},
|
|
46
|
+
},
|
|
47
|
+
fetchCashFlowForTimeframeProjectView: {
|
|
48
|
+
prepare(timeframe, cacheOverride = false) {
|
|
49
|
+
return { payload: { timeframe, cacheOverride } };
|
|
50
|
+
},
|
|
51
|
+
reducer(draft, action) {
|
|
52
|
+
const timeframe = action.payload.timeframe;
|
|
53
|
+
draft.fetchState[timeframe].fetchState = 'In-Progress';
|
|
54
|
+
draft.fetchState[timeframe].error = undefined;
|
|
55
|
+
},
|
|
56
|
+
},
|
|
57
|
+
updateCashFlowForTimeframeProjectView(draft, action) {
|
|
58
|
+
doUpdateCashFlowProjectView(draft, action.payload.timeframe, action.payload.report);
|
|
59
|
+
},
|
|
60
|
+
updateCashFlowForTimeframeProjectViewFailure: {
|
|
61
|
+
prepare(error, timeframe) {
|
|
62
|
+
return {
|
|
63
|
+
payload: {
|
|
64
|
+
error,
|
|
65
|
+
timeframe,
|
|
66
|
+
},
|
|
67
|
+
};
|
|
68
|
+
},
|
|
69
|
+
reducer(draft, action) {
|
|
70
|
+
draft.fetchState[action.payload.timeframe] = {
|
|
71
|
+
fetchState: 'Error',
|
|
72
|
+
error: action.payload.error,
|
|
73
|
+
};
|
|
74
|
+
},
|
|
75
|
+
},
|
|
76
|
+
updateCashFlowProjectsToFilterOut(draft, action) {
|
|
77
|
+
draft.uiState.projectsToFilterOut = action.payload.projectsToFilterOut;
|
|
78
|
+
},
|
|
79
|
+
updateCashFlowProjectViewUIState(draft, action) {
|
|
80
|
+
const { nodeCollapseState, scrollPosition, resetLeftScroll } = action.payload;
|
|
81
|
+
if (nodeCollapseState != null) {
|
|
82
|
+
draft.uiState.nodeCollapseState = Object.assign({}, draft.uiState.nodeCollapseState, {
|
|
83
|
+
[nodeCollapseState.nodeId]: nodeCollapseState.isCollapsed,
|
|
84
|
+
});
|
|
85
|
+
}
|
|
86
|
+
// Mutually exclusive: resetLeftScroll clears only scrollLeft from the
|
|
87
|
+
// recorded position, scrollPosition replaces the whole record.
|
|
88
|
+
if (resetLeftScroll === true && draft.uiState.scrollPosition != null) {
|
|
89
|
+
draft.uiState.scrollPosition.scrollLeft = undefined;
|
|
90
|
+
}
|
|
91
|
+
else if (scrollPosition != null) {
|
|
92
|
+
draft.uiState.scrollPosition = scrollPosition;
|
|
93
|
+
}
|
|
94
|
+
},
|
|
95
|
+
updateCashFlowProjectViewAccountViewMode(draft, action) {
|
|
96
|
+
draft.uiState.accountViewMode = action.payload.viewMode;
|
|
97
|
+
},
|
|
98
|
+
resetCashFlowProjectNodeCollapseState(draft) {
|
|
99
|
+
draft.uiState.nodeCollapseState = {};
|
|
100
|
+
},
|
|
101
|
+
},
|
|
102
|
+
extraReducers: (builder) => {
|
|
103
|
+
builder.addCase(clearAll, (draft) => {
|
|
104
|
+
Object.assign(draft, initialState);
|
|
105
|
+
});
|
|
106
|
+
},
|
|
107
|
+
});
|
|
108
|
+
export const { fetchCashFlowProjectView, fetchCashFlowForTimeframeProjectView, updateCashFlowForTimeframeProjectView, updateCashFlowForTimeframeProjectViewFailure, updateCashFlowProjectsToFilterOut, updateCashFlowProjectViewUIState, updateCashFlowProjectViewAccountViewMode, resetCashFlowProjectNodeCollapseState, } = cashFlowProjectView.actions;
|
|
109
|
+
export default cashFlowProjectView.reducer;
|
|
110
|
+
const doUpdateCashFlowProjectView = (draft, timeframe, cashFlowReport) => {
|
|
111
|
+
const report = mapReportPayloadV2ToReportV2(cashFlowReport.report);
|
|
112
|
+
draft.currency = report.currency;
|
|
113
|
+
draft.dataAvailable = report.dataAvailable;
|
|
114
|
+
draft.firstMonthOfFY = report.firstMonthOfFY;
|
|
115
|
+
draft.bookCloseDate = report.bookCloseDate;
|
|
116
|
+
draft.status = report.status;
|
|
117
|
+
draft.fetchState[timeframe].fetchState = 'Completed';
|
|
118
|
+
draft.fetchState[timeframe].error = undefined;
|
|
119
|
+
// Populated once, as with classHierarchy in the classes view: a project added
|
|
120
|
+
// mid-session is not picked up until the store is cleared, even by a hard
|
|
121
|
+
// refresh. Matches profitAndLossProjectViewReducer.
|
|
122
|
+
if (draft.projectIds.length <= 0) {
|
|
123
|
+
draft.projectIds = cashFlowReport.report.projects.map((project) => project.accounting_project_id);
|
|
124
|
+
}
|
|
125
|
+
};
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import { getCOABalances } from '../../commonStateTypes/coaBalance/getCOABalancesSlice';
|
|
2
|
+
import { reduceFetchStateParallelTimeframes } from '../../commonStateTypes/reduceFetchState';
|
|
3
|
+
import { getProjectsByIds } from '../../entity/project/projectSelector';
|
|
4
|
+
import { getSectionProjectViewReport } from '../../entity/sectionProjectView/sectionProjectViewSelector';
|
|
5
|
+
import { CASH_FLOW_GROUPED_BREAKDOWN_IDS, CASH_FLOW_GROUPED_CALCULATED_IDS, CASH_FLOW_GROUPED_FINANCING_IDS_IN_ORDER, CASH_FLOW_GROUPED_IDS_IN_ORDER, CASH_FLOW_GROUPED_INVESTING_IDS_IN_ORDER, CASH_FLOW_GROUPED_OPERATING_IDS_IN_ORDER, } from '../cashFlow/cashFlowGroupedSectionOrder';
|
|
6
|
+
export const getCashFlowProjectView = (filter, accountState, projectState, sectionsState, cashFlowProjectViewState) => {
|
|
7
|
+
const fetchState = reduceFetchStateParallelTimeframes([
|
|
8
|
+
cashFlowProjectViewState.fetchState.month,
|
|
9
|
+
cashFlowProjectViewState.fetchState.quarter,
|
|
10
|
+
cashFlowProjectViewState.fetchState.year,
|
|
11
|
+
]);
|
|
12
|
+
const reportId = 'cash_flow_by_projects';
|
|
13
|
+
const sections = {};
|
|
14
|
+
const calculatedSections = {};
|
|
15
|
+
if (fetchState.fetchState === 'Completed') {
|
|
16
|
+
CASH_FLOW_GROUPED_BREAKDOWN_IDS.forEach((sectionId) => {
|
|
17
|
+
sections[sectionId] = getSectionProjectViewReport(accountState, projectState, sectionsState, cashFlowProjectViewState.projectIds, { reportId, sectionId }, filter);
|
|
18
|
+
});
|
|
19
|
+
// These come back grouped, so each figure is read through the section layer
|
|
20
|
+
// and arrives already pruned by the class/project picker — the same source
|
|
21
|
+
// the breakdown rows above render from, so the two can never disagree.
|
|
22
|
+
CASH_FLOW_GROUPED_CALCULATED_IDS.forEach((calculatedSectionId) => {
|
|
23
|
+
calculatedSections[calculatedSectionId] = getCOABalances(
|
|
24
|
+
// Already built by the breakdown loop above; rebuilding it would repeat
|
|
25
|
+
// the whole section walk on every recompute.
|
|
26
|
+
sections[calculatedSectionId].sectionBalancesTotalByPeriod, filter);
|
|
27
|
+
});
|
|
28
|
+
calculatedSections['investingActivitiesTotal'] = getCOABalances(sections['investingActivities'].sectionBalancesTotalByPeriod, filter);
|
|
29
|
+
calculatedSections['financingActivitiesTotal'] = getCOABalances(sections['financingActivities'].sectionBalancesTotalByPeriod, filter);
|
|
30
|
+
}
|
|
31
|
+
return {
|
|
32
|
+
sections,
|
|
33
|
+
calculatedSections,
|
|
34
|
+
fetchState: fetchState.fetchState,
|
|
35
|
+
error: fetchState.error,
|
|
36
|
+
filter,
|
|
37
|
+
uiState: cashFlowProjectViewState.uiState,
|
|
38
|
+
projects: getProjectsByIds(projectState, cashFlowProjectViewState.projectIds),
|
|
39
|
+
projectsToFilterOut: cashFlowProjectViewState.uiState.projectsToFilterOut,
|
|
40
|
+
reportId: cashFlowProjectViewState.reportId,
|
|
41
|
+
reportTitle: cashFlowProjectViewState.reportTitle,
|
|
42
|
+
firstMonthOfFY: cashFlowProjectViewState.firstMonthOfFY,
|
|
43
|
+
dataAvailable: cashFlowProjectViewState.dataAvailable,
|
|
44
|
+
bookCloseDate: cashFlowProjectViewState.bookCloseDate,
|
|
45
|
+
version: cashFlowProjectViewState.version,
|
|
46
|
+
status: cashFlowProjectViewState.status,
|
|
47
|
+
idsInOrder: CASH_FLOW_GROUPED_IDS_IN_ORDER,
|
|
48
|
+
rootSectionsWithSubSectionIds: {
|
|
49
|
+
operatingActivities: CASH_FLOW_GROUPED_OPERATING_IDS_IN_ORDER,
|
|
50
|
+
investingActivities: CASH_FLOW_GROUPED_INVESTING_IDS_IN_ORDER,
|
|
51
|
+
financingActivities: CASH_FLOW_GROUPED_FINANCING_IDS_IN_ORDER,
|
|
52
|
+
},
|
|
53
|
+
};
|
|
54
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -9,18 +9,6 @@ import { clearAll } from '../../../../rootActions';
|
|
|
9
9
|
import { date } from '../../../../zeniDayJS';
|
|
10
10
|
import { SERVICE_MONTH_FORMAT, } from '../../payload/jeSchedulesPayload';
|
|
11
11
|
import { fetchJeSchedules, fetchJeSchedulesFailure, fetchJeSchedulesSuccess, initializeJeScheduleLocalData, } from '../../reducers/jeSchedulesViewReducer';
|
|
12
|
-
/**
|
|
13
|
-
* How far back to look for accrued schedules, matching the Vendors page
|
|
14
|
-
* (`getDefaultSelectedTimeframeForScheduleType`, 'accrued_expenses'), which queries the same
|
|
15
|
-
* start_date filter through /1.0/schedules.
|
|
16
|
-
*/
|
|
17
|
-
const ACCRUED_LOOKBACK_MONTHS = 24;
|
|
18
|
-
/**
|
|
19
|
-
* One-time accruals keep their own, narrower lookback. Unlike an accrued schedule they belong to
|
|
20
|
-
* exactly one service month and never span months, so the reason the accrued window has to reach
|
|
21
|
-
* back does not apply to them -- widening it would only add older history to the Existing tab.
|
|
22
|
-
*/
|
|
23
|
-
const ONE_TIME_ACCRUAL_LOOKBACK_MONTHS = 12;
|
|
24
12
|
export const fetchJeSchedulesEpic = (actions$, state$, zeniAPI) => actions$.pipe(filter(fetchJeSchedules.match), mergeMap((action) => {
|
|
25
13
|
const state = state$.value;
|
|
26
14
|
const { expenseAutomationViewState: { selectedPeriodByTenantId }, } = state;
|
|
@@ -42,21 +30,15 @@ export const fetchJeSchedulesEpic = (actions$, state$, zeniAPI) => actions$.pipe
|
|
|
42
30
|
const endDate = isClosePeriodTab || existingEndDate == null
|
|
43
31
|
? toString(period.end)
|
|
44
32
|
: toString(existingEndDate);
|
|
45
|
-
// Accrued rows are windowed on the schedule's own start_date
|
|
46
|
-
//
|
|
47
|
-
//
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
.format(DEFAULT_DATE_FORMAT);
|
|
55
|
-
// Formatted as a service month, not a date: that is the only thing it is sent as.
|
|
56
|
-
const oneTimeAccrualServiceMonthStart = parsedEndDate
|
|
57
|
-
.subtract(ONE_TIME_ACCRUAL_LOOKBACK_MONTHS, 'month')
|
|
58
|
-
.startOf('month')
|
|
59
|
-
.format(SERVICE_MONTH_FORMAT);
|
|
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);
|
|
60
42
|
const queryParam = {
|
|
61
43
|
base_transaction_end_date: endDate,
|
|
62
44
|
end_date: endDate,
|
|
@@ -77,8 +59,8 @@ export const fetchJeSchedulesEpic = (actions$, state$, zeniAPI) => actions$.pipe
|
|
|
77
59
|
filter_failed_je_postings_by_date: true,
|
|
78
60
|
}
|
|
79
61
|
: {
|
|
80
|
-
one_time_accrual_service_month_start:
|
|
81
|
-
one_time_accrual_service_month_end:
|
|
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),
|
|
82
64
|
// Existing lists what actually reached the books.
|
|
83
65
|
one_time_accrual_statuses: ['posted'],
|
|
84
66
|
// A failed posting from an earlier month still needs to surface here, so this list
|
|
@@ -11,6 +11,8 @@ import { getBalanceSheet } from '../balanceSheet/balanceSheetSelector';
|
|
|
11
11
|
import { getBalanceSheetClassesView } from '../balanceSheetClassesView/balanceSheetClassesViewSelector';
|
|
12
12
|
import { getBalanceSheetProjectView } from '../balanceSheetProjectView/balanceSheetProjectViewSelector';
|
|
13
13
|
import { getCashFlow } from '../cashFlow/cashFlowSelector';
|
|
14
|
+
import { getCashFlowClassesView } from '../cashFlowClassesView/cashFlowClassesViewSelector';
|
|
15
|
+
import { getCashFlowProjectView } from '../cashFlowProjectView/cashFlowProjectViewSelector';
|
|
14
16
|
import { getProfitAndLossReport, } from '../profitAndLoss/profitAndLossSelector';
|
|
15
17
|
import { getProfitAndLossClassesHorizontalView } from '../profitAndLossClassesView/profitAndLossClassesByClassHorizontalSelector';
|
|
16
18
|
import { getProfitAndLossClassesView } from '../profitAndLossClassesView/profitAndLossClassesViewSelector';
|
|
@@ -39,7 +41,7 @@ function getFirstMonthOfFY(profitAndLossState, balanceSheetState, cashFlowState)
|
|
|
39
41
|
cashFlowState.firstMonthOfFY ??
|
|
40
42
|
1);
|
|
41
43
|
}
|
|
42
|
-
export const getFinanceStatement = createSelector((state) => state.accountState, (state) => state.accountGroupState, (state) => state.classState, (state) => state.sectionClassesViewStateV2, (state) => state.profitAndLossState, (state) => state.profitAndLossClassesViewState, (state) => state.projectState, (state) => state.sectionProjectViewState, (state) => state.profitAndLossProjectViewState, (state) => state.balanceSheetState, (state) => state.balanceSheetClassesViewState, (state) => state.balanceSheetProjectViewState, (state) => state.cashFlowState, (state) => state.financeStatementState, (state) => state.sectionAccountsViewState, (state) => state.forecastState, (accountState, accountGroupState, classState, sectionsState, profitAndLossState, profitAndLossClassesViewState, projectState, sectionProjectViewState, profitAndLossProjectViewState, balanceSheetState, balanceSheetClassesViewState, balanceSheetProjectViewState, cashFlowState, financeStatementState, sectionAccountsViewState, forecastState) => {
|
|
44
|
+
export const getFinanceStatement = createSelector((state) => state.accountState, (state) => state.accountGroupState, (state) => state.classState, (state) => state.sectionClassesViewStateV2, (state) => state.profitAndLossState, (state) => state.profitAndLossClassesViewState, (state) => state.projectState, (state) => state.sectionProjectViewState, (state) => state.profitAndLossProjectViewState, (state) => state.balanceSheetState, (state) => state.balanceSheetClassesViewState, (state) => state.balanceSheetProjectViewState, (state) => state.cashFlowState, (state) => state.cashFlowClassesViewState, (state) => state.cashFlowProjectViewState, (state) => state.financeStatementState, (state) => state.sectionAccountsViewState, (state) => state.forecastState, (accountState, accountGroupState, classState, sectionsState, profitAndLossState, profitAndLossClassesViewState, projectState, sectionProjectViewState, profitAndLossProjectViewState, balanceSheetState, balanceSheetClassesViewState, balanceSheetProjectViewState, cashFlowState, cashFlowClassesViewState, cashFlowProjectViewState, financeStatementState, sectionAccountsViewState, forecastState) => {
|
|
43
45
|
// to get min and max dates across three reports
|
|
44
46
|
let allTimeframeTicks = [];
|
|
45
47
|
let balancesInTimeframe = [];
|
|
@@ -81,6 +83,10 @@ export const getFinanceStatement = createSelector((state) => state.accountState,
|
|
|
81
83
|
const balanceSheetReport = getBalanceSheet(filter, accountState, accountGroupState, sectionAccountsViewState, balanceSheetState);
|
|
82
84
|
const balanceSheetClassFilter = newBalancesFilterClassesView(filter.firstMonthOfFY, filter.timeframe, filter.balancesRange.numberOfPeriods, filter.balancesRange.thisPeriod, filter.balancesRange.orderBy, filter.additionalBalances, balanceSheetClassesViewState.uiState.classesToFilterOut);
|
|
83
85
|
const balanceSheetByClassReport = getBalanceSheetClassesView(balanceSheetClassFilter, accountState, classState, sectionsState, balanceSheetClassesViewState);
|
|
86
|
+
const cashFlowClassFilter = newBalancesFilterClassesView(filter.firstMonthOfFY, filter.timeframe, filter.balancesRange.numberOfPeriods, filter.balancesRange.thisPeriod, filter.balancesRange.orderBy, filter.additionalBalances, cashFlowClassesViewState.uiState.classesToFilterOut);
|
|
87
|
+
const cashFlowByClassReport = getCashFlowClassesView(cashFlowClassFilter, accountState, classState, sectionsState, cashFlowClassesViewState);
|
|
88
|
+
const cashFlowProjectFilter = newBalancesFilterProjectView(filter.firstMonthOfFY, filter.timeframe, filter.balancesRange.numberOfPeriods, filter.balancesRange.thisPeriod, filter.balancesRange.orderBy, filter.additionalBalances, cashFlowProjectViewState.uiState.projectsToFilterOut);
|
|
89
|
+
const cashFlowByProjectReport = getCashFlowProjectView(cashFlowProjectFilter, accountState, projectState, sectionProjectViewState, cashFlowProjectViewState);
|
|
84
90
|
const balanceSheetProjectFilter = newBalancesFilterProjectView(filter.firstMonthOfFY, filter.timeframe, filter.balancesRange.numberOfPeriods, filter.balancesRange.thisPeriod, filter.balancesRange.orderBy, filter.additionalBalances, balanceSheetProjectViewState.uiState.projectsToFilterOut);
|
|
85
91
|
const balanceSheetByProjectReport = getBalanceSheetProjectView(balanceSheetProjectFilter, accountState, projectState, sectionProjectViewState, balanceSheetProjectViewState);
|
|
86
92
|
const cashFlowReport = getCashFlow(filter, accountState, accountGroupState, sectionAccountsViewState, cashFlowState);
|
|
@@ -129,6 +135,18 @@ export const getFinanceStatement = createSelector((state) => state.accountState,
|
|
|
129
135
|
error: cashFlowReport.error,
|
|
130
136
|
};
|
|
131
137
|
break;
|
|
138
|
+
case 'cash_flow_by_classes':
|
|
139
|
+
selectedReportAndTimeframeFetchState = {
|
|
140
|
+
fetchState: cashFlowByClassReport.fetchState,
|
|
141
|
+
error: cashFlowByClassReport.error,
|
|
142
|
+
};
|
|
143
|
+
break;
|
|
144
|
+
case 'cash_flow_by_projects':
|
|
145
|
+
selectedReportAndTimeframeFetchState = {
|
|
146
|
+
fetchState: cashFlowByProjectReport.fetchState,
|
|
147
|
+
error: cashFlowByProjectReport.error,
|
|
148
|
+
};
|
|
149
|
+
break;
|
|
132
150
|
default:
|
|
133
151
|
break;
|
|
134
152
|
}
|
|
@@ -151,6 +169,8 @@ export const getFinanceStatement = createSelector((state) => state.accountState,
|
|
|
151
169
|
profitAndLossByClassHorizontalReport,
|
|
152
170
|
balanceSheetReport,
|
|
153
171
|
balanceSheetByClassReport,
|
|
172
|
+
cashFlowByClassReport,
|
|
173
|
+
cashFlowByProjectReport,
|
|
154
174
|
balanceSheetByProjectReport,
|
|
155
175
|
cashFlowReport,
|
|
156
176
|
filter,
|