@zeniai/client-epic-state 4.19.95 → 4.19.96-beta0ND
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 +5 -4
- package/lib/esm/view/expenseAutomationView/epics/accountRecon/saveReconciliationReviewEpic.js +8 -3
- package/lib/esm/view/financeStatement/financeStatementReducer.js +11 -8
- package/lib/esm/view/financeStatement/financeStatementSelector.js +10 -5
- package/lib/esm/view/profitAndLossClassesView/profitAndLossClassesByClassHorizontalSelector.js +318 -0
- package/lib/esm/view/profitAndLossClassesView/profitAndLossClassesByClassHorizontalSelectorTypes.js +1 -0
- package/lib/esm/view/profitAndLossClassesView/profitAndLossClassesViewReducer.js +6 -1
- 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 +7 -5
- package/lib/index.js +29 -25
- package/lib/tsconfig.typecheck.tsbuildinfo +1 -1
- package/lib/view/expenseAutomationView/epics/accountRecon/saveReconciliationReviewEpic.js +8 -3
- package/lib/view/financeStatement/financeStatementReducer.js +11 -8
- package/lib/view/financeStatement/financeStatementSelector.d.ts +2 -0
- package/lib/view/financeStatement/financeStatementSelector.js +10 -5
- package/lib/view/profitAndLossClassesView/profitAndLossClassesByClassHorizontalSelector.d.ts +13 -0
- package/lib/view/profitAndLossClassesView/profitAndLossClassesByClassHorizontalSelector.js +322 -0
- package/lib/view/profitAndLossClassesView/profitAndLossClassesByClassHorizontalSelectorTypes.d.ts +59 -0
- package/lib/view/profitAndLossClassesView/profitAndLossClassesByClassHorizontalSelectorTypes.js +2 -0
- package/lib/view/profitAndLossClassesView/profitAndLossClassesViewReducer.d.ts +4 -2
- package/lib/view/profitAndLossClassesView/profitAndLossClassesViewReducer.js +7 -2
- package/lib/view/profitAndLossClassesView/profitAndLossClassesViewSelector.js +2 -29
- package/lib/view/profitAndLossClassesView/profitAndLossClassesViewState.d.ts +4 -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';
|
|
@@ -217,7 +217,8 @@ import { changeZeniPersonRoles, deletePerson, fetchAllPeopleRequiredViews, fetch
|
|
|
217
217
|
import { getPeople, getPeopleLocalData } from './view/people/peopleSelector';
|
|
218
218
|
import { fetchProfitAndLoss, fetchProfitAndLossForTimeframe, resetProfitAndLossNodeCollapseState, updateProfitAndLossUIState, } from './view/profitAndLoss/profitAndLossReducer';
|
|
219
219
|
import { getPandLReportFetchState, getProfitAndLossReport, } from './view/profitAndLoss/profitAndLossSelector';
|
|
220
|
-
import { fetchProfitAndLossClassesView, resetProfitAndLossClassesNodeCollapseState, updateAccountViewMode as updateProfitAndLossAccountViewMode, updateClassesToFilterOut as updateProfitAndLossClassesToFilterOut, updateProfitAndLossClassesViewUIState, } from './view/profitAndLossClassesView/profitAndLossClassesViewReducer';
|
|
220
|
+
import { fetchProfitAndLossClassesView, resetProfitAndLossClassesNodeCollapseState, updateAccountViewMode as updateProfitAndLossAccountViewMode, updateClassesToFilterOut as updateProfitAndLossClassesToFilterOut, updateClassViewLayout, updateProfitAndLossClassesViewUIState, } from './view/profitAndLossClassesView/profitAndLossClassesViewReducer';
|
|
221
|
+
import { getProfitAndLossClassesHorizontalView } from './view/profitAndLossClassesView/profitAndLossClassesByClassHorizontalSelector';
|
|
221
222
|
import { getProfitAndLossClassesView } from './view/profitAndLossClassesView/profitAndLossClassesViewSelector';
|
|
222
223
|
import { isPandLReportViewCalculatedSectionID, isPandLReportViewSectionID, } from './view/profitAndLossClassesView/profitAndLossClassesViewSelectorTypes';
|
|
223
224
|
import { fetchEntityRecommendationsByTransactionId, fetchRecommendationByEntityId, fetchRecommendationByEntityName, } from './view/recommendation/recommendationReducer';
|
|
@@ -451,7 +452,7 @@ export { fetchDashboard, getDashboard, updateTreasuryVideoClosed, };
|
|
|
451
452
|
export { updateDashboardLayout };
|
|
452
453
|
export { getPandLWithForecast, } from './view/profitAndLoss/pAndLWithForecast/pAndLWithForecastSelector';
|
|
453
454
|
export { fetchProfitAndLoss, resetProfitAndLossNodeCollapseState, updateProfitAndLossUIState, getProfitAndLossReport, getPandLReportFetchState, fetchProfitAndLossForTimeframe, };
|
|
454
|
-
export { fetchProfitAndLossClassesView, updateProfitAndLossClassesToFilterOut, resetProfitAndLossClassesNodeCollapseState, updateProfitAndLossClassesViewUIState, updateProfitAndLossAccountViewMode, getProfitAndLossClassesView, isPandLReportViewCalculatedSectionID, isPandLReportViewSectionID, };
|
|
455
|
+
export { fetchProfitAndLossClassesView, updateProfitAndLossClassesToFilterOut, resetProfitAndLossClassesNodeCollapseState, updateProfitAndLossClassesViewUIState, updateProfitAndLossAccountViewMode, updateClassViewLayout, getProfitAndLossClassesView, getProfitAndLossClassesHorizontalView, isPandLReportViewCalculatedSectionID, isPandLReportViewSectionID, };
|
|
455
456
|
export { getAccountingProviderAttachment };
|
|
456
457
|
export { fetchUserListByType, getUserList };
|
|
457
458
|
export { fetchAllPeopleRequiredViews, fetchPeoplePage, fetchPeople, deletePerson, resendInvite, changeZeniPersonRoles, invitePeople, inviteZeniPeople, updatePeopleUIState, peopleSaveUpdates, resetUpdateErrorMessage, peopleSaveDataInLocalStore, peopleClearDataInLocalStore, getPeople, getPeopleLocalData, initializeEditPerson, };
|
|
@@ -543,7 +544,7 @@ export { saveRealTimeApproval, updateIsEditModeRealTimeApprovals, };
|
|
|
543
544
|
export { deleteRemi, fetchRemiDetail, cancelAndDeleteRemi, approveOrRejectRemi, clearRemiDetailView, fetchDuplicateReimbursement, clearDuplicateReimbursementDetail, removeDuplicateReimbursementByLineId, };
|
|
544
545
|
export { getEditRemiDetail, };
|
|
545
546
|
export { fetchEditRemiDetailPage, fetchRecommendationsAndUpdateMerchantRecommendations, fetchRemiAndInitializeLocalStore, initializeRemiToLocalStore, saveRemiUpdatesToLocalStore, fetchCurrencyConversionValue, discardRemiUpdatesInLocalStore, removeFileFromRemiUpdatesInLocalStore, saveRemiDetail, saveRemiSuccessOrFailure, parseReceiptsToRemi, clearEditRemiViewDetail, updateAddRemiAutoFields, updateUploadFetchState, updateTentativeMerchantNames, clearTentativeMerchantName, updateReimbursementType, updateHomeCurrencyConversion, clearAddRemiAutoFields, };
|
|
546
|
-
export { reduceFetchState, reduceAnyFetchState, reduceAllFetchState, reduceAnyCompletedFetchState, isAnyFetchInProgress, isAllFetchCompleted, ALL_FILE_TYPES, toFileTypeStrict, };
|
|
547
|
+
export { reduceFetchState, reduceFetchStateParallelTimeframes, reduceAnyFetchState, reduceAllFetchState, reduceAnyCompletedFetchState, isAnyFetchInProgress, isAllFetchCompleted, ALL_FILE_TYPES, toFileTypeStrict, };
|
|
547
548
|
export { getNextNthWorkingDay, getPreviousNthWorkingDay, isHolidayToday, filterDays, getYearsList, isHoliday, holidaysFormatted, PAYMENT_BUSINESS_DAYS, };
|
|
548
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, };
|
|
549
550
|
export { getTransactionsListByCategoryType, getTransactionListUIStateByCategoryType, };
|
package/lib/esm/view/expenseAutomationView/epics/accountRecon/saveReconciliationReviewEpic.js
CHANGED
|
@@ -4,6 +4,7 @@ import { DEFAULT_DATE_FORMAT } from '../../../../commonStateTypes/fiscalYearHelp
|
|
|
4
4
|
import { addTransactionToReconcileList, excludeReconReviewTransaction, } from '../../../../entity/accountRecon/accountReconReducer';
|
|
5
5
|
import { getAccountReconByAccountIdAndSelectedPeriod, } from '../../../../entity/accountRecon/accountReconSelector';
|
|
6
6
|
import { toAccountReconKey, } from '../../../../entity/accountRecon/accountReconState';
|
|
7
|
+
import { getEntityByEntityIDs } from '../../../../entity/genericEntity/entitySelector';
|
|
7
8
|
import { openSnackbar } from '../../../../entity/snackbar/snackbarReducer';
|
|
8
9
|
import { getCurrentTenant } from '../../../../entity/tenant/tenantSelector';
|
|
9
10
|
import { updateMultipleReconcileTransactions } from '../../../../entity/transaction/transactionReducer';
|
|
@@ -12,6 +13,7 @@ import { createZeniAPIStatus, isSuccessResponse, } from '../../../../responsePay
|
|
|
12
13
|
import { saveReconciliationReview, updateReconcileTabLocalData, updateSaveReconciliationReviewFetchStatus, } from '../../reducers/reconciliationViewReducer';
|
|
13
14
|
export const saveReconciliationReviewEpic = (actions$, state$, zeniAPI) => actions$.pipe(filter(saveReconciliationReview.match), mergeMap((action) => {
|
|
14
15
|
const state = state$.value;
|
|
16
|
+
const entityState = state.entityState;
|
|
15
17
|
const { transactionId } = action.payload;
|
|
16
18
|
const localData = state.expenseAutomationReconciliationViewState.reconTabsState.review
|
|
17
19
|
.localData[transactionId];
|
|
@@ -59,7 +61,7 @@ export const saveReconciliationReviewEpic = (actions$, state$, zeniAPI) => actio
|
|
|
59
61
|
payload = getPayloadForCCPayment(updatedTransaction, localData, reconciliationData?.account.accountType);
|
|
60
62
|
break;
|
|
61
63
|
case 'record_deposit':
|
|
62
|
-
payload = getPayloadForDeposit(updatedTransaction, localData);
|
|
64
|
+
payload = getPayloadForDeposit(updatedTransaction, localData, entityState);
|
|
63
65
|
break;
|
|
64
66
|
}
|
|
65
67
|
}
|
|
@@ -159,7 +161,10 @@ function getPayloadForExpenseRecord(updatedTransaction, localData) {
|
|
|
159
161
|
currency_code: updatedTransaction.amount.currencyCode,
|
|
160
162
|
};
|
|
161
163
|
}
|
|
162
|
-
function getPayloadForDeposit(updatedTransaction, localData) {
|
|
164
|
+
function getPayloadForDeposit(updatedTransaction, localData, entityState) {
|
|
165
|
+
const customerZeniId = localData.customer?.id != null
|
|
166
|
+
? getEntityByEntityIDs(entityState, [localData.customer?.id])[0]?.zeniId
|
|
167
|
+
: undefined;
|
|
163
168
|
return {
|
|
164
169
|
amount: updatedTransaction.amount.amount,
|
|
165
170
|
transaction_memo: updatedTransaction.memo,
|
|
@@ -167,7 +172,7 @@ function getPayloadForDeposit(updatedTransaction, localData) {
|
|
|
167
172
|
transaction_date: updatedTransaction.transactionDate.format(DEFAULT_DATE_FORMAT),
|
|
168
173
|
transaction_direction: updatedTransaction.transactionDirection,
|
|
169
174
|
transaction_id: updatedTransaction.transactionId,
|
|
170
|
-
customer_id:
|
|
175
|
+
customer_id: customerZeniId,
|
|
171
176
|
customer_name: localData.customer?.name,
|
|
172
177
|
account_id: localData.categoryId,
|
|
173
178
|
accounting_class_id: localData.classId,
|
|
@@ -44,19 +44,20 @@ const financeStatement = createSlice({
|
|
|
44
44
|
updateFinanceStatementThisPeriod(draft, action) {
|
|
45
45
|
const { firstMonthOfFY, coaBalances, maxNumOfPeriodsToHighlight } = action.payload;
|
|
46
46
|
const { timeframe, selectedCOABalancesRange } = draft;
|
|
47
|
-
|
|
48
|
-
|
|
47
|
+
const safeCoaBalances = coaBalances != null ? coaBalances : [];
|
|
48
|
+
if (safeCoaBalances.length > 0) {
|
|
49
|
+
const prevThisPeriod = extractThisPeriod(action.payload.firstMonthOfFY, timeframe, selectedCOABalancesRange, safeCoaBalances);
|
|
49
50
|
if (prevThisPeriod != null) {
|
|
50
51
|
const selectedCoaBalancesRangeWithThisPeriod = {
|
|
51
52
|
...selectedCOABalancesRange,
|
|
52
53
|
thisPeriod: prevThisPeriod,
|
|
53
54
|
};
|
|
54
|
-
const newThisPeriod = getMatchingThisPeriod(action.payload.firstMonthOfFY, timeframe, action.payload.thisPeriod,
|
|
55
|
+
const newThisPeriod = getMatchingThisPeriod(action.payload.firstMonthOfFY, timeframe, action.payload.thisPeriod, safeCoaBalances);
|
|
55
56
|
if (newThisPeriod != null) {
|
|
56
57
|
const selectionRanges = getSelectedAndHighlightedRangesForThisPeriod({
|
|
57
58
|
firstMonthOfFY,
|
|
58
59
|
thisPeriod: newThisPeriod,
|
|
59
|
-
coaBalances,
|
|
60
|
+
coaBalances: safeCoaBalances,
|
|
60
61
|
timeframe,
|
|
61
62
|
maxNumOfPeriodsToSelect: maxNumOfPeriodsToHighlight,
|
|
62
63
|
currentSelection: {
|
|
@@ -75,7 +76,9 @@ const financeStatement = createSlice({
|
|
|
75
76
|
draft.selectedReportId = action.payload;
|
|
76
77
|
},
|
|
77
78
|
updateFinanceStatementAdditionalBalancesSelection(draft, action) {
|
|
78
|
-
const { firstMonthOfFY, additionalBalances, coaBalances, maxNumOfPeriodsToHighlight, } = action.payload;
|
|
79
|
+
const { firstMonthOfFY, additionalBalances: additionalBalancesPayload, coaBalances, maxNumOfPeriodsToHighlight, } = action.payload;
|
|
80
|
+
const safeCoaBalances = coaBalances != null ? coaBalances : [];
|
|
81
|
+
const additionalBalances = additionalBalancesPayload ?? [];
|
|
79
82
|
let tempAdditionalBalances = [...additionalBalances];
|
|
80
83
|
if (additionalBalances.includes('this_period_vs_last_period') ||
|
|
81
84
|
additionalBalances.includes('this_period_vs_last_period_percent')) {
|
|
@@ -91,8 +94,8 @@ const financeStatement = createSlice({
|
|
|
91
94
|
draft.isAdditionalBalancesShown =
|
|
92
95
|
additionalBalances.length != 0 ? true : false;
|
|
93
96
|
const { timeframe, selectedCOABalancesRange } = draft;
|
|
94
|
-
if (
|
|
95
|
-
const thisPeriod = extractThisPeriod(action.payload.firstMonthOfFY, timeframe, selectedCOABalancesRange,
|
|
97
|
+
if (safeCoaBalances.length > 0) {
|
|
98
|
+
const thisPeriod = extractThisPeriod(action.payload.firstMonthOfFY, timeframe, selectedCOABalancesRange, safeCoaBalances);
|
|
96
99
|
if (thisPeriod != null) {
|
|
97
100
|
const selectedCoaBalancesRangeWithThisPeriod = {
|
|
98
101
|
...selectedCOABalancesRange,
|
|
@@ -101,7 +104,7 @@ const financeStatement = createSlice({
|
|
|
101
104
|
const selectionRanges = getSelectedAndHighlightedRangesForThisPeriod({
|
|
102
105
|
firstMonthOfFY,
|
|
103
106
|
thisPeriod: thisPeriod,
|
|
104
|
-
coaBalances,
|
|
107
|
+
coaBalances: safeCoaBalances,
|
|
105
108
|
timeframe,
|
|
106
109
|
maxNumOfPeriodsToHighlight: maxNumOfPeriodsToHighlight,
|
|
107
110
|
currentSelection: {
|
|
@@ -8,6 +8,7 @@ import { extractThisPeriod } from '../../commonStateTypes/viewAndReport/thisPeri
|
|
|
8
8
|
import { getBalanceSheet } from '../balanceSheet/balanceSheetSelector';
|
|
9
9
|
import { getCashFlow } from '../cashFlow/cashFlowSelector';
|
|
10
10
|
import { getProfitAndLossReport, } from '../profitAndLoss/profitAndLossSelector';
|
|
11
|
+
import { getProfitAndLossClassesHorizontalView } from '../profitAndLossClassesView/profitAndLossClassesByClassHorizontalSelector';
|
|
11
12
|
import { getProfitAndLossClassesView } from '../profitAndLossClassesView/profitAndLossClassesViewSelector';
|
|
12
13
|
function getDateRangeForFinanceReports(profitAndLossState, balanceSheetState, cashFlowState) {
|
|
13
14
|
const datesSorted = [
|
|
@@ -42,11 +43,11 @@ export const getFinanceStatement = createSelector((state) => state.accountState,
|
|
|
42
43
|
if (dataAvailable != null) {
|
|
43
44
|
const noFilter = newBalancesFilterForDateRange(firstMonthOfFY, financeStatementState.timeframe, dataAvailable, 'ascending_date', []);
|
|
44
45
|
const profitAndLossForTimeframeTicks = getProfitAndLossReport(noFilter, undefined, accountState, accountGroupState, sectionAccountsViewState, profitAndLossState, forecastState);
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
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) {
|
|
50
51
|
allTimeframeTicks = balancesInTimeframe.map((balance) => toTimeframeTick(balance));
|
|
51
52
|
}
|
|
52
53
|
}
|
|
@@ -60,6 +61,9 @@ export const getFinanceStatement = createSelector((state) => state.accountState,
|
|
|
60
61
|
const profitAndLossReport = getProfitAndLossReport(filter, undefined, accountState, accountGroupState, sectionAccountsViewState, profitAndLossState, forecastState);
|
|
61
62
|
const classFilter = newBalancesFilterClassesView(filter.firstMonthOfFY, filter.timeframe, filter.balancesRange.numberOfPeriods, filter.balancesRange.thisPeriod, filter.balancesRange.orderBy, filter.additionalBalances, profitAndLossClassesViewState.uiState.classesToFilterOut);
|
|
62
63
|
const profitAndLossByClassReport = getProfitAndLossClassesView(classFilter, accountState, classState, sectionsState, profitAndLossClassesViewState);
|
|
64
|
+
const profitAndLossByClassHorizontalReport = getProfitAndLossClassesHorizontalView(classFilter, accountState, classState, sectionsState, profitAndLossClassesViewState, profitAndLossClassesViewState.uiState.classViewLayout === 'horizontal'
|
|
65
|
+
? thisPeriod
|
|
66
|
+
: undefined);
|
|
63
67
|
const balanceSheetReport = getBalanceSheet(filter, accountState, accountGroupState, sectionAccountsViewState, balanceSheetState);
|
|
64
68
|
const cashFlowReport = getCashFlow(filter, accountState, accountGroupState, sectionAccountsViewState, cashFlowState);
|
|
65
69
|
const allReports = [
|
|
@@ -107,6 +111,7 @@ export const getFinanceStatement = createSelector((state) => state.accountState,
|
|
|
107
111
|
dataAvailable,
|
|
108
112
|
profitAndLossReport,
|
|
109
113
|
profitAndLossByClassReport,
|
|
114
|
+
profitAndLossByClassHorizontalReport,
|
|
110
115
|
balanceSheetReport,
|
|
111
116
|
cashFlowReport,
|
|
112
117
|
filter,
|
package/lib/esm/view/profitAndLossClassesView/profitAndLossClassesByClassHorizontalSelector.js
ADDED
|
@@ -0,0 +1,318 @@
|
|
|
1
|
+
import { toAmountWC } from '../../commonStateTypes/amount';
|
|
2
|
+
import { reduceFetchStateParallelTimeframes } from '../../commonStateTypes/reduceFetchState';
|
|
3
|
+
import { getSectionClassesViewReport } from '../../entity/sectionClassesViewV2/sectionClassesViewSelector';
|
|
4
|
+
/** If `ProfitAndLossClassesViewState.currency` is unset (e.g. tests). */
|
|
5
|
+
const FALLBACK_REPORT_CURRENCY = {
|
|
6
|
+
currencyCode: 'USD',
|
|
7
|
+
currencySymbol: '$',
|
|
8
|
+
};
|
|
9
|
+
export const profitAndLossHorizontalIdsInOrder = [
|
|
10
|
+
'income',
|
|
11
|
+
'cogs',
|
|
12
|
+
'grossProfit',
|
|
13
|
+
'expenses',
|
|
14
|
+
'earningsBeforeInterestAndTax',
|
|
15
|
+
'otherIncome',
|
|
16
|
+
'otherExpenses',
|
|
17
|
+
'netOtherIncome',
|
|
18
|
+
'netIncome',
|
|
19
|
+
];
|
|
20
|
+
const SECTION_TITLES = {
|
|
21
|
+
income: 'Income',
|
|
22
|
+
cogs: 'Cost of Goods Sold',
|
|
23
|
+
grossProfit: 'Gross Profit',
|
|
24
|
+
expenses: 'Expenses',
|
|
25
|
+
earningsBeforeInterestAndTax: 'Net Operating Income',
|
|
26
|
+
otherIncome: 'Other Income',
|
|
27
|
+
otherExpenses: 'Other Expenses',
|
|
28
|
+
netOtherIncome: 'Net Other Income',
|
|
29
|
+
netIncome: 'Net Income',
|
|
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
|
+
];
|
|
39
|
+
export const getProfitAndLossClassesHorizontalView = (filter, accountState, classState, sectionsState, profitAndLossClassesViewState, selectedPeriod) => {
|
|
40
|
+
const fetchState = reduceFetchStateParallelTimeframes([
|
|
41
|
+
profitAndLossClassesViewState.fetchState.month,
|
|
42
|
+
profitAndLossClassesViewState.fetchState.quarter,
|
|
43
|
+
profitAndLossClassesViewState.fetchState.year,
|
|
44
|
+
]);
|
|
45
|
+
const reportId = 'profit_and_loss_by_classes';
|
|
46
|
+
// Build class columns from the class hierarchy (top-level only).
|
|
47
|
+
// Use `filter.classesToFilterOut` so PDF/Excel downloads (fresh store, empty UI state)
|
|
48
|
+
// respect `classes_to_filter_out` from the request; in-app `classFilter` mirrors uiState.
|
|
49
|
+
const classColumns = buildClassColumns(profitAndLossClassesViewState.classHierarchy, filter.classesToFilterOut);
|
|
50
|
+
const sections = {};
|
|
51
|
+
const calculatedSections = {};
|
|
52
|
+
let reportCurrency = FALLBACK_REPORT_CURRENCY;
|
|
53
|
+
if (fetchState.fetchState === 'Completed' && selectedPeriod != null) {
|
|
54
|
+
// Get section reports using existing selector infrastructure
|
|
55
|
+
const sectionReports = {};
|
|
56
|
+
HORIZONTAL_PANDL_SECTION_IDS.forEach((sectionId) => {
|
|
57
|
+
sectionReports[sectionId] = getSectionClassesViewReport(accountState, classState, sectionsState, { reportId, sectionId }, filter);
|
|
58
|
+
});
|
|
59
|
+
reportCurrency =
|
|
60
|
+
profitAndLossClassesViewState.currency ?? FALLBACK_REPORT_CURRENCY;
|
|
61
|
+
// Pivot each section from class→account to account→class
|
|
62
|
+
HORIZONTAL_PANDL_SECTION_IDS.forEach((sectionId) => {
|
|
63
|
+
const sectionReport = sectionReports[sectionId];
|
|
64
|
+
if (sectionReport != null) {
|
|
65
|
+
sections[sectionId] = pivotSectionToHorizontal(sectionReport, classColumns, SECTION_TITLES[sectionId] ?? sectionId, reportCurrency);
|
|
66
|
+
}
|
|
67
|
+
});
|
|
68
|
+
// Calculate derived sections
|
|
69
|
+
const incomeSection = sections['income'];
|
|
70
|
+
const cogsSection = sections['cogs'];
|
|
71
|
+
const expensesSection = sections['expenses'];
|
|
72
|
+
const otherIncomeSection = sections['otherIncome'];
|
|
73
|
+
const otherExpensesSection = sections['otherExpenses'];
|
|
74
|
+
// Gross Profit = Income - COGS
|
|
75
|
+
if (incomeSection != null && cogsSection != null) {
|
|
76
|
+
calculatedSections['grossProfit'] = computeCalculatedSection(incomeSection.classTotals, cogsSection.classTotals, incomeSection.sectionTotal, cogsSection.sectionTotal, 'subtract', SECTION_TITLES['grossProfit']);
|
|
77
|
+
}
|
|
78
|
+
// EBIT = Gross Profit - Expenses
|
|
79
|
+
const grossProfit = calculatedSections['grossProfit'];
|
|
80
|
+
if (grossProfit != null && expensesSection != null) {
|
|
81
|
+
calculatedSections['earningsBeforeInterestAndTax'] =
|
|
82
|
+
computeCalculatedSection(grossProfit.classTotals, expensesSection.classTotals, grossProfit.sectionTotal, expensesSection.sectionTotal, 'subtract', SECTION_TITLES['earningsBeforeInterestAndTax']);
|
|
83
|
+
}
|
|
84
|
+
// Net Other Income = Other Income - Other Expenses
|
|
85
|
+
if (otherIncomeSection != null && otherExpensesSection != null) {
|
|
86
|
+
calculatedSections['netOtherIncome'] = computeCalculatedSection(otherIncomeSection.classTotals, otherExpensesSection.classTotals, otherIncomeSection.sectionTotal, otherExpensesSection.sectionTotal, 'subtract', SECTION_TITLES['netOtherIncome']);
|
|
87
|
+
}
|
|
88
|
+
// Net Income = EBIT + Net Other Income
|
|
89
|
+
const ebit = calculatedSections['earningsBeforeInterestAndTax'];
|
|
90
|
+
const netOtherIncome = calculatedSections['netOtherIncome'];
|
|
91
|
+
if (ebit != null && netOtherIncome != null) {
|
|
92
|
+
calculatedSections['netIncome'] = computeCalculatedSection(ebit.classTotals, netOtherIncome.classTotals, ebit.sectionTotal, netOtherIncome.sectionTotal, 'add', SECTION_TITLES['netIncome']);
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
// Build synthetic header COABalances for rendering class names as column headers
|
|
96
|
+
const headerBalances = buildHeaderBalances(classColumns, filter.timeframe, selectedPeriod, reportCurrency);
|
|
97
|
+
return {
|
|
98
|
+
reportId,
|
|
99
|
+
reportTitle: 'Profit and Loss by Class',
|
|
100
|
+
firstMonthOfFY: profitAndLossClassesViewState.firstMonthOfFY,
|
|
101
|
+
fetchState: fetchState.fetchState,
|
|
102
|
+
bookCloseDate: profitAndLossClassesViewState.bookCloseDate,
|
|
103
|
+
dataAvailable: profitAndLossClassesViewState.dataAvailable,
|
|
104
|
+
selectedPeriod,
|
|
105
|
+
classColumns,
|
|
106
|
+
sections,
|
|
107
|
+
calculatedSections,
|
|
108
|
+
idsInOrder: profitAndLossHorizontalIdsInOrder,
|
|
109
|
+
uiState: profitAndLossClassesViewState.uiState,
|
|
110
|
+
headerBalances,
|
|
111
|
+
};
|
|
112
|
+
};
|
|
113
|
+
/**
|
|
114
|
+
* Build column definitions from class hierarchy (top-level classes only).
|
|
115
|
+
*/
|
|
116
|
+
function buildClassColumns(classHierarchy, classesToFilterOut) {
|
|
117
|
+
const filteredIds = new Set(classesToFilterOut.map((id) => id[0]));
|
|
118
|
+
return classHierarchy
|
|
119
|
+
.filter((c) => !filteredIds.has(c.classId[0]))
|
|
120
|
+
.map((c) => ({
|
|
121
|
+
classId: c.classId[0],
|
|
122
|
+
className: c.className,
|
|
123
|
+
nestedClassId: c.classId,
|
|
124
|
+
qboId: c.qboId,
|
|
125
|
+
}))
|
|
126
|
+
.sort((a, b) => a.className.localeCompare(b.className, [], { sensitivity: 'base' }));
|
|
127
|
+
}
|
|
128
|
+
/**
|
|
129
|
+
* Pivot a section from class→account→balances to account→class→balance (single period).
|
|
130
|
+
*/
|
|
131
|
+
function pivotSectionToHorizontal(section, classColumns, title, currency) {
|
|
132
|
+
// Map: accountId -> { accountName, classId -> balance }
|
|
133
|
+
const accountMap = new Map();
|
|
134
|
+
// Also track class totals
|
|
135
|
+
const classTotalMap = new Map();
|
|
136
|
+
classColumns.forEach((col) => classTotalMap.set(col.classId, 0));
|
|
137
|
+
// Iterate over each class in the section
|
|
138
|
+
section.classes.forEach((classReport) => {
|
|
139
|
+
const classId = classReport.id[0];
|
|
140
|
+
// Only process classes that are in our columns
|
|
141
|
+
if (!classTotalMap.has(classId)) {
|
|
142
|
+
return;
|
|
143
|
+
}
|
|
144
|
+
// Sum all sliced period balances (same slice as vertical columns; multi-period = range total)
|
|
145
|
+
const classBalance = sumBalancesInSlice(classReport.childrenBalancesTotal.balances);
|
|
146
|
+
classTotalMap.set(classId, classBalance);
|
|
147
|
+
// Iterate through accounts in this class
|
|
148
|
+
collectAccountsFromClass(classReport, classId, accountMap);
|
|
149
|
+
});
|
|
150
|
+
// Build account rows in COA tree order (same parent/child ordering as vertical P&L by class).
|
|
151
|
+
// Sorting by depth + name flattened the hierarchy and broke sub-account grouping.
|
|
152
|
+
const orderedIds = collectAccountIdsInTreeOrder(section, classColumns);
|
|
153
|
+
const usedIds = new Set();
|
|
154
|
+
const accounts = [];
|
|
155
|
+
const pushAccountRow = (accountId) => {
|
|
156
|
+
const accountData = accountMap.get(accountId);
|
|
157
|
+
if (accountData == null) {
|
|
158
|
+
return;
|
|
159
|
+
}
|
|
160
|
+
usedIds.add(accountId);
|
|
161
|
+
const classBalances = classColumns.map((col) => ({
|
|
162
|
+
classId: col.classId,
|
|
163
|
+
balance: toAmountWC(accountData.classBalances.get(col.classId) ?? 0, currency),
|
|
164
|
+
}));
|
|
165
|
+
const rowTotal = classBalances.reduce((sum, cb) => sum + cb.balance.amount, 0);
|
|
166
|
+
accounts.push({
|
|
167
|
+
accountId,
|
|
168
|
+
accountName: accountData.accountName,
|
|
169
|
+
depth: accountData.depth,
|
|
170
|
+
classBalances,
|
|
171
|
+
rowTotal: toAmountWC(rowTotal, currency),
|
|
172
|
+
});
|
|
173
|
+
};
|
|
174
|
+
for (const id of orderedIds) {
|
|
175
|
+
pushAccountRow(id);
|
|
176
|
+
}
|
|
177
|
+
for (const accountId of accountMap.keys()) {
|
|
178
|
+
if (!usedIds.has(accountId)) {
|
|
179
|
+
pushAccountRow(accountId);
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
// Build class totals
|
|
183
|
+
const classTotals = classColumns.map((col) => ({
|
|
184
|
+
classId: col.classId,
|
|
185
|
+
balance: toAmountWC(classTotalMap.get(col.classId) ?? 0, currency),
|
|
186
|
+
}));
|
|
187
|
+
const sectionTotal = classTotals.reduce((sum, ct) => sum + ct.balance.amount, 0);
|
|
188
|
+
return {
|
|
189
|
+
title,
|
|
190
|
+
accounts,
|
|
191
|
+
classTotals,
|
|
192
|
+
sectionTotal: toAmountWC(sectionTotal, currency),
|
|
193
|
+
};
|
|
194
|
+
}
|
|
195
|
+
/**
|
|
196
|
+
* DFS account ids in the same order as vertical P&L by class, using the first class
|
|
197
|
+
* column that appears in this section as the canonical tree (structure is identical per class).
|
|
198
|
+
*/
|
|
199
|
+
function collectAccountIdsInTreeOrder(section, classColumns) {
|
|
200
|
+
const ids = [];
|
|
201
|
+
const visitNested = (nested) => {
|
|
202
|
+
ids.push(nested.account.accountId);
|
|
203
|
+
nested.children.forEach(visitNested);
|
|
204
|
+
};
|
|
205
|
+
for (const col of classColumns) {
|
|
206
|
+
const classReport = section.classes.find((c) => c.id[0] === col.classId);
|
|
207
|
+
if (classReport == null) {
|
|
208
|
+
continue;
|
|
209
|
+
}
|
|
210
|
+
classReport.class.accounts.forEach(visitNested);
|
|
211
|
+
return ids;
|
|
212
|
+
}
|
|
213
|
+
return ids;
|
|
214
|
+
}
|
|
215
|
+
/**
|
|
216
|
+
* Recursively collect account balances from a NestedClassReportV2 into accountMap.
|
|
217
|
+
*/
|
|
218
|
+
function collectAccountsFromClass(classReport, classId, accountMap) {
|
|
219
|
+
// Process accounts directly on this class (depth 2 matches vertical `AccountsSection` first level)
|
|
220
|
+
classReport.class.accounts.forEach((nestedAccount) => {
|
|
221
|
+
collectAccountsFromNestedAccount(nestedAccount, classId, accountMap, 2);
|
|
222
|
+
});
|
|
223
|
+
}
|
|
224
|
+
/**
|
|
225
|
+
* Recursively collect accounts from NestedAccountReport (handles sub-accounts).
|
|
226
|
+
*/
|
|
227
|
+
function collectAccountsFromNestedAccount(nestedAccount, classId, accountMap, depth) {
|
|
228
|
+
const accountId = nestedAccount.account.accountId;
|
|
229
|
+
const accountName = nestedAccount.account.accountName;
|
|
230
|
+
const balance = sumBalancesInSlice(nestedAccount.account.balancesInTimeframe.balances);
|
|
231
|
+
if (!accountMap.has(accountId)) {
|
|
232
|
+
accountMap.set(accountId, {
|
|
233
|
+
accountName,
|
|
234
|
+
depth,
|
|
235
|
+
classBalances: new Map(),
|
|
236
|
+
});
|
|
237
|
+
}
|
|
238
|
+
const accountData = accountMap.get(accountId);
|
|
239
|
+
if (accountData == null) {
|
|
240
|
+
return;
|
|
241
|
+
}
|
|
242
|
+
accountData.depth = Math.max(accountData.depth, depth);
|
|
243
|
+
const existing = accountData.classBalances.get(classId) ?? 0;
|
|
244
|
+
accountData.classBalances.set(classId, existing + balance);
|
|
245
|
+
// Process sub-accounts
|
|
246
|
+
nestedAccount.children.forEach((child) => {
|
|
247
|
+
collectAccountsFromNestedAccount(child, classId, accountMap, depth + 1);
|
|
248
|
+
});
|
|
249
|
+
}
|
|
250
|
+
/**
|
|
251
|
+
* Total amount for the current report slice. `balances` is already narrowed by
|
|
252
|
+
* `getCOABalances` / `sliceCOABalances` to the selected range; summing matches
|
|
253
|
+
* multi-period selections and avoids mismatches when `thisPeriod` does not
|
|
254
|
+
* align with a row (e.g. slice fallback) or when several period rows are shown.
|
|
255
|
+
*/
|
|
256
|
+
function sumBalancesInSlice(balances) {
|
|
257
|
+
let sum = 0;
|
|
258
|
+
for (const bal of balances) {
|
|
259
|
+
sum += bal.balance?.amount ?? 0;
|
|
260
|
+
}
|
|
261
|
+
return sum;
|
|
262
|
+
}
|
|
263
|
+
/**
|
|
264
|
+
* Compute a calculated section by adding or subtracting two sets of class totals.
|
|
265
|
+
*/
|
|
266
|
+
function computeCalculatedSection(aTotals, bTotals, aTotal, bTotal, operation, title) {
|
|
267
|
+
const currency = {
|
|
268
|
+
currencyCode: aTotal.currencyCode,
|
|
269
|
+
currencySymbol: aTotal.currencySymbol,
|
|
270
|
+
};
|
|
271
|
+
const bTotalsMap = new Map(bTotals.map((b) => [b.classId, b.balance.amount]));
|
|
272
|
+
const classTotals = aTotals.map((a) => {
|
|
273
|
+
const bAmount = bTotalsMap.get(a.classId) ?? 0;
|
|
274
|
+
const resultAmount = operation === 'add'
|
|
275
|
+
? a.balance.amount + bAmount
|
|
276
|
+
: a.balance.amount - bAmount;
|
|
277
|
+
return {
|
|
278
|
+
classId: a.classId,
|
|
279
|
+
balance: toAmountWC(resultAmount, currency),
|
|
280
|
+
};
|
|
281
|
+
});
|
|
282
|
+
const sectionTotalAmount = operation === 'add'
|
|
283
|
+
? aTotal.amount + bTotal.amount
|
|
284
|
+
: aTotal.amount - bTotal.amount;
|
|
285
|
+
return {
|
|
286
|
+
title,
|
|
287
|
+
classTotals,
|
|
288
|
+
sectionTotal: toAmountWC(sectionTotalAmount, currency),
|
|
289
|
+
};
|
|
290
|
+
}
|
|
291
|
+
/**
|
|
292
|
+
* Build synthetic COABalance array for header rendering.
|
|
293
|
+
* One entry per class column + one for "Total".
|
|
294
|
+
*/
|
|
295
|
+
function buildHeaderBalances(classColumns, timeframe, selectedPeriod, currency) {
|
|
296
|
+
if (selectedPeriod == null) {
|
|
297
|
+
return [];
|
|
298
|
+
}
|
|
299
|
+
const { endDate, startDate } = selectedPeriod;
|
|
300
|
+
const balances = classColumns.map((col) => ({
|
|
301
|
+
balance: toAmountWC(0, currency),
|
|
302
|
+
balanceTimeFrame: timeframe,
|
|
303
|
+
endDate,
|
|
304
|
+
startDate,
|
|
305
|
+
type: 'default',
|
|
306
|
+
label: col.className,
|
|
307
|
+
}));
|
|
308
|
+
// Add a "Total" column
|
|
309
|
+
balances.push({
|
|
310
|
+
balance: toAmountWC(0, currency),
|
|
311
|
+
balanceTimeFrame: timeframe,
|
|
312
|
+
endDate,
|
|
313
|
+
startDate,
|
|
314
|
+
type: 'default',
|
|
315
|
+
label: 'Total',
|
|
316
|
+
});
|
|
317
|
+
return balances;
|
|
318
|
+
}
|
package/lib/esm/view/profitAndLossClassesView/profitAndLossClassesByClassHorizontalSelectorTypes.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -23,6 +23,7 @@ export const initialState = {
|
|
|
23
23
|
nodeCollapseState: {},
|
|
24
24
|
scrollPosition: undefined,
|
|
25
25
|
accountViewMode: 'account_group',
|
|
26
|
+
classViewLayout: 'vertical',
|
|
26
27
|
classesToFilterOut: [],
|
|
27
28
|
},
|
|
28
29
|
firstMonthOfFY: 1,
|
|
@@ -94,6 +95,9 @@ const profitAndLossClassesView = createSlice({
|
|
|
94
95
|
updateAccountViewMode(draft, action) {
|
|
95
96
|
draft.uiState.accountViewMode = action.payload.viewMode;
|
|
96
97
|
},
|
|
98
|
+
updateClassViewLayout(draft, action) {
|
|
99
|
+
draft.uiState.classViewLayout = action.payload.classViewLayout;
|
|
100
|
+
},
|
|
97
101
|
resetProfitAndLossClassesNodeCollapseState(draft) {
|
|
98
102
|
draft.uiState.nodeCollapseState = {};
|
|
99
103
|
},
|
|
@@ -102,10 +106,11 @@ const profitAndLossClassesView = createSlice({
|
|
|
102
106
|
},
|
|
103
107
|
},
|
|
104
108
|
});
|
|
105
|
-
export const { fetchProfitAndLossClassesView, fetchProfitAndLossForTimeframeClassesView, updateProfitAndLossForTimeframeClassesView, updateProfitAndLossForTimeframeClassesViewFailure, updateClassesToFilterOut, updateProfitAndLossClassesViewUIState, updateAccountViewMode, resetProfitAndLossClassesNodeCollapseState, clearProfitAndLossClassesView, } = profitAndLossClassesView.actions;
|
|
109
|
+
export const { fetchProfitAndLossClassesView, fetchProfitAndLossForTimeframeClassesView, updateProfitAndLossForTimeframeClassesView, updateProfitAndLossForTimeframeClassesViewFailure, updateClassesToFilterOut, updateProfitAndLossClassesViewUIState, updateAccountViewMode, updateClassViewLayout, resetProfitAndLossClassesNodeCollapseState, clearProfitAndLossClassesView, } = profitAndLossClassesView.actions;
|
|
106
110
|
export default profitAndLossClassesView.reducer;
|
|
107
111
|
const doUpdatedProfitAndLossClassesView = (draft, timeframe, pandLReport) => {
|
|
108
112
|
const report = mapReportPayloadV2ToReportV2(pandLReport.report);
|
|
113
|
+
draft.currency = report.currency;
|
|
109
114
|
draft.dataAvailable = report.dataAvailable;
|
|
110
115
|
draft.firstMonthOfFY = report.firstMonthOfFY;
|
|
111
116
|
draft.bookCloseDate = report.bookCloseDate;
|