@zeniai/client-epic-state 4.19.91-beta0ND → 4.19.91-beta2ND
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/reduceFetchState.d.ts +9 -0
- package/lib/commonStateTypes/reduceFetchState.js +26 -0
- package/lib/esm/commonStateTypes/reduceFetchState.js +25 -0
- package/lib/esm/index.js +2 -2
- package/lib/esm/view/financeStatement/financeStatementReducer.js +2 -2
- package/lib/esm/view/financeStatement/financeStatementSelector.js +8 -12
- package/lib/esm/view/profitAndLossClassesView/profitAndLossClassesByClassHorizontalSelector.js +44 -48
- package/lib/esm/view/profitAndLossClassesView/profitAndLossClassesViewReducer.js +1 -0
- package/lib/esm/view/profitAndLossClassesView/profitAndLossClassesViewSelector.js +2 -29
- package/lib/esm/view/profitAndLossClassesView/profitAndLossForTimeframeClassesViewEpic.js +7 -5
- package/lib/esm/view/reportUIOptions/updateReportUIOptionCOABalancesRangeEpic.js +9 -7
- package/lib/index.d.ts +2 -2
- package/lib/index.js +14 -13
- package/lib/tsconfig.typecheck.tsbuildinfo +1 -1
- package/lib/view/financeStatement/financeStatementReducer.js +2 -2
- package/lib/view/financeStatement/financeStatementSelector.js +8 -12
- package/lib/view/profitAndLossClassesView/profitAndLossClassesByClassHorizontalSelector.js +44 -48
- package/lib/view/profitAndLossClassesView/profitAndLossClassesViewReducer.js +1 -0
- package/lib/view/profitAndLossClassesView/profitAndLossClassesViewSelector.js +2 -29
- package/lib/view/profitAndLossClassesView/profitAndLossClassesViewState.d.ts +2 -0
- package/lib/view/profitAndLossClassesView/profitAndLossForTimeframeClassesViewEpic.js +7 -5
- package/lib/view/reportUIOptions/updateReportUIOptionCOABalancesRangeEpic.js +8 -6
- package/package.json +1 -1
|
@@ -11,6 +11,15 @@ export declare const isAllFetchCompleted: (fetchStateList: FetchStateAndError[])
|
|
|
11
11
|
* @return single fetchStateWithError
|
|
12
12
|
*/
|
|
13
13
|
export declare function reduceFetchState(fetchStateList: FetchStateAndError[]): FetchStateAndError;
|
|
14
|
+
/**
|
|
15
|
+
* Combine multiple independent fetches (e.g. month / quarter / year for one report).
|
|
16
|
+
* In-Progress if any fetch is in progress; Completed only when all complete; Error if
|
|
17
|
+
* any failed once nothing is still in progress.
|
|
18
|
+
*
|
|
19
|
+
* Differs from {@link reduceFetchState} (requires all In-Progress for that state) and
|
|
20
|
+
* from {@link reduceAllFetchState} (Error only when every fetch failed).
|
|
21
|
+
*/
|
|
22
|
+
export declare function reduceFetchStateParallelTimeframes(fetchStateList: FetchStateAndError[]): FetchStateAndError;
|
|
14
23
|
/**
|
|
15
24
|
* Reduces list of fetch state to boolean
|
|
16
25
|
* @param fetchStateList list of fetch states
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.reduceAnyCompletedFetchState = exports.reduceAllFetchState = exports.reduceAnyFetchState = exports.isAnyFetchCompleted = exports.isAnyFetchInProgress = exports.isAllFetchCompleted = void 0;
|
|
4
4
|
exports.reduceFetchState = reduceFetchState;
|
|
5
|
+
exports.reduceFetchStateParallelTimeframes = reduceFetchStateParallelTimeframes;
|
|
5
6
|
/**
|
|
6
7
|
* Reduces list of fetch state to boolean
|
|
7
8
|
* @param fetchStateList list of fetch states
|
|
@@ -55,6 +56,31 @@ function reduceFetchState(fetchStateList) {
|
|
|
55
56
|
error,
|
|
56
57
|
};
|
|
57
58
|
}
|
|
59
|
+
/**
|
|
60
|
+
* Combine multiple independent fetches (e.g. month / quarter / year for one report).
|
|
61
|
+
* In-Progress if any fetch is in progress; Completed only when all complete; Error if
|
|
62
|
+
* any failed once nothing is still in progress.
|
|
63
|
+
*
|
|
64
|
+
* Differs from {@link reduceFetchState} (requires all In-Progress for that state) and
|
|
65
|
+
* from {@link reduceAllFetchState} (Error only when every fetch failed).
|
|
66
|
+
*/
|
|
67
|
+
function reduceFetchStateParallelTimeframes(fetchStateList) {
|
|
68
|
+
const isAnyProgress = fetchStateList.some((s) => s.fetchState === 'In-Progress');
|
|
69
|
+
const isAllCompleted = fetchStateList.every((s) => s.fetchState === 'Completed');
|
|
70
|
+
const isAnyError = fetchStateList.some((s) => s.fetchState === 'Error');
|
|
71
|
+
const error = reduceError(fetchStateList);
|
|
72
|
+
let fetchState = 'Not-Started';
|
|
73
|
+
if (isAnyProgress) {
|
|
74
|
+
fetchState = 'In-Progress';
|
|
75
|
+
}
|
|
76
|
+
else if (isAllCompleted) {
|
|
77
|
+
fetchState = 'Completed';
|
|
78
|
+
}
|
|
79
|
+
else if (isAnyError) {
|
|
80
|
+
fetchState = 'Error';
|
|
81
|
+
}
|
|
82
|
+
return { fetchState, error };
|
|
83
|
+
}
|
|
58
84
|
/**
|
|
59
85
|
* Reduces list of fetch state to boolean
|
|
60
86
|
* @param fetchStateList list of fetch states
|
|
@@ -50,6 +50,31 @@ export function reduceFetchState(fetchStateList) {
|
|
|
50
50
|
error,
|
|
51
51
|
};
|
|
52
52
|
}
|
|
53
|
+
/**
|
|
54
|
+
* Combine multiple independent fetches (e.g. month / quarter / year for one report).
|
|
55
|
+
* In-Progress if any fetch is in progress; Completed only when all complete; Error if
|
|
56
|
+
* any failed once nothing is still in progress.
|
|
57
|
+
*
|
|
58
|
+
* Differs from {@link reduceFetchState} (requires all In-Progress for that state) and
|
|
59
|
+
* from {@link reduceAllFetchState} (Error only when every fetch failed).
|
|
60
|
+
*/
|
|
61
|
+
export function reduceFetchStateParallelTimeframes(fetchStateList) {
|
|
62
|
+
const isAnyProgress = fetchStateList.some((s) => s.fetchState === 'In-Progress');
|
|
63
|
+
const isAllCompleted = fetchStateList.every((s) => s.fetchState === 'Completed');
|
|
64
|
+
const isAnyError = fetchStateList.some((s) => s.fetchState === 'Error');
|
|
65
|
+
const error = reduceError(fetchStateList);
|
|
66
|
+
let fetchState = 'Not-Started';
|
|
67
|
+
if (isAnyProgress) {
|
|
68
|
+
fetchState = 'In-Progress';
|
|
69
|
+
}
|
|
70
|
+
else if (isAllCompleted) {
|
|
71
|
+
fetchState = 'Completed';
|
|
72
|
+
}
|
|
73
|
+
else if (isAnyError) {
|
|
74
|
+
fetchState = 'Error';
|
|
75
|
+
}
|
|
76
|
+
return { fetchState, error };
|
|
77
|
+
}
|
|
53
78
|
/**
|
|
54
79
|
* Reduces list of fetch state to boolean
|
|
55
80
|
* @param fetchStateList list of fetch states
|
package/lib/esm/index.js
CHANGED
|
@@ -14,7 +14,7 @@ import { getActualPeriodOfFY, getActualPeriodOfFYQtr, } from './commonStateTypes
|
|
|
14
14
|
import { getFYMonths } from './commonStateTypes/fiscalYearHelpers/getFYMonths';
|
|
15
15
|
import { getFYQuarterAndYear, getLastMonthOfFYQuarter, getLastMonthOfFYYear, } from './commonStateTypes/fiscalYearHelpers/getFYQuarterAndYear';
|
|
16
16
|
import { getStartOfAndEndOfTimeframeForFY } from './commonStateTypes/fiscalYearHelpers/getStartOfAndEndOfTimeframeFY';
|
|
17
|
-
import { isAllFetchCompleted, isAnyFetchInProgress, reduceAllFetchState, reduceAnyCompletedFetchState, reduceAnyFetchState, reduceFetchState, } from './commonStateTypes/reduceFetchState';
|
|
17
|
+
import { isAllFetchCompleted, isAnyFetchInProgress, reduceAllFetchState, reduceAnyCompletedFetchState, reduceAnyFetchState, reduceFetchState, reduceFetchStateParallelTimeframes, } from './commonStateTypes/reduceFetchState';
|
|
18
18
|
import { toReimbursementTypeCode } from './commonStateTypes/reimbursementTypeCode';
|
|
19
19
|
import { stringToUnion, stringToUnionStrict, } from './commonStateTypes/stringToUnion';
|
|
20
20
|
import { SCHEDULE_DAYS_OF_MONTH, convertToPeriod, toAbsoluteDay, toMonth, toMonthStrict, toMonthYearPeriodId, toQuarter, toQuarterStrict, toScheduleDaysOfMonth, } from './commonStateTypes/timePeriod';
|
|
@@ -544,7 +544,7 @@ export { saveRealTimeApproval, updateIsEditModeRealTimeApprovals, };
|
|
|
544
544
|
export { deleteRemi, fetchRemiDetail, cancelAndDeleteRemi, approveOrRejectRemi, clearRemiDetailView, fetchDuplicateReimbursement, clearDuplicateReimbursementDetail, removeDuplicateReimbursementByLineId, };
|
|
545
545
|
export { getEditRemiDetail, };
|
|
546
546
|
export { fetchEditRemiDetailPage, fetchRecommendationsAndUpdateMerchantRecommendations, fetchRemiAndInitializeLocalStore, initializeRemiToLocalStore, saveRemiUpdatesToLocalStore, fetchCurrencyConversionValue, discardRemiUpdatesInLocalStore, removeFileFromRemiUpdatesInLocalStore, saveRemiDetail, saveRemiSuccessOrFailure, parseReceiptsToRemi, clearEditRemiViewDetail, updateAddRemiAutoFields, updateUploadFetchState, updateTentativeMerchantNames, clearTentativeMerchantName, updateReimbursementType, updateHomeCurrencyConversion, clearAddRemiAutoFields, };
|
|
547
|
-
export { reduceFetchState, reduceAnyFetchState, reduceAllFetchState, reduceAnyCompletedFetchState, isAnyFetchInProgress, isAllFetchCompleted, ALL_FILE_TYPES, toFileTypeStrict, };
|
|
547
|
+
export { reduceFetchState, reduceFetchStateParallelTimeframes, reduceAnyFetchState, reduceAllFetchState, reduceAnyCompletedFetchState, isAnyFetchInProgress, isAllFetchCompleted, ALL_FILE_TYPES, toFileTypeStrict, };
|
|
548
548
|
export { getNextNthWorkingDay, getPreviousNthWorkingDay, isHolidayToday, filterDays, getYearsList, isHoliday, holidaysFormatted, PAYMENT_BUSINESS_DAYS, };
|
|
549
549
|
export { fetchCompanyOnboardingView, fetchQBOConnectionPool, updateQBOConnectionPoolExternalConnection, fetchOnboardingCompletedCompanies, saveOnboardingCustomerCompletedStatus, toProductType, toProductTypeStrict, getOnboardingCockpitView, getNewOnboardingCustomerView, getOnboardingEmailGroup, initializeOnboardingCustomerViewUpdateData, clearOnboardingCustomerViewUpdateData, saveOnboardingCustomerViewUpdateData, updateOnboardingCustomerListUIState, updateCustomerCreationStatus, updateStatusAfterOnboardingCompleted, saveOnboardingCustomerViewUpdates, saveOnboardingCustomerNotes, saveOnboardingCustomerDataInLocalStore, updateOnboardingCustomerDataInLocalStore, resetNewOnboardedCustomerId, sendOnboardingCustomerViewInvite, retryBankAccountConnectionForOnboarding, };
|
|
550
550
|
export { getTransactionsListByCategoryType, getTransactionListUIStateByCategoryType, };
|
|
@@ -44,7 +44,7 @@ const financeStatement = createSlice({
|
|
|
44
44
|
updateFinanceStatementThisPeriod(draft, action) {
|
|
45
45
|
const { firstMonthOfFY, coaBalances, maxNumOfPeriodsToHighlight } = action.payload;
|
|
46
46
|
const { timeframe, selectedCOABalancesRange } = draft;
|
|
47
|
-
const safeCoaBalances = coaBalances
|
|
47
|
+
const safeCoaBalances = coaBalances != null ? coaBalances : [];
|
|
48
48
|
if (safeCoaBalances.length > 0) {
|
|
49
49
|
const prevThisPeriod = extractThisPeriod(action.payload.firstMonthOfFY, timeframe, selectedCOABalancesRange, safeCoaBalances);
|
|
50
50
|
if (prevThisPeriod != null) {
|
|
@@ -77,7 +77,7 @@ const financeStatement = createSlice({
|
|
|
77
77
|
},
|
|
78
78
|
updateFinanceStatementAdditionalBalancesSelection(draft, action) {
|
|
79
79
|
const { firstMonthOfFY, additionalBalances: additionalBalancesPayload, coaBalances, maxNumOfPeriodsToHighlight, } = action.payload;
|
|
80
|
-
const safeCoaBalances = coaBalances
|
|
80
|
+
const safeCoaBalances = coaBalances != null ? coaBalances : [];
|
|
81
81
|
const additionalBalances = additionalBalancesPayload ?? [];
|
|
82
82
|
let tempAdditionalBalances = [...additionalBalances];
|
|
83
83
|
if (additionalBalances.includes('this_period_vs_last_period') ||
|
|
@@ -43,15 +43,11 @@ export const getFinanceStatement = createSelector((state) => state.accountState,
|
|
|
43
43
|
if (dataAvailable != null) {
|
|
44
44
|
const noFilter = newBalancesFilterForDateRange(firstMonthOfFY, financeStatementState.timeframe, dataAvailable, 'ascending_date', []);
|
|
45
45
|
const profitAndLossForTimeframeTicks = getProfitAndLossReport(noFilter, undefined, accountState, accountGroupState, sectionAccountsViewState, profitAndLossState, forecastState);
|
|
46
|
-
const
|
|
47
|
-
const
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
if (
|
|
51
|
-
balancesInTimeframe =
|
|
52
|
-
(expensesBalances?.length ?? 0) > 0
|
|
53
|
-
? expensesBalances ?? []
|
|
54
|
-
: incomeBalances ?? [];
|
|
46
|
+
const expensesBalances = profitAndLossForTimeframeTicks.sections.expenses?.balances ?? [];
|
|
47
|
+
const incomeBalances = profitAndLossForTimeframeTicks.sections.income?.balances ?? [];
|
|
48
|
+
balancesInTimeframe =
|
|
49
|
+
expensesBalances.length > 0 ? expensesBalances : incomeBalances;
|
|
50
|
+
if (balancesInTimeframe.length > 0) {
|
|
55
51
|
allTimeframeTicks = balancesInTimeframe.map((balance) => toTimeframeTick(balance));
|
|
56
52
|
}
|
|
57
53
|
}
|
|
@@ -65,9 +61,9 @@ export const getFinanceStatement = createSelector((state) => state.accountState,
|
|
|
65
61
|
const profitAndLossReport = getProfitAndLossReport(filter, undefined, accountState, accountGroupState, sectionAccountsViewState, profitAndLossState, forecastState);
|
|
66
62
|
const classFilter = newBalancesFilterClassesView(filter.firstMonthOfFY, filter.timeframe, filter.balancesRange.numberOfPeriods, filter.balancesRange.thisPeriod, filter.balancesRange.orderBy, filter.additionalBalances, profitAndLossClassesViewState.uiState.classesToFilterOut);
|
|
67
63
|
const profitAndLossByClassReport = getProfitAndLossClassesView(classFilter, accountState, classState, sectionsState, profitAndLossClassesViewState);
|
|
68
|
-
const profitAndLossByClassHorizontalReport = profitAndLossClassesViewState.uiState.classViewLayout === 'horizontal'
|
|
69
|
-
?
|
|
70
|
-
:
|
|
64
|
+
const profitAndLossByClassHorizontalReport = getProfitAndLossClassesHorizontalView(classFilter, accountState, classState, sectionsState, profitAndLossClassesViewState, profitAndLossClassesViewState.uiState.classViewLayout === 'horizontal'
|
|
65
|
+
? thisPeriod
|
|
66
|
+
: undefined);
|
|
71
67
|
const balanceSheetReport = getBalanceSheet(filter, accountState, accountGroupState, sectionAccountsViewState, balanceSheetState);
|
|
72
68
|
const cashFlowReport = getCashFlow(filter, accountState, accountGroupState, sectionAccountsViewState, cashFlowState);
|
|
73
69
|
const allReports = [
|
package/lib/esm/view/profitAndLossClassesView/profitAndLossClassesByClassHorizontalSelector.js
CHANGED
|
@@ -1,7 +1,11 @@
|
|
|
1
1
|
import { toAmountWC } from '../../commonStateTypes/amount';
|
|
2
|
+
import { reduceFetchStateParallelTimeframes } from '../../commonStateTypes/reduceFetchState';
|
|
2
3
|
import { getSectionClassesViewReport } from '../../entity/sectionClassesViewV2/sectionClassesViewSelector';
|
|
3
|
-
|
|
4
|
-
const
|
|
4
|
+
/** If `ProfitAndLossClassesViewState.currency` is unset (e.g. tests). */
|
|
5
|
+
const FALLBACK_REPORT_CURRENCY = {
|
|
6
|
+
currencyCode: 'USD',
|
|
7
|
+
currencySymbol: '$',
|
|
8
|
+
};
|
|
5
9
|
export const profitAndLossHorizontalIdsInOrder = [
|
|
6
10
|
'income',
|
|
7
11
|
'cogs',
|
|
@@ -24,8 +28,16 @@ const SECTION_TITLES = {
|
|
|
24
28
|
netOtherIncome: 'Net Other Income',
|
|
25
29
|
netIncome: 'Net Income',
|
|
26
30
|
};
|
|
31
|
+
/** Sections fetched and pivoted for horizontal layout (excludes e.g. `netOperatingIncome`). */
|
|
32
|
+
const HORIZONTAL_PANDL_SECTION_IDS = [
|
|
33
|
+
'income',
|
|
34
|
+
'cogs',
|
|
35
|
+
'expenses',
|
|
36
|
+
'otherIncome',
|
|
37
|
+
'otherExpenses',
|
|
38
|
+
];
|
|
27
39
|
export const getProfitAndLossClassesHorizontalView = (filter, accountState, classState, sectionsState, profitAndLossClassesViewState, selectedPeriod) => {
|
|
28
|
-
const fetchState =
|
|
40
|
+
const fetchState = reduceFetchStateParallelTimeframes([
|
|
29
41
|
profitAndLossClassesViewState.fetchState.month,
|
|
30
42
|
profitAndLossClassesViewState.fetchState.quarter,
|
|
31
43
|
profitAndLossClassesViewState.fetchState.year,
|
|
@@ -35,24 +47,20 @@ export const getProfitAndLossClassesHorizontalView = (filter, accountState, clas
|
|
|
35
47
|
const classColumns = buildClassColumns(profitAndLossClassesViewState.classHierarchy, profitAndLossClassesViewState.uiState.classesToFilterOut);
|
|
36
48
|
const sections = {};
|
|
37
49
|
const calculatedSections = {};
|
|
50
|
+
let reportCurrency = FALLBACK_REPORT_CURRENCY;
|
|
38
51
|
if (fetchState.fetchState === 'Completed' && selectedPeriod != null) {
|
|
39
52
|
// Get section reports using existing selector infrastructure
|
|
40
53
|
const sectionReports = {};
|
|
41
|
-
|
|
54
|
+
HORIZONTAL_PANDL_SECTION_IDS.forEach((sectionId) => {
|
|
42
55
|
sectionReports[sectionId] = getSectionClassesViewReport(accountState, classState, sectionsState, { reportId, sectionId }, filter);
|
|
43
56
|
});
|
|
57
|
+
reportCurrency =
|
|
58
|
+
profitAndLossClassesViewState.currency ?? FALLBACK_REPORT_CURRENCY;
|
|
44
59
|
// Pivot each section from class→account to account→class
|
|
45
|
-
|
|
46
|
-
'income',
|
|
47
|
-
'cogs',
|
|
48
|
-
'expenses',
|
|
49
|
-
'otherIncome',
|
|
50
|
-
'otherExpenses',
|
|
51
|
-
];
|
|
52
|
-
sectionIds.forEach((sectionId) => {
|
|
60
|
+
HORIZONTAL_PANDL_SECTION_IDS.forEach((sectionId) => {
|
|
53
61
|
const sectionReport = sectionReports[sectionId];
|
|
54
62
|
if (sectionReport != null) {
|
|
55
|
-
sections[sectionId] = pivotSectionToHorizontal(sectionReport, classColumns, SECTION_TITLES[sectionId] ?? sectionId);
|
|
63
|
+
sections[sectionId] = pivotSectionToHorizontal(sectionReport, classColumns, SECTION_TITLES[sectionId] ?? sectionId, reportCurrency);
|
|
56
64
|
}
|
|
57
65
|
});
|
|
58
66
|
// Calculate derived sections
|
|
@@ -83,7 +91,7 @@ export const getProfitAndLossClassesHorizontalView = (filter, accountState, clas
|
|
|
83
91
|
}
|
|
84
92
|
}
|
|
85
93
|
// Build synthetic header COABalances for rendering class names as column headers
|
|
86
|
-
const headerBalances = buildHeaderBalances(classColumns, filter.timeframe, selectedPeriod);
|
|
94
|
+
const headerBalances = buildHeaderBalances(classColumns, filter.timeframe, selectedPeriod, reportCurrency);
|
|
87
95
|
return {
|
|
88
96
|
reportId,
|
|
89
97
|
reportTitle: 'Profit and Loss by Class',
|
|
@@ -104,19 +112,21 @@ export const getProfitAndLossClassesHorizontalView = (filter, accountState, clas
|
|
|
104
112
|
* Build column definitions from class hierarchy (top-level classes only).
|
|
105
113
|
*/
|
|
106
114
|
function buildClassColumns(classHierarchy, classesToFilterOut) {
|
|
115
|
+
const filteredIds = new Set(classesToFilterOut.map((id) => id[0]));
|
|
107
116
|
return classHierarchy
|
|
108
|
-
.filter((c) => !
|
|
117
|
+
.filter((c) => !filteredIds.has(c.classId[0]))
|
|
109
118
|
.map((c) => ({
|
|
110
119
|
classId: c.classId[0],
|
|
111
120
|
className: c.className,
|
|
112
121
|
nestedClassId: c.classId,
|
|
113
122
|
qboId: c.qboId,
|
|
114
|
-
}))
|
|
123
|
+
}))
|
|
124
|
+
.sort((a, b) => a.className.localeCompare(b.className, undefined, { sensitivity: 'base' }));
|
|
115
125
|
}
|
|
116
126
|
/**
|
|
117
127
|
* Pivot a section from class→account→balances to account→class→balance (single period).
|
|
118
128
|
*/
|
|
119
|
-
function pivotSectionToHorizontal(section, classColumns, title) {
|
|
129
|
+
function pivotSectionToHorizontal(section, classColumns, title, currency) {
|
|
120
130
|
// Map: accountId -> { accountName, classId -> balance }
|
|
121
131
|
const accountMap = new Map();
|
|
122
132
|
// Also track class totals
|
|
@@ -126,7 +136,7 @@ function pivotSectionToHorizontal(section, classColumns, title) {
|
|
|
126
136
|
section.classes.forEach((classReport) => {
|
|
127
137
|
const classId = classReport.id[0];
|
|
128
138
|
// Only process classes that are in our columns
|
|
129
|
-
if (!
|
|
139
|
+
if (!classTotalMap.has(classId)) {
|
|
130
140
|
return;
|
|
131
141
|
}
|
|
132
142
|
// Sum all sliced period balances (same slice as vertical columns; multi-period = range total)
|
|
@@ -140,27 +150,27 @@ function pivotSectionToHorizontal(section, classColumns, title) {
|
|
|
140
150
|
accountMap.forEach((accountData, accountId) => {
|
|
141
151
|
const classBalances = classColumns.map((col) => ({
|
|
142
152
|
classId: col.classId,
|
|
143
|
-
balance: toAmountWC(accountData.classBalances.get(col.classId) ?? 0,
|
|
153
|
+
balance: toAmountWC(accountData.classBalances.get(col.classId) ?? 0, currency),
|
|
144
154
|
}));
|
|
145
155
|
const rowTotal = classBalances.reduce((sum, cb) => sum + cb.balance.amount, 0);
|
|
146
156
|
accounts.push({
|
|
147
157
|
accountId,
|
|
148
158
|
accountName: accountData.accountName,
|
|
149
159
|
classBalances,
|
|
150
|
-
rowTotal: toAmountWC(rowTotal,
|
|
160
|
+
rowTotal: toAmountWC(rowTotal, currency),
|
|
151
161
|
});
|
|
152
162
|
});
|
|
153
163
|
// Build class totals
|
|
154
164
|
const classTotals = classColumns.map((col) => ({
|
|
155
165
|
classId: col.classId,
|
|
156
|
-
balance: toAmountWC(classTotalMap.get(col.classId) ?? 0,
|
|
166
|
+
balance: toAmountWC(classTotalMap.get(col.classId) ?? 0, currency),
|
|
157
167
|
}));
|
|
158
168
|
const sectionTotal = classTotals.reduce((sum, ct) => sum + ct.balance.amount, 0);
|
|
159
169
|
return {
|
|
160
170
|
title,
|
|
161
171
|
accounts,
|
|
162
172
|
classTotals,
|
|
163
|
-
sectionTotal: toAmountWC(sectionTotal,
|
|
173
|
+
sectionTotal: toAmountWC(sectionTotal, currency),
|
|
164
174
|
};
|
|
165
175
|
}
|
|
166
176
|
/**
|
|
@@ -205,8 +215,7 @@ function collectAccountsFromNestedAccount(nestedAccount, classId, accountMap) {
|
|
|
205
215
|
function sumBalancesInSlice(balances) {
|
|
206
216
|
let sum = 0;
|
|
207
217
|
for (const bal of balances) {
|
|
208
|
-
|
|
209
|
-
sum += b.balance?.amount ?? 0;
|
|
218
|
+
sum += bal.balance?.amount ?? 0;
|
|
210
219
|
}
|
|
211
220
|
return sum;
|
|
212
221
|
}
|
|
@@ -214,15 +223,19 @@ function sumBalancesInSlice(balances) {
|
|
|
214
223
|
* Compute a calculated section by adding or subtracting two sets of class totals.
|
|
215
224
|
*/
|
|
216
225
|
function computeCalculatedSection(aTotals, bTotals, aTotal, bTotal, operation, title) {
|
|
226
|
+
const currency = {
|
|
227
|
+
currencyCode: aTotal.currencyCode,
|
|
228
|
+
currencySymbol: aTotal.currencySymbol,
|
|
229
|
+
};
|
|
230
|
+
const bTotalsMap = new Map(bTotals.map((b) => [b.classId, b.balance.amount]));
|
|
217
231
|
const classTotals = aTotals.map((a) => {
|
|
218
|
-
const
|
|
219
|
-
const bAmount = bMatch?.balance.amount ?? 0;
|
|
232
|
+
const bAmount = bTotalsMap.get(a.classId) ?? 0;
|
|
220
233
|
const resultAmount = operation === 'add'
|
|
221
234
|
? a.balance.amount + bAmount
|
|
222
235
|
: a.balance.amount - bAmount;
|
|
223
236
|
return {
|
|
224
237
|
classId: a.classId,
|
|
225
|
-
balance: toAmountWC(resultAmount,
|
|
238
|
+
balance: toAmountWC(resultAmount, currency),
|
|
226
239
|
};
|
|
227
240
|
});
|
|
228
241
|
const sectionTotalAmount = operation === 'add'
|
|
@@ -231,20 +244,20 @@ function computeCalculatedSection(aTotals, bTotals, aTotal, bTotal, operation, t
|
|
|
231
244
|
return {
|
|
232
245
|
title,
|
|
233
246
|
classTotals,
|
|
234
|
-
sectionTotal: toAmountWC(sectionTotalAmount,
|
|
247
|
+
sectionTotal: toAmountWC(sectionTotalAmount, currency),
|
|
235
248
|
};
|
|
236
249
|
}
|
|
237
250
|
/**
|
|
238
251
|
* Build synthetic COABalance array for header rendering.
|
|
239
252
|
* One entry per class column + one for "Total".
|
|
240
253
|
*/
|
|
241
|
-
function buildHeaderBalances(classColumns, timeframe, selectedPeriod) {
|
|
254
|
+
function buildHeaderBalances(classColumns, timeframe, selectedPeriod, currency) {
|
|
242
255
|
if (selectedPeriod == null) {
|
|
243
256
|
return [];
|
|
244
257
|
}
|
|
245
258
|
const { endDate, startDate } = selectedPeriod;
|
|
246
259
|
const balances = classColumns.map((col) => ({
|
|
247
|
-
balance: toAmountWC(0,
|
|
260
|
+
balance: toAmountWC(0, currency),
|
|
248
261
|
balanceTimeFrame: timeframe,
|
|
249
262
|
endDate,
|
|
250
263
|
startDate,
|
|
@@ -253,7 +266,7 @@ function buildHeaderBalances(classColumns, timeframe, selectedPeriod) {
|
|
|
253
266
|
}));
|
|
254
267
|
// Add a "Total" column
|
|
255
268
|
balances.push({
|
|
256
|
-
balance: toAmountWC(0,
|
|
269
|
+
balance: toAmountWC(0, currency),
|
|
257
270
|
balanceTimeFrame: timeframe,
|
|
258
271
|
endDate,
|
|
259
272
|
startDate,
|
|
@@ -262,20 +275,3 @@ function buildHeaderBalances(classColumns, timeframe, selectedPeriod) {
|
|
|
262
275
|
});
|
|
263
276
|
return balances;
|
|
264
277
|
}
|
|
265
|
-
function reduceFetchState(fetchStateList) {
|
|
266
|
-
const isAnyProgress = fetchStateList.some((s) => s.fetchState === 'In-Progress');
|
|
267
|
-
const isAllCompleted = fetchStateList.every((s) => s.fetchState === 'Completed');
|
|
268
|
-
const isAnyError = fetchStateList.some((s) => s.fetchState === 'Error');
|
|
269
|
-
const error = fetchStateList.find((s) => s.error != null)?.error;
|
|
270
|
-
let fetchState = 'Not-Started';
|
|
271
|
-
if (isAnyProgress) {
|
|
272
|
-
fetchState = 'In-Progress';
|
|
273
|
-
}
|
|
274
|
-
else if (isAllCompleted) {
|
|
275
|
-
fetchState = 'Completed';
|
|
276
|
-
}
|
|
277
|
-
else if (isAnyError) {
|
|
278
|
-
fetchState = 'Error';
|
|
279
|
-
}
|
|
280
|
-
return { fetchState, error };
|
|
281
|
-
}
|
|
@@ -110,6 +110,7 @@ export const { fetchProfitAndLossClassesView, fetchProfitAndLossForTimeframeClas
|
|
|
110
110
|
export default profitAndLossClassesView.reducer;
|
|
111
111
|
const doUpdatedProfitAndLossClassesView = (draft, timeframe, pandLReport) => {
|
|
112
112
|
const report = mapReportPayloadV2ToReportV2(pandLReport.report);
|
|
113
|
+
draft.currency = report.currency;
|
|
113
114
|
draft.dataAvailable = report.dataAvailable;
|
|
114
115
|
draft.firstMonthOfFY = report.firstMonthOfFY;
|
|
115
116
|
draft.bookCloseDate = report.bookCloseDate;
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { getDifferenceOfBalancesGroupedByPeriod } from '../../commonStateTypes/coaBalance/classBalances/getDifferenceOfBalancesGroupedByPeriod';
|
|
2
2
|
import { getSumOfBalancesByGroupedByPeriod } from '../../commonStateTypes/coaBalance/classBalances/getSumOfBalancesGroupedByPeriod';
|
|
3
3
|
import { getCOABalances } from '../../commonStateTypes/coaBalance/coaBalance';
|
|
4
|
+
import { reduceFetchStateParallelTimeframes } from '../../commonStateTypes/reduceFetchState';
|
|
4
5
|
import { getSectionClassesViewReport } from '../../entity/sectionClassesViewV2/sectionClassesViewSelector';
|
|
5
6
|
import { ALL_PANDL_REPORT_VIEW_SECTION_IDS, } from './profitAndLossClassesViewSelectorTypes';
|
|
6
7
|
export const profitAndLossIdsInOrder = [
|
|
@@ -15,7 +16,7 @@ export const profitAndLossIdsInOrder = [
|
|
|
15
16
|
'netIncome',
|
|
16
17
|
];
|
|
17
18
|
export const getProfitAndLossClassesView = (filter, accountState, classState, sectionsState, profitAndLossClassesViewState) => {
|
|
18
|
-
const fetchState =
|
|
19
|
+
const fetchState = reduceFetchStateParallelTimeframes([
|
|
19
20
|
profitAndLossClassesViewState.fetchState.month,
|
|
20
21
|
profitAndLossClassesViewState.fetchState.quarter,
|
|
21
22
|
profitAndLossClassesViewState.fetchState.year,
|
|
@@ -64,31 +65,3 @@ export const getProfitAndLossClassesView = (filter, accountState, classState, se
|
|
|
64
65
|
idsInOrder: profitAndLossIdsInOrder,
|
|
65
66
|
};
|
|
66
67
|
};
|
|
67
|
-
function reduceFetchState(fetchStateList) {
|
|
68
|
-
const isAnyProgress = fetchStateList.reduce((prevValue, currentValue) => {
|
|
69
|
-
return prevValue === true || currentValue.fetchState === 'In-Progress';
|
|
70
|
-
}, false);
|
|
71
|
-
const isAllCompleted = fetchStateList.reduce((prevValue, currentValue) => {
|
|
72
|
-
return prevValue === true && currentValue.fetchState === 'Completed';
|
|
73
|
-
}, true);
|
|
74
|
-
const isAnyError = fetchStateList.reduce((prevValue, currentValue) => {
|
|
75
|
-
return prevValue === true || currentValue.fetchState === 'Error';
|
|
76
|
-
}, false);
|
|
77
|
-
const error = fetchStateList.reduce((prevValue, currentValue) => {
|
|
78
|
-
return prevValue ?? currentValue.error;
|
|
79
|
-
}, undefined);
|
|
80
|
-
let fetchState = 'Not-Started';
|
|
81
|
-
if (isAnyProgress) {
|
|
82
|
-
fetchState = 'In-Progress';
|
|
83
|
-
}
|
|
84
|
-
else if (isAllCompleted) {
|
|
85
|
-
fetchState = 'Completed';
|
|
86
|
-
}
|
|
87
|
-
else if (isAnyError) {
|
|
88
|
-
fetchState = 'Error';
|
|
89
|
-
}
|
|
90
|
-
return {
|
|
91
|
-
fetchState,
|
|
92
|
-
error,
|
|
93
|
-
};
|
|
94
|
-
}
|
|
@@ -24,11 +24,13 @@ export const fetchProfitAndLossForTimeframeClassesViewEpic = (actions$, _, zeniA
|
|
|
24
24
|
.pipe(mergeMap((response) => {
|
|
25
25
|
if (response.data != null && isSuccessResponse(response)) {
|
|
26
26
|
const actions = [];
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
actions.push(updateSectionClassesView(action.payload.timeframe, '
|
|
30
|
-
actions.push(updateSectionClassesView(action.payload.timeframe, '
|
|
31
|
-
actions.push(updateSectionClassesView(action.payload.timeframe, '
|
|
27
|
+
const report = response.data.report;
|
|
28
|
+
const currency = report.currency;
|
|
29
|
+
actions.push(updateSectionClassesView(action.payload.timeframe, 'cogs', 'profit_and_loss_by_classes', report.cogs, report.classes, report.accounts, currency));
|
|
30
|
+
actions.push(updateSectionClassesView(action.payload.timeframe, 'expenses', 'profit_and_loss_by_classes', report.expenses, report.classes, report.accounts, currency));
|
|
31
|
+
actions.push(updateSectionClassesView(action.payload.timeframe, 'income', 'profit_and_loss_by_classes', report.income, report.classes, report.accounts, currency));
|
|
32
|
+
actions.push(updateSectionClassesView(action.payload.timeframe, 'otherExpenses', 'profit_and_loss_by_classes', report.other_expenses, report.classes, report.accounts, currency));
|
|
33
|
+
actions.push(updateSectionClassesView(action.payload.timeframe, 'otherIncome', 'profit_and_loss_by_classes', report.other_income, report.classes, report.accounts, currency));
|
|
32
34
|
actions.push(updateProfitAndLossForTimeframeClassesView({
|
|
33
35
|
timeframe: action.payload.timeframe,
|
|
34
36
|
report: response.data,
|
|
@@ -2,15 +2,19 @@ import { of } from 'rxjs';
|
|
|
2
2
|
import { filter, switchMap } from 'rxjs/operators';
|
|
3
3
|
import { updateCashInCashOutCOABalancesRange } from '../cashInCashOut/cashInCashOutReducer';
|
|
4
4
|
import { updateCashPositionCOABalancesRange } from '../cashPosition/cashPositionReducer';
|
|
5
|
-
import {
|
|
5
|
+
import { updateCOABalancesRange } from '../financeStatement/financeStatementReducer';
|
|
6
6
|
import { updateNetBurnOrIncomeCOABalancesRange } from '../netBurnOrIncome/netBurnOrIncomeReducer';
|
|
7
7
|
import { updateOpExCOABalancesRange } from '../opEx/opExReducer';
|
|
8
8
|
import { updateRevenueCOABalancesRange } from '../revenue/revenueReducer';
|
|
9
9
|
import { updateReportUIOptionCOABalancesRange } from './reportUIOptionsReducer';
|
|
10
10
|
export const updateReportUIOptionCOABalancesRangeEpic = (actions$, state$) => actions$.pipe(filter(updateReportUIOptionCOABalancesRange.match), switchMap((action) => {
|
|
11
|
-
const
|
|
12
|
-
const
|
|
13
|
-
const
|
|
11
|
+
const selectedRange = action.payload.selectedCOABalancesRange;
|
|
12
|
+
const thisPeriod = selectedRange.thisPeriod;
|
|
13
|
+
const orderBy = selectedRange.orderBy;
|
|
14
|
+
const numberOfPeriodsFromSelection = selectedRange.numberOfPeriods;
|
|
15
|
+
const highlightedNoOfPeriods = state$.value.reportUIOptionsState.isCompareModeOn === true
|
|
16
|
+
? numberOfPeriodsFromSelection
|
|
17
|
+
: 1;
|
|
14
18
|
const highlightedCOABalancesRange = action.payload.highlightedCOABalancesRange == null && thisPeriod != null
|
|
15
19
|
? {
|
|
16
20
|
numberOfPeriods: highlightedNoOfPeriods,
|
|
@@ -62,9 +66,7 @@ export const updateReportUIOptionCOABalancesRangeEpic = (actions$, state$) => ac
|
|
|
62
66
|
thisPeriod: action.payload.highlightedCOABalancesRange != null
|
|
63
67
|
? action.payload.highlightedCOABalancesRange.thisPeriod
|
|
64
68
|
: thisPeriod,
|
|
65
|
-
numberOfPeriods:
|
|
66
|
-
? 4
|
|
67
|
-
: initialFinanceStatementState.maxNumOfPeriodsToHighlight,
|
|
69
|
+
numberOfPeriods: numberOfPeriodsFromSelection,
|
|
68
70
|
orderBy,
|
|
69
71
|
}));
|
|
70
72
|
}));
|
package/lib/index.d.ts
CHANGED
|
@@ -24,7 +24,7 @@ import { getFYMonths } from './commonStateTypes/fiscalYearHelpers/getFYMonths';
|
|
|
24
24
|
import { getFYQuarterAndYear, getLastMonthOfFYQuarter, getLastMonthOfFYYear } from './commonStateTypes/fiscalYearHelpers/getFYQuarterAndYear';
|
|
25
25
|
import { getStartOfAndEndOfTimeframeForFY } from './commonStateTypes/fiscalYearHelpers/getStartOfAndEndOfTimeframeFY';
|
|
26
26
|
import { COTLineItemTracking, COTRecommendationTracking, COTTransactionTracking, COTTransactionTrackingByTransactionId, Recommendation, RecommendationWithCOT, TransactionLineRecommendationFieldTypes } from './commonStateTypes/recommendationBase';
|
|
27
|
-
import { isAllFetchCompleted, isAnyFetchInProgress, reduceAllFetchState, reduceAnyCompletedFetchState, reduceAnyFetchState, reduceFetchState } from './commonStateTypes/reduceFetchState';
|
|
27
|
+
import { isAllFetchCompleted, isAnyFetchInProgress, reduceAllFetchState, reduceAnyCompletedFetchState, reduceAnyFetchState, reduceFetchState, reduceFetchStateParallelTimeframes } from './commonStateTypes/reduceFetchState';
|
|
28
28
|
import { toReimbursementTypeCode } from './commonStateTypes/reimbursementTypeCode';
|
|
29
29
|
import { ClassesViewSelectorReportV2 } from './commonStateTypes/selectorTypes/classesViewSelectorReport';
|
|
30
30
|
import { COABalancesSliceOrder, CalculatedSection, EntityOrder, Section, SectionWithAccountOnly, TransactionsOrder } from './commonStateTypes/selectorTypes/selectorTypes';
|
|
@@ -782,7 +782,7 @@ export { RemiDetailLocalData, AutoFields, OutofPocketReimbursementLineWithRecomm
|
|
|
782
782
|
export { Merchant };
|
|
783
783
|
export { fetchEditRemiDetailPage, fetchRecommendationsAndUpdateMerchantRecommendations, fetchRemiAndInitializeLocalStore, initializeRemiToLocalStore, saveRemiUpdatesToLocalStore, fetchCurrencyConversionValue, discardRemiUpdatesInLocalStore, removeFileFromRemiUpdatesInLocalStore, saveRemiDetail, saveRemiSuccessOrFailure, parseReceiptsToRemi, clearEditRemiViewDetail, updateAddRemiAutoFields, updateUploadFetchState, updateTentativeMerchantNames, clearTentativeMerchantName, updateReimbursementType, updateHomeCurrencyConversion, clearAddRemiAutoFields, };
|
|
784
784
|
export { AnimationFileName };
|
|
785
|
-
export { reduceFetchState, reduceAnyFetchState, reduceAllFetchState, reduceAnyCompletedFetchState, isAnyFetchInProgress, isAllFetchCompleted, SortOrder, ALL_FILE_TYPES, FileType, toFileTypeStrict, };
|
|
785
|
+
export { reduceFetchState, reduceFetchStateParallelTimeframes, reduceAnyFetchState, reduceAllFetchState, reduceAnyCompletedFetchState, isAnyFetchInProgress, isAllFetchCompleted, SortOrder, ALL_FILE_TYPES, FileType, toFileTypeStrict, };
|
|
786
786
|
export { getNextNthWorkingDay, getPreviousNthWorkingDay, isHolidayToday, filterDays, getYearsList, isHoliday, holidaysFormatted, PAYMENT_BUSINESS_DAYS, };
|
|
787
787
|
export { CustomerRatingCodeType, TeamRatingCodeType };
|
|
788
788
|
export { CustomerSatisfactionInfo };
|