@zeniai/client-epic-state 4.19.99-betaRD21 → 4.19.99-betaRD4
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.
Potentially problematic release.
This version of @zeniai/client-epic-state might be problematic. Click here for more details.
- package/lib/entity/aiAccountantCustomer/aiAccountantCustomerPayload.d.ts +44 -0
- package/lib/entity/aiAccountantCustomer/aiAccountantCustomerPayload.js +53 -0
- package/lib/entity/aiAccountantCustomer/aiAccountantCustomerReducer.d.ts +10 -0
- package/lib/entity/aiAccountantCustomer/aiAccountantCustomerReducer.js +49 -0
- package/lib/entity/aiAccountantCustomer/aiAccountantCustomerSelector.d.ts +48 -0
- package/lib/entity/aiAccountantCustomer/aiAccountantCustomerSelector.js +66 -0
- package/lib/entity/aiAccountantCustomer/aiAccountantCustomerState.d.ts +52 -0
- package/lib/entity/aiAccountantCustomer/aiAccountantCustomerState.js +36 -0
- package/lib/entity/billPay/billTransaction/billTransactionState.d.ts +2 -2
- package/lib/entity/chargeCard/chargeCard.d.ts +1 -1
- package/lib/entity/depositAccountTransaction/depositAccountTransaction.d.ts +1 -1
- package/lib/entity/entityApprovalStatus/entityApprovalStatusState.d.ts +2 -2
- package/lib/entity/jeSchedules/jeSchedulesPayload.d.ts +6 -9
- package/lib/entity/jeSchedules/jeSchedulesPayload.js +2 -36
- package/lib/entity/jeSchedules/jeSchedulesSelector.d.ts +2 -4
- package/lib/entity/jeSchedules/jeSchedulesSelector.js +2 -5
- package/lib/entity/jeSchedules/jeSchedulesState.d.ts +2 -26
- package/lib/entity/jeSchedules/jeSchedulesTypes.d.ts +1 -1
- package/lib/entity/snackbar/snackbarTypes.d.ts +1 -1
- package/lib/entity/tenant/clearAllEpic.d.ts +3 -1
- package/lib/entity/tenant/clearAllEpic.js +4 -0
- package/lib/entity/transaction/payloadTypes/scheduleTransactionPayload.d.ts +1 -4
- package/lib/entity/transaction/payloadTypes/scheduleTransactionPayload.js +0 -1
- package/lib/entity/transaction/stateTypes/scheduleTransaction.d.ts +0 -1
- package/lib/entity/userRole/userRoleType.d.ts +2 -2
- package/lib/epic.d.ts +5 -1
- package/lib/epic.js +5 -1
- package/lib/esm/entity/aiAccountantCustomer/aiAccountantCustomerPayload.js +47 -0
- package/lib/esm/entity/aiAccountantCustomer/aiAccountantCustomerReducer.js +45 -0
- package/lib/esm/entity/aiAccountantCustomer/aiAccountantCustomerSelector.js +62 -0
- package/lib/esm/entity/aiAccountantCustomer/aiAccountantCustomerState.js +30 -0
- package/lib/esm/entity/jeSchedules/jeSchedulesPayload.js +2 -36
- package/lib/esm/entity/jeSchedules/jeSchedulesSelector.js +2 -5
- package/lib/esm/entity/tenant/clearAllEpic.js +4 -0
- package/lib/esm/entity/transaction/payloadTypes/scheduleTransactionPayload.js +0 -1
- package/lib/esm/epic.js +5 -1
- package/lib/esm/index.js +7 -0
- package/lib/esm/reducer.js +6 -0
- package/lib/esm/view/aiAccountantView/aiAccountantViewPayload.js +2 -0
- package/lib/esm/view/aiAccountantView/aiAccountantViewReducer.js +147 -0
- package/lib/esm/view/aiAccountantView/aiAccountantViewSelector.js +61 -0
- package/lib/esm/view/aiAccountantView/aiAccountantViewState.js +11 -0
- package/lib/esm/view/aiAccountantView/epics/cancelAiAccountantOnboardingEpic.js +26 -0
- package/lib/esm/view/aiAccountantView/epics/fetchAiAccountantCustomersEpic.js +27 -0
- package/lib/esm/view/aiAccountantView/epics/fetchAiAccountantJobsEpic.js +47 -0
- package/lib/esm/view/aiAccountantView/epics/triggerAiAccountantJobEpic.js +39 -0
- package/lib/esm/view/expenseAutomationView/epics/jeSchedule/fetchJeSchedulesEpic.js +2 -2
- package/lib/esm/view/expenseAutomationView/epics/missingReceipts/bulkUploadReceiptsEpic.js +2 -2
- package/lib/esm/view/expenseAutomationView/epics/missingReceipts/watchBulkUploadBatchStatusEpic.js +3 -4
- package/lib/esm/view/expenseAutomationView/expenseAutomationViewSelector.js +1 -0
- package/lib/esm/view/expenseAutomationView/selectors/fluxAnalysisViewSelector.js +2 -10
- package/lib/esm/view/expenseAutomationView/selectors/jeSchedulesViewSelector.js +3 -13
- package/lib/esm/view/expenseAutomationView/selectors/missingReceiptsSelector.js +3 -11
- package/lib/esm/view/expenseAutomationView/selectors/reconciliationViewSelector.js +9 -22
- package/lib/esm/view/expenseAutomationView/selectors/transactionCategorizationSelector.js +6 -12
- package/lib/esm/view/expenseAutomationView/types/jeSchedulesViewState.js +0 -1
- package/lib/esm/view/profitAndLossClassesView/profitAndLossClassesByClassHorizontalSelector.js +8 -3
- package/lib/esm/view/profitAndLossClassesView/profitAndLossHorizontalEnrichment.js +63 -144
- package/lib/esm/view/transactionDetail/transactionDetailSelector.js +2 -9
- package/lib/index.d.ts +10 -2
- package/lib/index.js +30 -2
- package/lib/reducer.d.ts +6 -0
- package/lib/reducer.js +6 -0
- package/lib/tsconfig.typecheck.tsbuildinfo +1 -1
- package/lib/view/aiAccountantView/aiAccountantViewPayload.d.ts +32 -0
- package/lib/view/aiAccountantView/aiAccountantViewPayload.js +8 -0
- package/lib/view/aiAccountantView/aiAccountantViewReducer.d.ts +29 -0
- package/lib/view/aiAccountantView/aiAccountantViewReducer.js +151 -0
- package/lib/view/aiAccountantView/aiAccountantViewSelector.d.ts +13 -0
- package/lib/view/aiAccountantView/aiAccountantViewSelector.js +67 -0
- package/lib/view/aiAccountantView/aiAccountantViewState.d.ts +27 -0
- package/lib/view/aiAccountantView/aiAccountantViewState.js +13 -0
- package/lib/view/aiAccountantView/epics/cancelAiAccountantOnboardingEpic.d.ts +20 -0
- package/lib/view/aiAccountantView/epics/cancelAiAccountantOnboardingEpic.js +30 -0
- package/lib/view/aiAccountantView/epics/fetchAiAccountantCustomersEpic.d.ts +23 -0
- package/lib/view/aiAccountantView/epics/fetchAiAccountantCustomersEpic.js +31 -0
- package/lib/view/aiAccountantView/epics/fetchAiAccountantJobsEpic.d.ts +33 -0
- package/lib/view/aiAccountantView/epics/fetchAiAccountantJobsEpic.js +51 -0
- package/lib/view/aiAccountantView/epics/triggerAiAccountantJobEpic.d.ts +15 -0
- package/lib/view/aiAccountantView/epics/triggerAiAccountantJobEpic.js +43 -0
- package/lib/view/companyView/types/cockpitTypes.d.ts +6 -5
- package/lib/view/expenseAutomationView/epics/jeSchedule/fetchJeSchedulesEpic.js +2 -2
- package/lib/view/expenseAutomationView/epics/missingReceipts/bulkUploadReceiptsEpic.js +1 -1
- package/lib/view/expenseAutomationView/epics/missingReceipts/watchBulkUploadBatchStatusEpic.js +3 -4
- package/lib/view/expenseAutomationView/expenseAutomationViewSelector.js +1 -0
- package/lib/view/expenseAutomationView/helpers/transactionCategorizationLocalDataHelper.d.ts +1 -1
- package/lib/view/expenseAutomationView/payload/jeSchedulesPayload.d.ts +1 -1
- package/lib/view/expenseAutomationView/selectors/fluxAnalysisViewSelector.js +2 -10
- package/lib/view/expenseAutomationView/selectors/jeSchedulesViewSelector.js +3 -13
- package/lib/view/expenseAutomationView/selectors/missingReceiptsSelector.js +3 -11
- package/lib/view/expenseAutomationView/selectors/reconciliationViewSelector.js +9 -22
- package/lib/view/expenseAutomationView/selectors/transactionCategorizationSelector.js +5 -11
- package/lib/view/expenseAutomationView/types/jeSchedulesViewState.d.ts +1 -1
- package/lib/view/expenseAutomationView/types/jeSchedulesViewState.js +0 -1
- package/lib/view/expenseAutomationView/types/missingReceiptsViewState.d.ts +1 -1
- package/lib/view/profitAndLossClassesView/profitAndLossClassesByClassHorizontalSelector.js +8 -3
- package/lib/view/profitAndLossClassesView/profitAndLossHorizontalEnrichment.js +63 -144
- package/lib/view/reviewCompanyView/reviewCompanyViewState.d.ts +1 -1
- package/lib/view/spendManagement/billPay/billList/billListReducer.d.ts +1 -1
- package/lib/view/spendManagement/billPay/billList/billListState.d.ts +1 -1
- package/lib/view/spendManagement/chargeCards/chargeCardDetail/chargeCardDetailReducer.d.ts +4 -4
- package/lib/view/spendManagement/reimbursement/remiListView/remiListReducer.d.ts +1 -1
- package/lib/view/spendManagement/reimbursement/remiListView/remiListState.d.ts +3 -3
- package/lib/view/subscriptionView/types/subscriptionTypes.d.ts +1 -1
- package/lib/view/transactionDetail/transactionDetailSelector.d.ts +0 -1
- package/lib/view/transactionDetail/transactionDetailSelector.js +2 -9
- package/package.json +1 -1
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { from, of } from 'rxjs';
|
|
2
|
+
import { catchError, filter, mergeMap } from 'rxjs/operators';
|
|
3
|
+
import { createZeniAPIStatus, isSuccessResponse } from '../../../responsePayload';
|
|
4
|
+
import { fetchAiAccountantCustomers, triggerAiAccountantJob, triggerAiAccountantJobFailure, triggerAiAccountantJobSuccess, } from '../aiAccountantViewReducer';
|
|
5
|
+
export const triggerAiAccountantJobEpic = (actions$, state$, zeniAPI) => actions$.pipe(filter(triggerAiAccountantJob.match), mergeMap((action) => {
|
|
6
|
+
const { operationType, params, triggeredBy } = action.payload;
|
|
7
|
+
const rootState = state$.value;
|
|
8
|
+
const selectedTenantIds = rootState.aiAccountantViewState.selectedTenantIdsForJobTrigger;
|
|
9
|
+
const entityState = rootState.aiAccountantCustomerState;
|
|
10
|
+
const customers = selectedTenantIds
|
|
11
|
+
.map((tenantId) => {
|
|
12
|
+
const customer = entityState.customerByTenantId[tenantId];
|
|
13
|
+
return customer != null
|
|
14
|
+
? { company_id: customer.companyId, tenant_id: customer.tenantId }
|
|
15
|
+
: undefined;
|
|
16
|
+
})
|
|
17
|
+
.filter((entry) => entry != null);
|
|
18
|
+
const base = `${zeniAPI.apiEndPoints.tenantMicroServiceBaseUrl}/1.0/cockpit-panels`;
|
|
19
|
+
const url = `${base}/ai-accountant/jobs`;
|
|
20
|
+
return zeniAPI
|
|
21
|
+
.postAndGetJSON(url, {
|
|
22
|
+
customers,
|
|
23
|
+
operation_type: operationType,
|
|
24
|
+
params: params ?? {},
|
|
25
|
+
triggered_by: triggeredBy ?? 'cockpit-ui',
|
|
26
|
+
})
|
|
27
|
+
.pipe(mergeMap((response) => {
|
|
28
|
+
if (isSuccessResponse(response)) {
|
|
29
|
+
return from([
|
|
30
|
+
triggerAiAccountantJobSuccess(),
|
|
31
|
+
fetchAiAccountantCustomers(),
|
|
32
|
+
]);
|
|
33
|
+
}
|
|
34
|
+
else {
|
|
35
|
+
return of(triggerAiAccountantJobFailure(response.status));
|
|
36
|
+
}
|
|
37
|
+
}), catchError((error) => of(triggerAiAccountantJobFailure(createZeniAPIStatus('Unexpected error', 'AI Accountant trigger job failed: ' +
|
|
38
|
+
JSON.stringify(error))))));
|
|
39
|
+
}));
|
|
@@ -21,13 +21,13 @@ export const fetchJeSchedulesEpic = (actions$, state$, zeniAPI) => actions$.pipe
|
|
|
21
21
|
if (isSuccessResponse(response) && response.data != null) {
|
|
22
22
|
const updateActions = [];
|
|
23
23
|
updateActions.push(updateJESchedules([
|
|
24
|
-
...response.data.
|
|
24
|
+
...response.data.draft_je_schedules,
|
|
25
25
|
...response.data.failed_je_postings.je_schedules,
|
|
26
26
|
]), updateJESchedulesDetails([...response.data.failed_je_postings.je_schedules], response.data.failed_je_postings.scheduled_journal_entries), initializeJeScheduleLocalData([
|
|
27
27
|
...response.data.failed_je_postings.je_schedules,
|
|
28
28
|
]));
|
|
29
29
|
updateActions.push(fetchJeSchedulesSuccess({
|
|
30
|
-
jeSchedules: [...response.data.
|
|
30
|
+
jeSchedules: [...response.data.draft_je_schedules],
|
|
31
31
|
failedJeSchedules: [
|
|
32
32
|
...response.data.failed_je_postings.je_schedules,
|
|
33
33
|
],
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { concat, of, timer } from 'rxjs';
|
|
2
|
-
import { catchError, filter, mergeMap
|
|
2
|
+
import { catchError, filter, mergeMap } from 'rxjs/operators';
|
|
3
3
|
import { createZeniAPIStatus, isSuccessResponse, } from '../../../../responsePayload';
|
|
4
4
|
import { BULK_UPLOAD_BAR_COMPLETE_HOLD_MS } from '../../bulkUploadTiming';
|
|
5
5
|
import { bulkUploadReceipts, bulkUploadReceiptsFailure, bulkUploadReceiptsSuccess, updateBulkUploadProgress, } from '../../reducers/missingReceiptsViewReducer';
|
|
6
|
-
export const bulkUploadReceiptsEpic = (actions$, _state$, zeniAPI) => actions$.pipe(filter(bulkUploadReceipts.match),
|
|
6
|
+
export const bulkUploadReceiptsEpic = (actions$, _state$, zeniAPI) => actions$.pipe(filter(bulkUploadReceipts.match), mergeMap((action) => {
|
|
7
7
|
const { files } = action.payload;
|
|
8
8
|
const formData = new FormData();
|
|
9
9
|
for (const file of files) {
|
package/lib/esm/view/expenseAutomationView/epics/missingReceipts/watchBulkUploadBatchStatusEpic.js
CHANGED
|
@@ -25,7 +25,7 @@ export const pusherBatchStatusCompletionEpic = (actions$) => actions$.pipe(filte
|
|
|
25
25
|
* force `phase` to `completed` (dismiss automatching banner) and refresh the batch list.
|
|
26
26
|
* Cancels when the batch completes normally, bulk state is cleared, or another upload supersedes.
|
|
27
27
|
*/
|
|
28
|
-
export const bulkUploadAutomatchingTimeoutEpic = (actions$, state$) => actions$.pipe(filter(bulkUploadReceiptsSuccess.match),
|
|
28
|
+
export const bulkUploadAutomatchingTimeoutEpic = (actions$, state$) => actions$.pipe(filter(bulkUploadReceiptsSuccess.match), mergeMap((action) => {
|
|
29
29
|
const { batchId } = action.payload;
|
|
30
30
|
return timer(BULK_UPLOAD_AUTOMATCHING_TIMEOUT_MS).pipe(mergeMap(() => {
|
|
31
31
|
const bulk = state$.value.expenseAutomationMissingReceiptsViewState.bulkUpload;
|
|
@@ -44,11 +44,10 @@ export const bulkUploadAutomatchingTimeoutEpic = (actions$, state$) => actions$.
|
|
|
44
44
|
* error snackbar per upload session (first failure only) so the user is not spammed every
|
|
45
45
|
* interval; Pusher or a later successful poll still completes the flow.
|
|
46
46
|
*/
|
|
47
|
-
export const pollBulkUploadBatchStatusEpic = (actions$, _state$, zeniAPI) => actions$.pipe(filter(bulkUploadReceiptsSuccess.match),
|
|
47
|
+
export const pollBulkUploadBatchStatusEpic = (actions$, _state$, zeniAPI) => actions$.pipe(filter(bulkUploadReceiptsSuccess.match), mergeMap((action) => {
|
|
48
48
|
const { batchId } = action.payload;
|
|
49
49
|
let pollErrorNotified = false;
|
|
50
|
-
return timer(FALLBACK_FIRST_DELAY_MS, FALLBACK_POLL_INTERVAL_MS).pipe(takeUntil(merge(actions$.pipe(filter(clearBulkUpload.match)), actions$.pipe(filter(pusherBatchStatusUpdate.match), filter((action) => action.payload.batchId === batchId
|
|
51
|
-
action.payload.status === 'completed')), actions$.pipe(filter(fetchBulkUploadBatchDetailsSuccess.match), filter((action) => action.payload.batchId === batchId)), actions$.pipe(filter(bulkUploadAutomatchingTimedOut.match), filter((action) => action.payload.batchId === batchId)))), switchMap(() => zeniAPI
|
|
50
|
+
return timer(FALLBACK_FIRST_DELAY_MS, FALLBACK_POLL_INTERVAL_MS).pipe(takeUntil(merge(actions$.pipe(filter(clearBulkUpload.match)), actions$.pipe(filter(pusherBatchStatusUpdate.match), filter((action) => action.payload.batchId === batchId)), actions$.pipe(filter(fetchBulkUploadBatchDetailsSuccess.match), filter((action) => action.payload.batchId === batchId)), actions$.pipe(filter(bulkUploadAutomatchingTimedOut.match), filter((action) => action.payload.batchId === batchId)))), switchMap(() => zeniAPI
|
|
52
51
|
.getJSON(`${zeniAPI.apiEndPoints.communicationAgentMicroServiceBaseUrl}/1.0/batches/${batchId}`)
|
|
53
52
|
.pipe(mergeMap((response) => {
|
|
54
53
|
/** Same batch-details URL; polls until `status` is completed (Pusher may win first). */
|
|
@@ -91,6 +91,7 @@ export function getExpenseAutomationView(state) {
|
|
|
91
91
|
const fetchStateVariables = [
|
|
92
92
|
expenseAutomationMissingReceiptsViewState,
|
|
93
93
|
expenseAutomationJESchedulesViewState,
|
|
94
|
+
monthEndCloseChecksView,
|
|
94
95
|
expenseAutomationTransactionsView,
|
|
95
96
|
expenseAutomationReconciliationViewState,
|
|
96
97
|
];
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import { reduceAnyFetchState } from '../../../commonStateTypes/reduceFetchState';
|
|
2
1
|
import { toMonthYearPeriodId } from '../../../commonStateTypes/timePeriod';
|
|
3
2
|
import { getAccountBase } from '../../../entity/account/accountSelector';
|
|
4
3
|
import { getClassById } from '../../../entity/class/classSelector';
|
|
@@ -7,7 +6,7 @@ import { getUserByUserId } from '../../../entity/user/userSelector';
|
|
|
7
6
|
import { getVendorByVendorId } from '../../../entity/vendor/vendorSelector';
|
|
8
7
|
import { getAllSteps } from '../selectorTypes/expenseAutomationViewSelectorTypes';
|
|
9
8
|
export function getExpenseAutomationFluxAnalysisView(state) {
|
|
10
|
-
const { expenseAutomationFluxAnalysisViewState, monthEndCloseChecksState
|
|
9
|
+
const { expenseAutomationFluxAnalysisViewState, monthEndCloseChecksState } = state;
|
|
11
10
|
const { fetchState, error, refreshStatus, uiState, reviewOperatingExpenseIdsByPeriod, selectedSectionIdsByPeriod, groupsBySelectedPeriod, fluxAnalysisEntities, bulkReviewStatus, currency, totalBalancesAndVariance, } = expenseAutomationFluxAnalysisViewState;
|
|
12
11
|
const fetchStateAndError = {
|
|
13
12
|
fetchState,
|
|
@@ -92,17 +91,10 @@ export function getExpenseAutomationFluxAnalysisView(state) {
|
|
|
92
91
|
},
|
|
93
92
|
};
|
|
94
93
|
const completionStatus = fluxCompletionStatus != null ? fluxCompletionStatus : 'incomplete';
|
|
95
|
-
const monthEndFetchState = monthYearPeriodId != null
|
|
96
|
-
? (monthEndCloseChecksViewState.monthEndCloseChecksViewByTenantId[currentTenant.tenantId]?.[monthYearPeriodId] ?? { fetchState: 'Not-Started', error: undefined })
|
|
97
|
-
: { fetchState: 'Not-Started', error: undefined };
|
|
98
|
-
const reducedFetchStatus = reduceAnyFetchState([
|
|
99
|
-
fetchStateAndError,
|
|
100
|
-
monthEndFetchState,
|
|
101
|
-
]);
|
|
102
94
|
return {
|
|
103
95
|
sections,
|
|
104
96
|
totalBalancesAndVariance,
|
|
105
|
-
fetchStatus:
|
|
97
|
+
fetchStatus: fetchStateAndError,
|
|
106
98
|
bulkReviewStatus,
|
|
107
99
|
reviewOperatingExpensesIds,
|
|
108
100
|
selectedSectionIds,
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import omit from 'lodash/omit';
|
|
2
2
|
import orderBy from 'lodash/orderBy';
|
|
3
|
-
import { reduceAnyFetchState } from '../../../commonStateTypes/reduceFetchState';
|
|
4
3
|
import { toMonthYearPeriodId } from '../../../commonStateTypes/timePeriod';
|
|
5
4
|
import { getAccountIdsForTypes } from '../../../entity/account/accountSelector';
|
|
6
5
|
import { getJEScheduledTransactionByJEScheduleTransactionKey, } from '../../../entity/jeSchedules/jeSchedulesSelector';
|
|
@@ -20,8 +19,6 @@ function getJEScheduleSortAccessor(sortKey) {
|
|
|
20
19
|
return (s) => s.jeDebit.account?.accountName?.toLowerCase();
|
|
21
20
|
case 'class':
|
|
22
21
|
return (s) => s.jeDebit.accountingClass?.className?.toLowerCase();
|
|
23
|
-
case 'depCategory':
|
|
24
|
-
return (s) => s.jeCredit.account?.accountName?.toLowerCase();
|
|
25
22
|
case 'scheduleCategory':
|
|
26
23
|
return (s) => s.jeScheduleType;
|
|
27
24
|
case 'startMonth':
|
|
@@ -53,7 +50,7 @@ function sortJEScheduledTransactions(transactions, sortKey, sortOrder) {
|
|
|
53
50
|
export function getExpenseAutomationJESchedulesView(state) {
|
|
54
51
|
const jeScheduledTransaction = [];
|
|
55
52
|
const failedJeScheduledTransaction = [];
|
|
56
|
-
const { accountState, accountListState, classState, classListState, expenseAutomationJESchedulesViewState, expenseAutomationViewState, monthEndCloseChecksState,
|
|
53
|
+
const { accountState, accountListState, classState, classListState, expenseAutomationJESchedulesViewState, expenseAutomationViewState, monthEndCloseChecksState, } = state;
|
|
57
54
|
const { jeScheduleTransactionKeysByPeriod, failedJeScheduleTransactionKeysByPeriod, jeScheduleLocalDataById, postStatusById, ignoreStatusById, uiState, error, fetchState, refreshStatus, } = expenseAutomationJESchedulesViewState;
|
|
58
55
|
const accountSettingsView = getJEAccountSettingsView(state);
|
|
59
56
|
const currentTenant = getCurrentTenant(state);
|
|
@@ -119,13 +116,6 @@ export function getExpenseAutomationJESchedulesView(state) {
|
|
|
119
116
|
: [];
|
|
120
117
|
const jeCompletionStatus = allSteps.find((step) => step.step === 'je_schedules')?.completionStatus;
|
|
121
118
|
const completionStatus = jeCompletionStatus != null ? jeCompletionStatus : 'incomplete';
|
|
122
|
-
const monthEndFetchState = monthYearPeriodId != null
|
|
123
|
-
? (monthEndCloseChecksViewState.monthEndCloseChecksViewByTenantId[currentTenant.tenantId]?.[monthYearPeriodId] ?? { fetchState: 'Not-Started', error: undefined })
|
|
124
|
-
: { fetchState: 'Not-Started', error: undefined };
|
|
125
|
-
const reducedFetchStatus = reduceAnyFetchState([
|
|
126
|
-
{ fetchState, error },
|
|
127
|
-
monthEndFetchState,
|
|
128
|
-
]);
|
|
129
119
|
return {
|
|
130
120
|
uncategorizedAccounts,
|
|
131
121
|
allDepreciationAccountList: filteredDepAccounts,
|
|
@@ -141,10 +131,10 @@ export function getExpenseAutomationJESchedulesView(state) {
|
|
|
141
131
|
accountSettingsView,
|
|
142
132
|
postStatusById: postStatusById,
|
|
143
133
|
ignoreStatusById: ignoreStatusById,
|
|
144
|
-
fetchState:
|
|
134
|
+
fetchState: fetchState,
|
|
145
135
|
jeScheduleLocalDataById: jeScheduleLocalDataById,
|
|
146
136
|
uiState: uiState,
|
|
147
|
-
error:
|
|
137
|
+
error: error,
|
|
148
138
|
refreshStatus,
|
|
149
139
|
completionStatus,
|
|
150
140
|
};
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import orderBy from 'lodash/orderBy';
|
|
2
|
-
import { reduceAnyFetchState } from '../../../commonStateTypes/reduceFetchState';
|
|
3
2
|
import { toMonthYearPeriodId } from '../../../commonStateTypes/timePeriod';
|
|
4
3
|
import { getCurrentTenant } from '../../../entity/tenant/tenantSelector';
|
|
5
4
|
import { getSupportedTransactionById, getSupportedTransactionsByIds, } from '../../../entity/transaction/transactionSelector';
|
|
@@ -8,7 +7,7 @@ import { getCompletedTransactionsCacheKey } from '../reducers/missingReceiptsVie
|
|
|
8
7
|
import { getAllSteps } from '../selectorTypes/expenseAutomationViewSelectorTypes';
|
|
9
8
|
import { isUnmatchedTabFileStatus, } from '../types/missingReceiptsViewState';
|
|
10
9
|
export function getExpenseAutomationMissingReceiptsView(state) {
|
|
11
|
-
const { expenseAutomationMissingReceiptsViewState, expenseAutomationViewState, transactionState, monthEndCloseChecksState,
|
|
10
|
+
const { expenseAutomationMissingReceiptsViewState, expenseAutomationViewState, transactionState, monthEndCloseChecksState, } = state;
|
|
12
11
|
const currentTenant = getCurrentTenant(state);
|
|
13
12
|
const { selectedPeriodByTenantId } = expenseAutomationViewState;
|
|
14
13
|
const selectedPeriod = selectedPeriodByTenantId[currentTenant.tenantId];
|
|
@@ -176,16 +175,9 @@ export function getExpenseAutomationMissingReceiptsView(state) {
|
|
|
176
175
|
vendorLogo: result.vendorLogo ?? transaction?.logo?.href,
|
|
177
176
|
};
|
|
178
177
|
});
|
|
179
|
-
const monthEndFetchState = monthYearPeriodId != null
|
|
180
|
-
? (monthEndCloseChecksViewState.monthEndCloseChecksViewByTenantId[currentTenant.tenantId]?.[monthYearPeriodId] ?? { fetchState: 'Not-Started', error: undefined })
|
|
181
|
-
: { fetchState: 'Not-Started', error: undefined };
|
|
182
|
-
const reducedFetchStatus = reduceAnyFetchState([
|
|
183
|
-
{ fetchState, error },
|
|
184
|
-
monthEndFetchState,
|
|
185
|
-
]);
|
|
186
178
|
return {
|
|
187
|
-
fetchState
|
|
188
|
-
error
|
|
179
|
+
fetchState,
|
|
180
|
+
error,
|
|
189
181
|
uploadReceiptStatusById,
|
|
190
182
|
uiState,
|
|
191
183
|
refreshStatus,
|
|
@@ -13,7 +13,7 @@ import { getAccountList, getNestedAccountListHierarchy, } from '../../accountLis
|
|
|
13
13
|
import { getClassList, getNestedClassListHierarchy, } from '../../classList/classListSelector';
|
|
14
14
|
import { initialActionFetchState, initialReconciliationTabsState, initialState, } from '../reducers/reconciliationViewReducer';
|
|
15
15
|
import { getAllSteps } from '../selectorTypes/expenseAutomationViewSelectorTypes';
|
|
16
|
-
export const getExpenseAutomationReconciliationView = createSelector((state) => state, (state) => getCurrentTenant(state), (state) => state.expenseAutomationReconciliationViewState, (state) => state.expenseAutomationViewState, (state) => state.plaidAccountViewState, (state) => state.accountListState, (state) => state.accountState, (state) => state.classListState, (state) => state.classState, (state) => state.monthEndCloseChecksState, (state) => state.vendorState, (state
|
|
16
|
+
export const getExpenseAutomationReconciliationView = createSelector((state) => state, (state) => getCurrentTenant(state), (state) => state.expenseAutomationReconciliationViewState, (state) => state.expenseAutomationViewState, (state) => state.plaidAccountViewState, (state) => state.accountListState, (state) => state.accountState, (state) => state.classListState, (state) => state.classState, (state) => state.monthEndCloseChecksState, (state) => state.vendorState, (state, currentTenant, reconciliationViewState, expenseAutomationViewState, plaidAccountViewState, accountListState, accountState, classListState, classState, monthEndCloseChecksState, vendorState) => {
|
|
17
17
|
const { selectedPeriodByTenantId } = expenseAutomationViewState;
|
|
18
18
|
const reconcileTabUiState = reconciliationViewState.reconTabsState.reconcile.uiState;
|
|
19
19
|
const reviewTabUiState = reconciliationViewState.reconTabsState.review.uiState;
|
|
@@ -35,13 +35,6 @@ export const getExpenseAutomationReconciliationView = createSelector((state) =>
|
|
|
35
35
|
}
|
|
36
36
|
return acc;
|
|
37
37
|
}, []);
|
|
38
|
-
const monthYearPeriodId = selectedPeriod != null ? toMonthYearPeriodId(selectedPeriod) : null;
|
|
39
|
-
const monthEndFetchState = monthYearPeriodId != null
|
|
40
|
-
? (monthEndCloseChecksViewState.monthEndCloseChecksViewByTenantId[currentTenant.tenantId]?.[monthYearPeriodId] ?? {
|
|
41
|
-
fetchState: 'Not-Started',
|
|
42
|
-
error: undefined,
|
|
43
|
-
})
|
|
44
|
-
: { fetchState: 'Not-Started', error: undefined };
|
|
45
38
|
if (accountReconForMonthYearPeriod == null) {
|
|
46
39
|
return {
|
|
47
40
|
bankAccounts: [],
|
|
@@ -51,13 +44,10 @@ export const getExpenseAutomationReconciliationView = createSelector((state) =>
|
|
|
51
44
|
classListNestedAccountHierarchy: [],
|
|
52
45
|
allAccountList: [],
|
|
53
46
|
allClassList: [],
|
|
54
|
-
fetchStatus:
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
},
|
|
59
|
-
monthEndFetchState,
|
|
60
|
-
]),
|
|
47
|
+
fetchStatus: {
|
|
48
|
+
fetchState: reconciliationViewState.fetchState,
|
|
49
|
+
error: reconciliationViewState.error,
|
|
50
|
+
},
|
|
61
51
|
plaidConnectionDetails: plaidAccountViewState['expense_automation_reconcile']
|
|
62
52
|
.plaidConnectionDetails,
|
|
63
53
|
completionStatus: 'incomplete',
|
|
@@ -280,13 +270,10 @@ export const getExpenseAutomationReconciliationView = createSelector((state) =>
|
|
|
280
270
|
bankAccounts: uniqueBankAccounts,
|
|
281
271
|
creditCards: uniqueCreditCards,
|
|
282
272
|
accountReconciliationsByAccountID: reconList,
|
|
283
|
-
fetchStatus:
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
},
|
|
288
|
-
monthEndFetchState,
|
|
289
|
-
]),
|
|
273
|
+
fetchStatus: {
|
|
274
|
+
fetchState: reconciliationViewState.fetchState,
|
|
275
|
+
error: reconciliationViewState.error,
|
|
276
|
+
},
|
|
290
277
|
plaidConnectionDetails: plaidAccountViewState['expense_automation_reconcile']
|
|
291
278
|
.plaidConnectionDetails,
|
|
292
279
|
reconciliationTabsState: reconciliationViewState.reconTabsState,
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import omit from 'lodash/omit';
|
|
2
|
-
import { reduceAllFetchState
|
|
2
|
+
import { reduceAllFetchState } from '../../../commonStateTypes/reduceFetchState';
|
|
3
3
|
import { toMonthYearPeriodId } from '../../../commonStateTypes/timePeriod';
|
|
4
4
|
import { getCurrentTenant } from '../../../entity/tenant/tenantSelector';
|
|
5
5
|
import { getTransactionWithCOT } from '../../../entity/transaction/transactionHelper';
|
|
@@ -8,7 +8,7 @@ import { getAccountList, getNestedAccountListHierarchy, getUncategorizedAccounts
|
|
|
8
8
|
import { getClassList, getNestedClassListHierarchy, } from '../../classList/classListSelector';
|
|
9
9
|
import { getAllSteps } from '../selectorTypes/expenseAutomationViewSelectorTypes';
|
|
10
10
|
export function getExpenseAutomationTransactionView(state) {
|
|
11
|
-
const { accountState, classState, classListState, accountListState, expenseAutomationTransactionsViewState, expenseAutomationViewState, transactionState, monthEndCloseChecksState,
|
|
11
|
+
const { accountState, classState, classListState, accountListState, expenseAutomationTransactionsViewState, expenseAutomationViewState, transactionState, monthEndCloseChecksState, } = state;
|
|
12
12
|
const { selectedTransactionCategorizationTab } = expenseAutomationTransactionsViewState;
|
|
13
13
|
const { uiState, refreshStatus, saveStatus, markAsNotMiscategorizedStatus, transactionIdsBySelectedPeriod, transactionReviewLocalDataById, selectedCheckBoxTransactionIds, transactionIdsWithUnsavedData, uploadReceiptStatusById, selectedTransactionId, selectedTransactionLineId, } = expenseAutomationTransactionsViewState.transactionCategorizationView[selectedTransactionCategorizationTab];
|
|
14
14
|
const uncategorizedIncomeExpense = getUncategorizedAccounts(accountState, accountListState, 'accountList');
|
|
@@ -41,16 +41,10 @@ export function getExpenseAutomationTransactionView(state) {
|
|
|
41
41
|
.filter((transaction) => transaction != null);
|
|
42
42
|
const transactions = getSupportedTransactionsByIds(transactionState, transactionIds);
|
|
43
43
|
const transactionsWithCOT = transactions.map((transaction) => getTransactionWithCOT(transaction));
|
|
44
|
-
const
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
reduceAllFetchState([
|
|
49
|
-
accountList,
|
|
50
|
-
classList,
|
|
51
|
-
expenseAutomationTransactionsViewState.transactionCategorizationView[selectedTransactionCategorizationTab],
|
|
52
|
-
]),
|
|
53
|
-
monthEndFetchState,
|
|
44
|
+
const fetchStatus = reduceAllFetchState([
|
|
45
|
+
accountList,
|
|
46
|
+
classList,
|
|
47
|
+
expenseAutomationTransactionsViewState.transactionCategorizationView[selectedTransactionCategorizationTab],
|
|
54
48
|
]);
|
|
55
49
|
const totalCountByReview = expenseAutomationTransactionsViewState.transactionCategorizationView.review
|
|
56
50
|
.uiState.totalCount;
|
package/lib/esm/view/profitAndLossClassesView/profitAndLossClassesByClassHorizontalSelector.js
CHANGED
|
@@ -49,11 +49,16 @@ export const getProfitAndLossClassesHorizontalView = (filter, accountState, clas
|
|
|
49
49
|
const calculatedSections = {};
|
|
50
50
|
let reportCurrency = defaultCustomerCurrency;
|
|
51
51
|
if (fetchState.fetchState === 'Completed' && selectedPeriod != null) {
|
|
52
|
+
// Get section reports using existing selector infrastructure
|
|
53
|
+
const sectionReports = {};
|
|
54
|
+
HORIZONTAL_PANDL_SECTION_IDS.forEach((sectionId) => {
|
|
55
|
+
sectionReports[sectionId] = getSectionClassesViewReport(accountState, classState, sectionsState, { reportId, sectionId }, filter);
|
|
56
|
+
});
|
|
52
57
|
reportCurrency =
|
|
53
58
|
profitAndLossClassesViewState.currency ?? defaultCustomerCurrency;
|
|
54
|
-
//
|
|
59
|
+
// Pivot each section from class→account to account→class
|
|
55
60
|
HORIZONTAL_PANDL_SECTION_IDS.forEach((sectionId) => {
|
|
56
|
-
const sectionReport =
|
|
61
|
+
const sectionReport = sectionReports[sectionId];
|
|
57
62
|
if (sectionReport != null) {
|
|
58
63
|
sections[sectionId] = pivotSectionToHorizontal(sectionReport, classColumns, SECTION_TITLES[sectionId] ?? sectionId, reportCurrency);
|
|
59
64
|
}
|
|
@@ -256,7 +261,7 @@ function sumBalancesInSlice(balances) {
|
|
|
256
261
|
if (balances.length === 0) {
|
|
257
262
|
return 0;
|
|
258
263
|
}
|
|
259
|
-
const summed = getSummationFreeRangeTotalBalance(balances);
|
|
264
|
+
const summed = getSummationFreeRangeTotalBalance([...balances]);
|
|
260
265
|
return summed?.balance.amount ?? 0;
|
|
261
266
|
}
|
|
262
267
|
/**
|
|
@@ -25,31 +25,30 @@ function enrichHorizontalSection(report, section) {
|
|
|
25
25
|
return total?.balance.amount ?? 0;
|
|
26
26
|
});
|
|
27
27
|
section.sectionHeaderBalancesSlice = buildHorizontalClassColumnBalancesSlice(report, classAmounts, section.sectionTotal.amount);
|
|
28
|
-
const
|
|
29
|
-
const childrenRowIndicesByParent = buildHorizontalAccountChildIndicesByParent(parentIndices);
|
|
28
|
+
const childrenRowIndicesByParent = buildHorizontalAccountChildIndicesByParent(section.accounts);
|
|
30
29
|
const childrenRecord = {};
|
|
31
30
|
childrenRowIndicesByParent.forEach((childIndices, parentIndex) => {
|
|
32
31
|
childrenRecord[parentIndex] = childIndices;
|
|
33
32
|
});
|
|
34
33
|
section.treeLayout = {
|
|
35
34
|
rootAccountRowIndices: section.accounts
|
|
36
|
-
.map((_, i) => (
|
|
35
|
+
.map((_, i) => findHorizontalAccountParentIndex(section.accounts, i) === -1 ? i : -1)
|
|
37
36
|
.filter((i) => i >= 0),
|
|
38
37
|
childrenRowIndicesByParent: childrenRecord,
|
|
39
38
|
};
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
39
|
+
for (let i = 0; i < section.accounts.length; i++) {
|
|
40
|
+
const row = section.accounts[i];
|
|
41
|
+
const classRowAmounts = report.classColumns.map((col) => {
|
|
42
|
+
const cb = row.classBalances.find((b) => b.classId === col.classId);
|
|
43
|
+
return cb?.balance.amount ?? 0;
|
|
44
|
+
});
|
|
46
45
|
row.accountReportData = {
|
|
47
46
|
accountId: row.accountId,
|
|
48
47
|
accountName: row.accountName,
|
|
49
48
|
accountType: row.accountType,
|
|
50
49
|
depth: row.depth,
|
|
51
50
|
balancesInTimeframe: buildHorizontalClassColumnBalancesSlice(report, classRowAmounts, row.rowTotal.amount),
|
|
52
|
-
horizontalTreeView:
|
|
51
|
+
horizontalTreeView: buildHorizontalTreeView(section.accounts, i),
|
|
53
52
|
};
|
|
54
53
|
}
|
|
55
54
|
}
|
|
@@ -81,9 +80,9 @@ function buildHorizontalClassColumnBalancesSlice(report, classAmounts, totalAmou
|
|
|
81
80
|
return emptySlice;
|
|
82
81
|
}
|
|
83
82
|
const { startDate, endDate } = report.selectedPeriod;
|
|
84
|
-
const balances = report.classColumns.map((col,
|
|
83
|
+
const balances = report.classColumns.map((col, i) => ({
|
|
85
84
|
balance: {
|
|
86
|
-
amount: classAmounts[
|
|
85
|
+
amount: classAmounts[i] ?? 0,
|
|
87
86
|
currencyCode,
|
|
88
87
|
currencySymbol,
|
|
89
88
|
},
|
|
@@ -121,157 +120,64 @@ function buildHorizontalClassColumnBalancesSlice(report, classAmounts, totalAmou
|
|
|
121
120
|
},
|
|
122
121
|
};
|
|
123
122
|
}
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
if (accountRow == null) {
|
|
135
|
-
continue;
|
|
136
|
-
}
|
|
137
|
-
const depth = accountRow.depth;
|
|
138
|
-
while (stack.length > 0) {
|
|
139
|
-
const topIndex = stack[stack.length - 1];
|
|
140
|
-
if (topIndex == null) {
|
|
141
|
-
break;
|
|
142
|
-
}
|
|
143
|
-
const topRow = rows[topIndex];
|
|
144
|
-
if (topRow == null) {
|
|
145
|
-
stack.pop();
|
|
146
|
-
continue;
|
|
147
|
-
}
|
|
148
|
-
if (topRow.depth < depth) {
|
|
149
|
-
break;
|
|
150
|
-
}
|
|
151
|
-
stack.pop();
|
|
152
|
-
}
|
|
153
|
-
if (depth <= 2) {
|
|
154
|
-
parentIndex[rowIndex] = -1;
|
|
155
|
-
}
|
|
156
|
-
else if (stack.length === 0) {
|
|
157
|
-
parentIndex[rowIndex] = -1;
|
|
158
|
-
}
|
|
159
|
-
else {
|
|
160
|
-
const peek = stack[stack.length - 1];
|
|
161
|
-
if (peek == null) {
|
|
162
|
-
parentIndex[rowIndex] = -1;
|
|
163
|
-
}
|
|
164
|
-
else {
|
|
165
|
-
const parentRow = rows[peek];
|
|
166
|
-
parentIndex[rowIndex] =
|
|
167
|
-
parentRow != null && parentRow.depth === depth - 1 ? peek : -1;
|
|
123
|
+
function findHorizontalAccountParentIndex(dfsOrderedAccountRows, childRowIndex) {
|
|
124
|
+
const childDepth = dfsOrderedAccountRows[childRowIndex].depth;
|
|
125
|
+
if (childDepth <= 2) {
|
|
126
|
+
return -1;
|
|
127
|
+
}
|
|
128
|
+
for (let earlierRowIndex = childRowIndex - 1; earlierRowIndex >= 0; earlierRowIndex--) {
|
|
129
|
+
const earlierDepth = dfsOrderedAccountRows[earlierRowIndex].depth;
|
|
130
|
+
if (earlierDepth < childDepth) {
|
|
131
|
+
if (earlierDepth === childDepth - 1) {
|
|
132
|
+
return earlierRowIndex;
|
|
168
133
|
}
|
|
134
|
+
return -1;
|
|
169
135
|
}
|
|
170
|
-
stack.push(rowIndex);
|
|
171
136
|
}
|
|
172
|
-
return
|
|
137
|
+
return -1;
|
|
173
138
|
}
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
const
|
|
177
|
-
const
|
|
178
|
-
for (let
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
}
|
|
184
|
-
const key = `${parentRowIndex}:${accountRow.depth}`;
|
|
185
|
-
let siblingGroup = keyToIndices.get(key);
|
|
186
|
-
if (siblingGroup == null) {
|
|
187
|
-
siblingGroup = [];
|
|
188
|
-
keyToIndices.set(key, siblingGroup);
|
|
139
|
+
function getHorizontalAccountSiblingIndices(dfsOrderedAccountRows, rowIndex) {
|
|
140
|
+
const parentRowIndex = findHorizontalAccountParentIndex(dfsOrderedAccountRows, rowIndex);
|
|
141
|
+
const rowDepth = dfsOrderedAccountRows[rowIndex].depth;
|
|
142
|
+
const siblings = [];
|
|
143
|
+
for (let i = 0; i < dfsOrderedAccountRows.length; i++) {
|
|
144
|
+
if (dfsOrderedAccountRows[i].depth === rowDepth &&
|
|
145
|
+
findHorizontalAccountParentIndex(dfsOrderedAccountRows, i) ===
|
|
146
|
+
parentRowIndex) {
|
|
147
|
+
siblings.push(i);
|
|
189
148
|
}
|
|
190
|
-
siblingGroup.push(rowIndex);
|
|
191
149
|
}
|
|
192
|
-
|
|
193
|
-
for (let rowIndex = 0; rowIndex < accountRowCount; rowIndex++) {
|
|
194
|
-
const parentRowIndex = parentIndices[rowIndex];
|
|
195
|
-
const accountRow = rows[rowIndex];
|
|
196
|
-
if (parentRowIndex == null || accountRow == null) {
|
|
197
|
-
siblingsPerRow[rowIndex] = [rowIndex];
|
|
198
|
-
continue;
|
|
199
|
-
}
|
|
200
|
-
const key = `${parentRowIndex}:${accountRow.depth}`;
|
|
201
|
-
const group = keyToIndices.get(key);
|
|
202
|
-
siblingsPerRow[rowIndex] = group != null ? group : [rowIndex];
|
|
203
|
-
}
|
|
204
|
-
return siblingsPerRow;
|
|
150
|
+
return siblings;
|
|
205
151
|
}
|
|
206
|
-
function
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
for (let rowIndex = 0; rowIndex < rowCount; rowIndex++) {
|
|
210
|
-
const parentRowIndex = parentIndices[rowIndex];
|
|
211
|
-
if (parentRowIndex != null &&
|
|
212
|
-
parentRowIndex >= 0 &&
|
|
213
|
-
parentRowIndex < rowCount) {
|
|
214
|
-
flags[parentRowIndex] = true;
|
|
215
|
-
}
|
|
216
|
-
}
|
|
217
|
-
return flags;
|
|
152
|
+
function horizontalAccountHasChildRows(dfsOrderedAccountRows, parentRowIndex) {
|
|
153
|
+
return dfsOrderedAccountRows.some((_, rowIndex) => findHorizontalAccountParentIndex(dfsOrderedAccountRows, rowIndex) ===
|
|
154
|
+
parentRowIndex);
|
|
218
155
|
}
|
|
219
|
-
function
|
|
220
|
-
const
|
|
156
|
+
function buildHorizontalSubAccountAncestorMetadata(dfsOrderedAccountRows, currentRowIndex) {
|
|
157
|
+
const ancestorRowIndicesRootToLeaf = [];
|
|
221
158
|
let walkRowIndex = currentRowIndex;
|
|
222
159
|
while (walkRowIndex >= 0) {
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
if (parentRowIndex == null) {
|
|
226
|
-
break;
|
|
227
|
-
}
|
|
228
|
-
walkRowIndex = parentRowIndex;
|
|
160
|
+
ancestorRowIndicesRootToLeaf.unshift(walkRowIndex);
|
|
161
|
+
walkRowIndex = findHorizontalAccountParentIndex(dfsOrderedAccountRows, walkRowIndex);
|
|
229
162
|
}
|
|
230
|
-
return
|
|
231
|
-
const
|
|
232
|
-
const siblingIndices = siblingsPerRow[rowIndex];
|
|
233
|
-
const hasChild = hasChildFlags[rowIndex];
|
|
234
|
-
if (accountRow == null || siblingIndices == null) {
|
|
235
|
-
return {
|
|
236
|
-
depth: 0,
|
|
237
|
-
hasSibling: false,
|
|
238
|
-
hasChildren: hasChild === true,
|
|
239
|
-
isLastNode: true,
|
|
240
|
-
name: '',
|
|
241
|
-
};
|
|
242
|
-
}
|
|
163
|
+
return ancestorRowIndicesRootToLeaf.map((rowIndex) => {
|
|
164
|
+
const siblingIndices = getHorizontalAccountSiblingIndices(dfsOrderedAccountRows, rowIndex);
|
|
243
165
|
return {
|
|
244
|
-
depth:
|
|
166
|
+
depth: dfsOrderedAccountRows[rowIndex].depth - 2,
|
|
245
167
|
hasSibling: siblingIndices.length > 1,
|
|
246
|
-
hasChildren:
|
|
168
|
+
hasChildren: horizontalAccountHasChildRows(dfsOrderedAccountRows, rowIndex),
|
|
247
169
|
isLastNode: rowIndex === siblingIndices[siblingIndices.length - 1],
|
|
248
|
-
name:
|
|
170
|
+
name: dfsOrderedAccountRows[rowIndex].accountName,
|
|
249
171
|
};
|
|
250
172
|
});
|
|
251
173
|
}
|
|
252
|
-
function
|
|
253
|
-
const siblingIndices = siblingsPerRow[currentRowIndex];
|
|
254
|
-
const accountRow = dfsOrderedAccountRows[currentRowIndex];
|
|
255
|
-
const hasChildrenFlag = hasChildFlags[currentRowIndex];
|
|
256
|
-
const treeDepth = accountRow != null ? Math.max(0, accountRow.depth - 2) : 0;
|
|
257
|
-
const hasChildren = hasChildrenFlag === true;
|
|
258
|
-
const siblings = siblingIndices ?? [currentRowIndex];
|
|
259
|
-
return {
|
|
260
|
-
subAccountAncestorMetadata: buildHorizontalSubAccountAncestorMetadataFromPrecomputed(dfsOrderedAccountRows, currentRowIndex, parentIndices, siblingsPerRow, hasChildFlags),
|
|
261
|
-
treeDepth,
|
|
262
|
-
hasChildren,
|
|
263
|
-
hasSiblings: siblings.length > 1,
|
|
264
|
-
isLeaf: !hasChildren,
|
|
265
|
-
isLastNode: currentRowIndex === siblings[siblings.length - 1],
|
|
266
|
-
};
|
|
267
|
-
}
|
|
268
|
-
function buildHorizontalAccountChildIndicesByParent(parentIndices) {
|
|
174
|
+
function buildHorizontalAccountChildIndicesByParent(dfsOrderedAccountRows) {
|
|
269
175
|
const childIndicesByParentRowIndex = new Map();
|
|
270
|
-
for (let rowIndex = 0; rowIndex <
|
|
271
|
-
const parentRowIndex =
|
|
272
|
-
if (parentRowIndex
|
|
176
|
+
for (let rowIndex = 0; rowIndex < dfsOrderedAccountRows.length; rowIndex++) {
|
|
177
|
+
const parentRowIndex = findHorizontalAccountParentIndex(dfsOrderedAccountRows, rowIndex);
|
|
178
|
+
if (parentRowIndex >= 0) {
|
|
273
179
|
let childRowIndices = childIndicesByParentRowIndex.get(parentRowIndex);
|
|
274
|
-
if (childRowIndices
|
|
180
|
+
if (childRowIndices === undefined) {
|
|
275
181
|
childRowIndices = [];
|
|
276
182
|
childIndicesByParentRowIndex.set(parentRowIndex, childRowIndices);
|
|
277
183
|
}
|
|
@@ -280,3 +186,16 @@ function buildHorizontalAccountChildIndicesByParent(parentIndices) {
|
|
|
280
186
|
}
|
|
281
187
|
return childIndicesByParentRowIndex;
|
|
282
188
|
}
|
|
189
|
+
function buildHorizontalTreeView(dfsOrderedAccountRows, currentRowIndex) {
|
|
190
|
+
const treeDepth = Math.max(0, dfsOrderedAccountRows[currentRowIndex].depth - 2);
|
|
191
|
+
const siblingIndices = getHorizontalAccountSiblingIndices(dfsOrderedAccountRows, currentRowIndex);
|
|
192
|
+
const hasChildren = horizontalAccountHasChildRows(dfsOrderedAccountRows, currentRowIndex);
|
|
193
|
+
return {
|
|
194
|
+
subAccountAncestorMetadata: buildHorizontalSubAccountAncestorMetadata(dfsOrderedAccountRows, currentRowIndex),
|
|
195
|
+
treeDepth,
|
|
196
|
+
hasChildren,
|
|
197
|
+
hasSiblings: siblingIndices.length > 1,
|
|
198
|
+
isLeaf: !hasChildren,
|
|
199
|
+
isLastNode: currentRowIndex === siblingIndices[siblingIndices.length - 1],
|
|
200
|
+
};
|
|
201
|
+
}
|