@zeniai/client-epic-state 4.19.91-beta0ND → 4.19.91-beta1ND
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 +42 -47
- 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/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 +42 -47
- 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/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,8 +112,9 @@ 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,
|
|
@@ -116,7 +125,7 @@ function buildClassColumns(classHierarchy, classesToFilterOut) {
|
|
|
116
125
|
/**
|
|
117
126
|
* Pivot a section from class→account→balances to account→class→balance (single period).
|
|
118
127
|
*/
|
|
119
|
-
function pivotSectionToHorizontal(section, classColumns, title) {
|
|
128
|
+
function pivotSectionToHorizontal(section, classColumns, title, currency) {
|
|
120
129
|
// Map: accountId -> { accountName, classId -> balance }
|
|
121
130
|
const accountMap = new Map();
|
|
122
131
|
// Also track class totals
|
|
@@ -126,7 +135,7 @@ function pivotSectionToHorizontal(section, classColumns, title) {
|
|
|
126
135
|
section.classes.forEach((classReport) => {
|
|
127
136
|
const classId = classReport.id[0];
|
|
128
137
|
// Only process classes that are in our columns
|
|
129
|
-
if (!
|
|
138
|
+
if (!classTotalMap.has(classId)) {
|
|
130
139
|
return;
|
|
131
140
|
}
|
|
132
141
|
// Sum all sliced period balances (same slice as vertical columns; multi-period = range total)
|
|
@@ -140,27 +149,27 @@ function pivotSectionToHorizontal(section, classColumns, title) {
|
|
|
140
149
|
accountMap.forEach((accountData, accountId) => {
|
|
141
150
|
const classBalances = classColumns.map((col) => ({
|
|
142
151
|
classId: col.classId,
|
|
143
|
-
balance: toAmountWC(accountData.classBalances.get(col.classId) ?? 0,
|
|
152
|
+
balance: toAmountWC(accountData.classBalances.get(col.classId) ?? 0, currency),
|
|
144
153
|
}));
|
|
145
154
|
const rowTotal = classBalances.reduce((sum, cb) => sum + cb.balance.amount, 0);
|
|
146
155
|
accounts.push({
|
|
147
156
|
accountId,
|
|
148
157
|
accountName: accountData.accountName,
|
|
149
158
|
classBalances,
|
|
150
|
-
rowTotal: toAmountWC(rowTotal,
|
|
159
|
+
rowTotal: toAmountWC(rowTotal, currency),
|
|
151
160
|
});
|
|
152
161
|
});
|
|
153
162
|
// Build class totals
|
|
154
163
|
const classTotals = classColumns.map((col) => ({
|
|
155
164
|
classId: col.classId,
|
|
156
|
-
balance: toAmountWC(classTotalMap.get(col.classId) ?? 0,
|
|
165
|
+
balance: toAmountWC(classTotalMap.get(col.classId) ?? 0, currency),
|
|
157
166
|
}));
|
|
158
167
|
const sectionTotal = classTotals.reduce((sum, ct) => sum + ct.balance.amount, 0);
|
|
159
168
|
return {
|
|
160
169
|
title,
|
|
161
170
|
accounts,
|
|
162
171
|
classTotals,
|
|
163
|
-
sectionTotal: toAmountWC(sectionTotal,
|
|
172
|
+
sectionTotal: toAmountWC(sectionTotal, currency),
|
|
164
173
|
};
|
|
165
174
|
}
|
|
166
175
|
/**
|
|
@@ -205,8 +214,7 @@ function collectAccountsFromNestedAccount(nestedAccount, classId, accountMap) {
|
|
|
205
214
|
function sumBalancesInSlice(balances) {
|
|
206
215
|
let sum = 0;
|
|
207
216
|
for (const bal of balances) {
|
|
208
|
-
|
|
209
|
-
sum += b.balance?.amount ?? 0;
|
|
217
|
+
sum += bal.balance?.amount ?? 0;
|
|
210
218
|
}
|
|
211
219
|
return sum;
|
|
212
220
|
}
|
|
@@ -214,15 +222,19 @@ function sumBalancesInSlice(balances) {
|
|
|
214
222
|
* Compute a calculated section by adding or subtracting two sets of class totals.
|
|
215
223
|
*/
|
|
216
224
|
function computeCalculatedSection(aTotals, bTotals, aTotal, bTotal, operation, title) {
|
|
225
|
+
const currency = {
|
|
226
|
+
currencyCode: aTotal.currencyCode,
|
|
227
|
+
currencySymbol: aTotal.currencySymbol,
|
|
228
|
+
};
|
|
229
|
+
const bTotalsMap = new Map(bTotals.map((b) => [b.classId, b.balance.amount]));
|
|
217
230
|
const classTotals = aTotals.map((a) => {
|
|
218
|
-
const
|
|
219
|
-
const bAmount = bMatch?.balance.amount ?? 0;
|
|
231
|
+
const bAmount = bTotalsMap.get(a.classId) ?? 0;
|
|
220
232
|
const resultAmount = operation === 'add'
|
|
221
233
|
? a.balance.amount + bAmount
|
|
222
234
|
: a.balance.amount - bAmount;
|
|
223
235
|
return {
|
|
224
236
|
classId: a.classId,
|
|
225
|
-
balance: toAmountWC(resultAmount,
|
|
237
|
+
balance: toAmountWC(resultAmount, currency),
|
|
226
238
|
};
|
|
227
239
|
});
|
|
228
240
|
const sectionTotalAmount = operation === 'add'
|
|
@@ -231,20 +243,20 @@ function computeCalculatedSection(aTotals, bTotals, aTotal, bTotal, operation, t
|
|
|
231
243
|
return {
|
|
232
244
|
title,
|
|
233
245
|
classTotals,
|
|
234
|
-
sectionTotal: toAmountWC(sectionTotalAmount,
|
|
246
|
+
sectionTotal: toAmountWC(sectionTotalAmount, currency),
|
|
235
247
|
};
|
|
236
248
|
}
|
|
237
249
|
/**
|
|
238
250
|
* Build synthetic COABalance array for header rendering.
|
|
239
251
|
* One entry per class column + one for "Total".
|
|
240
252
|
*/
|
|
241
|
-
function buildHeaderBalances(classColumns, timeframe, selectedPeriod) {
|
|
253
|
+
function buildHeaderBalances(classColumns, timeframe, selectedPeriod, currency) {
|
|
242
254
|
if (selectedPeriod == null) {
|
|
243
255
|
return [];
|
|
244
256
|
}
|
|
245
257
|
const { endDate, startDate } = selectedPeriod;
|
|
246
258
|
const balances = classColumns.map((col) => ({
|
|
247
|
-
balance: toAmountWC(0,
|
|
259
|
+
balance: toAmountWC(0, currency),
|
|
248
260
|
balanceTimeFrame: timeframe,
|
|
249
261
|
endDate,
|
|
250
262
|
startDate,
|
|
@@ -253,7 +265,7 @@ function buildHeaderBalances(classColumns, timeframe, selectedPeriod) {
|
|
|
253
265
|
}));
|
|
254
266
|
// Add a "Total" column
|
|
255
267
|
balances.push({
|
|
256
|
-
balance: toAmountWC(0,
|
|
268
|
+
balance: toAmountWC(0, currency),
|
|
257
269
|
balanceTimeFrame: timeframe,
|
|
258
270
|
endDate,
|
|
259
271
|
startDate,
|
|
@@ -262,20 +274,3 @@ function buildHeaderBalances(classColumns, timeframe, selectedPeriod) {
|
|
|
262
274
|
});
|
|
263
275
|
return balances;
|
|
264
276
|
}
|
|
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,
|
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 };
|