@zeniai/client-epic-state 4.19.87-betaVR2 → 4.19.88-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/entity/depositAccount/depositAccount.js +8 -1
- package/lib/epic.d.ts +4 -4
- package/lib/epic.js +4 -4
- package/lib/esm/entity/depositAccount/depositAccount.js +8 -1
- package/lib/esm/epic.js +4 -4
- package/lib/esm/index.js +4 -3
- package/lib/esm/view/expenseAutomationView/epics/missingReceipts/fetchMoreBatchDetailsEpic.js +1 -2
- package/lib/esm/view/expenseAutomationView/epics/missingReceipts/fetchMultipleBatchDetailsEpic.js +1 -2
- package/lib/esm/view/expenseAutomationView/epics/missingReceipts/searchTransactionsForManualMatchEpic.js +2 -3
- package/lib/esm/view/expenseAutomationView/epics/missingReceipts/watchBulkUploadBatchStatusEpic.js +1 -4
- package/lib/esm/view/expenseAutomationView/reducers/missingReceiptsViewReducer.js +11 -4
- package/lib/esm/view/expenseAutomationView/reducers/transactionsViewReducer.js +4 -1
- package/lib/esm/view/expenseAutomationView/selectors/missingReceiptsSelector.js +5 -7
- package/lib/esm/view/expenseAutomationView/types/missingReceiptsViewState.js +6 -1
- package/lib/esm/view/financeStatement/financeStatementSelector.js +5 -0
- package/lib/esm/view/profitAndLossClassesView/profitAndLossClassesByClassHorizontalSelector.js +282 -0
- package/lib/esm/view/profitAndLossClassesView/profitAndLossClassesByClassHorizontalSelectorTypes.js +1 -0
- package/lib/esm/view/profitAndLossClassesView/profitAndLossClassesViewReducer.js +5 -1
- package/lib/index.d.ts +8 -6
- package/lib/index.js +43 -40
- package/lib/tsconfig.typecheck.tsbuildinfo +1 -0
- package/lib/view/expenseAutomationView/epics/missingReceipts/fetchMoreBatchDetailsEpic.js +1 -2
- package/lib/view/expenseAutomationView/epics/missingReceipts/fetchMultipleBatchDetailsEpic.js +1 -2
- package/lib/view/expenseAutomationView/epics/missingReceipts/searchTransactionsForManualMatchEpic.js +1 -2
- package/lib/view/expenseAutomationView/epics/missingReceipts/watchBulkUploadBatchStatusEpic.js +1 -4
- package/lib/view/expenseAutomationView/payload/missingReceiptsPayload.d.ts +1 -1
- package/lib/view/expenseAutomationView/reducers/missingReceiptsViewReducer.d.ts +1 -1
- package/lib/view/expenseAutomationView/reducers/missingReceiptsViewReducer.js +11 -4
- package/lib/view/expenseAutomationView/reducers/transactionsViewReducer.js +4 -1
- package/lib/view/expenseAutomationView/selectorTypes/missingReceiptsSelectorTypes.d.ts +1 -1
- package/lib/view/expenseAutomationView/selectors/missingReceiptsSelector.js +5 -7
- package/lib/view/expenseAutomationView/types/missingReceiptsViewState.js +6 -1
- package/lib/view/financeStatement/financeStatementSelector.d.ts +2 -0
- package/lib/view/financeStatement/financeStatementSelector.js +5 -0
- package/lib/view/profitAndLossClassesView/profitAndLossClassesByClassHorizontalSelector.d.ts +13 -0
- package/lib/view/profitAndLossClassesView/profitAndLossClassesByClassHorizontalSelector.js +286 -0
- package/lib/view/profitAndLossClassesView/profitAndLossClassesByClassHorizontalSelectorTypes.d.ts +57 -0
- package/lib/view/profitAndLossClassesView/profitAndLossClassesByClassHorizontalSelectorTypes.js +2 -0
- package/lib/view/profitAndLossClassesView/profitAndLossClassesViewReducer.d.ts +4 -2
- package/lib/view/profitAndLossClassesView/profitAndLossClassesViewReducer.js +6 -2
- package/lib/view/profitAndLossClassesView/profitAndLossClassesViewState.d.ts +2 -0
- package/package.json +2 -2
|
@@ -2,7 +2,14 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.toDepositAccountStatusType = exports.toDepositSubAccounTypeCodeType = void 0;
|
|
4
4
|
const stringToUnion_1 = require("../../commonStateTypes/stringToUnion");
|
|
5
|
-
const ALL_DEPOSIT_SUB_ACCOUNT_TYPE_CODE = [
|
|
5
|
+
const ALL_DEPOSIT_SUB_ACCOUNT_TYPE_CODE = [
|
|
6
|
+
'Zinc',
|
|
7
|
+
'Bronze',
|
|
8
|
+
'Gold',
|
|
9
|
+
'Silver',
|
|
10
|
+
'Platinum',
|
|
11
|
+
'Checking',
|
|
12
|
+
];
|
|
6
13
|
const toDepositSubAccounTypeCodeType = (v) => (0, stringToUnion_1.stringToUnion)(v, ALL_DEPOSIT_SUB_ACCOUNT_TYPE_CODE);
|
|
7
14
|
exports.toDepositSubAccounTypeCodeType = toDepositSubAccounTypeCodeType;
|
|
8
15
|
const ALL_DEPOSIT_ACCOUNT_STATUS_TYPE = ['Closed', 'Open', 'Frozen'];
|
package/lib/epic.d.ts
CHANGED
|
@@ -145,14 +145,14 @@ import { ActionType as RetryExpenseAutomationJEScheduleActionType } from './view
|
|
|
145
145
|
import { ActionType as BulkUploadReceiptsActionType } from './view/expenseAutomationView/epics/missingReceipts/bulkUploadReceiptsEpic';
|
|
146
146
|
import { ActionType as ConfirmBulkUploadMatchActionType } from './view/expenseAutomationView/epics/missingReceipts/confirmBulkUploadMatchEpic';
|
|
147
147
|
import { ActionType as FetchBulkUploadBatchDetailsActionType } from './view/expenseAutomationView/epics/missingReceipts/fetchBulkUploadBatchDetailsEpic';
|
|
148
|
-
import { ActionType as FetchMultipleBatchDetailsActionType } from './view/expenseAutomationView/epics/missingReceipts/fetchMultipleBatchDetailsEpic';
|
|
149
|
-
import { ActionType as FetchMoreBatchDetailsActionType } from './view/expenseAutomationView/epics/missingReceipts/fetchMoreBatchDetailsEpic';
|
|
150
148
|
import { ActionType as FetchBulkUploadBatchesActionType } from './view/expenseAutomationView/epics/missingReceipts/fetchBulkUploadBatchesEpic';
|
|
151
|
-
import { ActionType as FetchExpenseAutomationMissingReceiptsActionType } from './view/expenseAutomationView/epics/missingReceipts/fetchMissingReceiptsEpic';
|
|
152
149
|
import { ActionType as FetchCompletedTransactionsActionType } from './view/expenseAutomationView/epics/missingReceipts/fetchCompletedTransactionsEpic';
|
|
150
|
+
import { ActionType as FetchExpenseAutomationMissingReceiptsActionType } from './view/expenseAutomationView/epics/missingReceipts/fetchMissingReceiptsEpic';
|
|
151
|
+
import { ActionType as FetchMoreBatchDetailsActionType } from './view/expenseAutomationView/epics/missingReceipts/fetchMoreBatchDetailsEpic';
|
|
152
|
+
import { ActionType as FetchMultipleBatchDetailsActionType } from './view/expenseAutomationView/epics/missingReceipts/fetchMultipleBatchDetailsEpic';
|
|
153
153
|
import { ActionType as SearchTransactionsForManualMatchActionType } from './view/expenseAutomationView/epics/missingReceipts/searchTransactionsForManualMatchEpic';
|
|
154
|
-
import { ActionType as WatchBulkUploadBatchStatusActionType } from './view/expenseAutomationView/epics/missingReceipts/watchBulkUploadBatchStatusEpic';
|
|
155
154
|
import { ActionType as UploadMissingReceiptSuccessEpicActionType } from './view/expenseAutomationView/epics/missingReceipts/uploadMissingReceiptSuccessEpic';
|
|
155
|
+
import { ActionType as WatchBulkUploadBatchStatusActionType } from './view/expenseAutomationView/epics/missingReceipts/watchBulkUploadBatchStatusEpic';
|
|
156
156
|
import { ActionType as BackgroundRefetchReviewTabActionType } from './view/expenseAutomationView/epics/transactionCategorization/backgroundRefetchReviewTabEpic';
|
|
157
157
|
import { ActionType as FetchExpenseAutomationTransactionCategorizationActionType } from './view/expenseAutomationView/epics/transactionCategorization/fetchTransactionCategorizationEpic';
|
|
158
158
|
import { ActionType as FetchExpenseAutomationTransactionCategorizationViewActionType } from './view/expenseAutomationView/epics/transactionCategorization/fetchTransactionCategorizationViewEpic';
|
package/lib/epic.js
CHANGED
|
@@ -149,14 +149,14 @@ const retryJeSchedulesEpic_1 = require("./view/expenseAutomationView/epics/jeSch
|
|
|
149
149
|
const bulkUploadReceiptsEpic_1 = require("./view/expenseAutomationView/epics/missingReceipts/bulkUploadReceiptsEpic");
|
|
150
150
|
const confirmBulkUploadMatchEpic_1 = require("./view/expenseAutomationView/epics/missingReceipts/confirmBulkUploadMatchEpic");
|
|
151
151
|
const fetchBulkUploadBatchDetailsEpic_1 = require("./view/expenseAutomationView/epics/missingReceipts/fetchBulkUploadBatchDetailsEpic");
|
|
152
|
-
const fetchMultipleBatchDetailsEpic_1 = require("./view/expenseAutomationView/epics/missingReceipts/fetchMultipleBatchDetailsEpic");
|
|
153
|
-
const fetchMoreBatchDetailsEpic_1 = require("./view/expenseAutomationView/epics/missingReceipts/fetchMoreBatchDetailsEpic");
|
|
154
152
|
const fetchBulkUploadBatchesEpic_1 = require("./view/expenseAutomationView/epics/missingReceipts/fetchBulkUploadBatchesEpic");
|
|
155
|
-
const fetchMissingReceiptsEpic_1 = require("./view/expenseAutomationView/epics/missingReceipts/fetchMissingReceiptsEpic");
|
|
156
153
|
const fetchCompletedTransactionsEpic_1 = require("./view/expenseAutomationView/epics/missingReceipts/fetchCompletedTransactionsEpic");
|
|
154
|
+
const fetchMissingReceiptsEpic_1 = require("./view/expenseAutomationView/epics/missingReceipts/fetchMissingReceiptsEpic");
|
|
155
|
+
const fetchMoreBatchDetailsEpic_1 = require("./view/expenseAutomationView/epics/missingReceipts/fetchMoreBatchDetailsEpic");
|
|
156
|
+
const fetchMultipleBatchDetailsEpic_1 = require("./view/expenseAutomationView/epics/missingReceipts/fetchMultipleBatchDetailsEpic");
|
|
157
157
|
const searchTransactionsForManualMatchEpic_1 = require("./view/expenseAutomationView/epics/missingReceipts/searchTransactionsForManualMatchEpic");
|
|
158
|
-
const watchBulkUploadBatchStatusEpic_1 = require("./view/expenseAutomationView/epics/missingReceipts/watchBulkUploadBatchStatusEpic");
|
|
159
158
|
const uploadMissingReceiptSuccessEpic_1 = require("./view/expenseAutomationView/epics/missingReceipts/uploadMissingReceiptSuccessEpic");
|
|
159
|
+
const watchBulkUploadBatchStatusEpic_1 = require("./view/expenseAutomationView/epics/missingReceipts/watchBulkUploadBatchStatusEpic");
|
|
160
160
|
const backgroundRefetchReviewTabEpic_1 = require("./view/expenseAutomationView/epics/transactionCategorization/backgroundRefetchReviewTabEpic");
|
|
161
161
|
const fetchTransactionCategorizationEpic_1 = require("./view/expenseAutomationView/epics/transactionCategorization/fetchTransactionCategorizationEpic");
|
|
162
162
|
const fetchTransactionCategorizationViewEpic_1 = require("./view/expenseAutomationView/epics/transactionCategorization/fetchTransactionCategorizationViewEpic");
|
|
@@ -1,5 +1,12 @@
|
|
|
1
1
|
import { stringToUnion } from '../../commonStateTypes/stringToUnion';
|
|
2
|
-
const ALL_DEPOSIT_SUB_ACCOUNT_TYPE_CODE = [
|
|
2
|
+
const ALL_DEPOSIT_SUB_ACCOUNT_TYPE_CODE = [
|
|
3
|
+
'Zinc',
|
|
4
|
+
'Bronze',
|
|
5
|
+
'Gold',
|
|
6
|
+
'Silver',
|
|
7
|
+
'Platinum',
|
|
8
|
+
'Checking',
|
|
9
|
+
];
|
|
3
10
|
export const toDepositSubAccounTypeCodeType = (v) => stringToUnion(v, ALL_DEPOSIT_SUB_ACCOUNT_TYPE_CODE);
|
|
4
11
|
const ALL_DEPOSIT_ACCOUNT_STATUS_TYPE = ['Closed', 'Open', 'Frozen'];
|
|
5
12
|
export const toDepositAccountStatusType = (v) => stringToUnion(v, ALL_DEPOSIT_ACCOUNT_STATUS_TYPE);
|
package/lib/esm/epic.js
CHANGED
|
@@ -147,14 +147,14 @@ import { retryJeScheduleEpic as retryExpenseAutomationJEScheduleEpic, } from './
|
|
|
147
147
|
import { bulkUploadReceiptsEpic, } from './view/expenseAutomationView/epics/missingReceipts/bulkUploadReceiptsEpic';
|
|
148
148
|
import { confirmBulkUploadMatchEpic, } from './view/expenseAutomationView/epics/missingReceipts/confirmBulkUploadMatchEpic';
|
|
149
149
|
import { fetchBulkUploadBatchDetailsEpic, } from './view/expenseAutomationView/epics/missingReceipts/fetchBulkUploadBatchDetailsEpic';
|
|
150
|
-
import { fetchMultipleBatchDetailsEpic, } from './view/expenseAutomationView/epics/missingReceipts/fetchMultipleBatchDetailsEpic';
|
|
151
|
-
import { fetchMoreBatchDetailsEpic, } from './view/expenseAutomationView/epics/missingReceipts/fetchMoreBatchDetailsEpic';
|
|
152
150
|
import { fetchBulkUploadBatchesEpic, } from './view/expenseAutomationView/epics/missingReceipts/fetchBulkUploadBatchesEpic';
|
|
153
|
-
import { fetchMissingReceiptsEpic as fetchExpenseAutomationMissingReceiptsEpic, } from './view/expenseAutomationView/epics/missingReceipts/fetchMissingReceiptsEpic';
|
|
154
151
|
import { fetchCompletedTransactionsEpic, } from './view/expenseAutomationView/epics/missingReceipts/fetchCompletedTransactionsEpic';
|
|
152
|
+
import { fetchMissingReceiptsEpic as fetchExpenseAutomationMissingReceiptsEpic, } from './view/expenseAutomationView/epics/missingReceipts/fetchMissingReceiptsEpic';
|
|
153
|
+
import { fetchMoreBatchDetailsEpic, } from './view/expenseAutomationView/epics/missingReceipts/fetchMoreBatchDetailsEpic';
|
|
154
|
+
import { fetchMultipleBatchDetailsEpic, } from './view/expenseAutomationView/epics/missingReceipts/fetchMultipleBatchDetailsEpic';
|
|
155
155
|
import { searchTransactionsForManualMatchEpic, } from './view/expenseAutomationView/epics/missingReceipts/searchTransactionsForManualMatchEpic';
|
|
156
|
-
import { bulkUploadAutomatchingTimeoutEpic, pollBulkUploadBatchStatusEpic, pusherBatchStatusCompletionEpic, } from './view/expenseAutomationView/epics/missingReceipts/watchBulkUploadBatchStatusEpic';
|
|
157
156
|
import { uploadMissingReceiptSuccessEpic, } from './view/expenseAutomationView/epics/missingReceipts/uploadMissingReceiptSuccessEpic';
|
|
157
|
+
import { bulkUploadAutomatchingTimeoutEpic, pollBulkUploadBatchStatusEpic, pusherBatchStatusCompletionEpic, } from './view/expenseAutomationView/epics/missingReceipts/watchBulkUploadBatchStatusEpic';
|
|
158
158
|
import { backgroundRefetchReviewTabEpic, } from './view/expenseAutomationView/epics/transactionCategorization/backgroundRefetchReviewTabEpic';
|
|
159
159
|
import { fetchTransactionCategorizationEpic as fetchExpenseAutomationTransactionCategorizationEpic, } from './view/expenseAutomationView/epics/transactionCategorization/fetchTransactionCategorizationEpic';
|
|
160
160
|
import { fetchTransactionCategorizationViewEpic as fetchExpenseAutomationTransactionCategorizationViewEpic, } from './view/expenseAutomationView/epics/transactionCategorization/fetchTransactionCategorizationViewEpic';
|
package/lib/esm/index.js
CHANGED
|
@@ -163,7 +163,7 @@ import { isReviewTransactionBankTransferType, isReviewTransactionBillPaymentType
|
|
|
163
163
|
import { MAX_SELECTION_LIMIT, checkIfAllLineItemsAreCategoryClassFilled, getLineItemsByTransactionIdsFromLocalData, isAnyItemWithUncategorizedExpenseAccount, } from './view/expenseAutomationView/helpers/transactionCategorizationLocalDataHelper';
|
|
164
164
|
import { clearExpenseAutomationFluxAnalysisView, fetchFluxAnalysisView, reviewFluxAnalysisView, updateFluxAnalysisViewPageMetaData, updateFluxAnalysisViewUIState, updateOperatingExpensesIdsForReview, updateSelectedSectionIdsForReview, } from './view/expenseAutomationView/reducers/fluxAnalysisViewReducer';
|
|
165
165
|
import { clearJeScheduleLocalData as clearExpenseAutomationJEScheduleLocalData, clearExpenseAutomationJESchedulesView, fetchJeSchedulesPage as fetchExpenseAutomationJESchedulesPage, ignoreRecommendedJeSchedule as ignoreExpenseAutomationJESchedule, initializeAccountSettingsView as initializeJeAccountSettingsView, initializeJeScheduleLocalData, removeJeScheduleTransactionKey, retryJeSchedule as retryExpenseAutomationJESchedule, saveAccountSettings as saveJeAccountSettings, saveAccountSettingsLocalData as saveJeAccountSettingsLocalData, updateJeScheduleLocalDataById, updateJeScheduleTransactionKeys, } from './view/expenseAutomationView/reducers/jeSchedulesViewReducer';
|
|
166
|
-
import {
|
|
166
|
+
import { acknowledgeBulkUploadConfirmMatchComplete, bulkUploadAutomatchingTimedOut, bulkUploadReceipts, bulkUploadReceiptsFailure, bulkUploadReceiptsSuccess, clearBulkUpload, clearManualSearchResults, clearMissingReceiptsTabNavigation, confirmBulkUploadMatch, confirmBulkUploadMatchFailure, confirmBulkUploadMatchSuccess, fetchBulkUploadBatchDetails, fetchBulkUploadBatchDetailsFailure, fetchBulkUploadBatchDetailsSuccess, fetchBulkUploadBatches, fetchBulkUploadBatchesFailure, fetchBulkUploadBatchesSuccess, fetchCompletedTransactions, fetchCompletedTransactionsFailure, fetchCompletedTransactionsSuccess, fetchMissingReceipts as fetchExpenseAutomationMissingReceipts, fetchMoreBatchDetails, fetchMoreBatchDetailsComplete, fetchMoreBatchDetailsFailure, markMissingReceiptAsDone as markExpenseAutomationMissingReceiptAsDone, pusherBatchStatusUpdate, requestMissingReceiptsTabNavigation, searchTransactionsForManualMatch, searchTransactionsForManualMatchFailure, searchTransactionsForManualMatchSuccess, setBulkUploadCompletedSubTab, setBulkUploadResultsTab, setBulkUploadSortConfig, storeBatchDetails, updateBulkUploadProgress, updateMissingReceiptUploadState as updateExpenseAutomationMissingReceiptUploadState, updateMissingReceiptsUIState as updateExpenseAutomationMissingReceiptsUIState, uploadMissingReceiptSuccess as uploadExpenseAutomationMissingReceiptSuccess, } from './view/expenseAutomationView/reducers/missingReceiptsViewReducer';
|
|
167
167
|
import { deleteAccountStatement, fetchReconciliation as fetchReconciliationView, saveReconciliationDetail as saveExpenseAutomationReconciliationDetail, saveReconciliationReview as saveExpenseAutomationReconciliationReview, setConnectionInProgressForAccount as setConnectionInProgressForAccountReconciliation, setStatementParseInProgress, updateAccountReconciliationLocalData as updateExpenseAutomationAccountReconciliationLocalData, updateSelectedAccountId as updateExpenseAutomationAccountReconciliationSelectedAccountId, updateSelectedTab as updateExpenseAutomationAccountReconciliationSelectedTab, updateReconListScrollPosition as updateExpenseAutomationReconListScrollPosition, updateReviewTabSortState as updateExpenseAutomationReconReviewTabListSortState, updateReviewTabLocalData as updateExpenseAutomationReconReviewTabLocalData, updateReconcileTabListScrollState as updateExpenseAutomationReconcileTabListScrollState, updateReconcileTabListSortState as updateExpenseAutomationReconcileTabListSortState, updateReconcileTabLocalData as updateExpenseAutomationReconcileTabLocalData, updateSelectedDrawerAccountId as updateExpenseAutomationSelectedDrawerAccountId, updateStatementUploadChosen, uploadAccountStatement, } from './view/expenseAutomationView/reducers/reconciliationViewReducer';
|
|
168
168
|
import { backgroundRefetchReviewTab, clearExpenseAutomationTransactionsView, fetchTransactionCategorization, fetchTransactionCategorizationFailure, fetchTransactionCategorizationView, initializeTransactionCategorizationViewLocalData, markTransactionAsNotMiscategorized, saveTransactionCategorization, saveTransactionCategorizationLocalData, setAllItemsToCategoryClassInLocalDataForCategorization, setEntityRecommendationForLineIdsForCategorization, syncTransactionCategorizationFromDetailSave, updateCurrentSelectedTransactionCategorizationTab, updateSelectedCheckboxTransactionIds, updateSelectedCustomerForTransaction, updateSelectedTransactionId, updateSelectedVendorForTransaction, updateTransactionCategorization, updateTransactionCategorizationSaveStatus, updateTransactionCategorizationUIState, updateTransactionCategorizationUploadReceiptState, uploadTransactionCategorizationReceiptSuccess, } from './view/expenseAutomationView/reducers/transactionsViewReducer';
|
|
169
169
|
import { getExpenseAutomationFluxAnalysisView } from './view/expenseAutomationView/selectors/fluxAnalysisViewSelector';
|
|
@@ -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, };
|
package/lib/esm/view/expenseAutomationView/epics/missingReceipts/fetchMoreBatchDetailsEpic.js
CHANGED
|
@@ -28,7 +28,6 @@ exhaustMap(() => {
|
|
|
28
28
|
}
|
|
29
29
|
const nextPage = unfetchedBatchIds.slice(0, MORE_BATCH_PAGE_SIZE);
|
|
30
30
|
return concat(fetchBatchDetailsByIds(nextPage, zeniAPI), of(fetchMoreBatchDetailsComplete())).pipe(catchError((error) => of(fetchMoreBatchDetailsFailure({
|
|
31
|
-
error: createZeniAPIStatus('Unexpected Error', 'Fetch more batch details errored out: ' +
|
|
32
|
-
JSON.stringify(error)),
|
|
31
|
+
error: createZeniAPIStatus('Unexpected Error', 'Fetch more batch details errored out: ' + JSON.stringify(error)),
|
|
33
32
|
}))));
|
|
34
33
|
}));
|
package/lib/esm/view/expenseAutomationView/epics/missingReceipts/fetchMultipleBatchDetailsEpic.js
CHANGED
|
@@ -25,8 +25,7 @@ export function fetchBatchDetailsByIds(batchIds, zeniAPI) {
|
|
|
25
25
|
actions.push(storeBatchDetails(toBatchDetails(response.data, zeniAPI.apiEndPoints.fileMicroServiceBaseUrl)));
|
|
26
26
|
return from(actions);
|
|
27
27
|
}), catchError((error) => {
|
|
28
|
-
console.error(`Failed to fetch batch details for ${batchId}:`, createZeniAPIStatus('Unexpected Error', 'Fetch batch details errored out: ' +
|
|
29
|
-
JSON.stringify(error)));
|
|
28
|
+
console.error(`Failed to fetch batch details for ${batchId}:`, createZeniAPIStatus('Unexpected Error', 'Fetch batch details errored out: ' + JSON.stringify(error)));
|
|
30
29
|
return of(batchDetailFetchFailed({ batchId }));
|
|
31
30
|
})), 5));
|
|
32
31
|
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { EMPTY, from, merge, of } from 'rxjs';
|
|
2
|
-
import { catchError, debounceTime, filter, mergeMap, switchMap } from 'rxjs/operators';
|
|
2
|
+
import { catchError, debounceTime, filter, mergeMap, switchMap, } from 'rxjs/operators';
|
|
3
3
|
import { convertToPeriod } from '../../../../commonStateTypes/timePeriod';
|
|
4
4
|
import { getCurrentTenant } from '../../../../entity/tenant/tenantSelector';
|
|
5
5
|
import { updateTransactions } from '../../../../entity/transaction/transactionReducer';
|
|
@@ -25,8 +25,7 @@ export const searchTransactionsForManualMatchEpic = (actions$, state$, zeniAPI)
|
|
|
25
25
|
action.payload.query.trim().length >= 2), debounceTime(300));
|
|
26
26
|
return merge(pagination$, newSearchTooShortOrClear$, newSearchDebounced$).pipe(switchMap((action) => {
|
|
27
27
|
const { query, pageToken } = action.payload;
|
|
28
|
-
if (pageToken == null &&
|
|
29
|
-
query.trim().length < 2) {
|
|
28
|
+
if (pageToken == null && query.trim().length < 2) {
|
|
30
29
|
return EMPTY;
|
|
31
30
|
}
|
|
32
31
|
const state = state$.value;
|
package/lib/esm/view/expenseAutomationView/epics/missingReceipts/watchBulkUploadBatchStatusEpic.js
CHANGED
|
@@ -29,12 +29,9 @@ export const bulkUploadAutomatchingTimeoutEpic = (actions$, state$) => actions$.
|
|
|
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;
|
|
32
|
-
if (bulk.phase !== 'matching' ||
|
|
33
|
-
bulk.currentBatchId !== batchId) {
|
|
32
|
+
if (bulk.phase !== 'matching' || bulk.currentBatchId !== batchId) {
|
|
34
33
|
return EMPTY;
|
|
35
34
|
}
|
|
36
|
-
// eslint-disable-next-line no-console
|
|
37
|
-
console.warn('[bulk-upload] Automatching wait exceeded timeout; releasing UI', { batchId });
|
|
38
35
|
return from([
|
|
39
36
|
bulkUploadAutomatchingTimedOut(batchId),
|
|
40
37
|
fetchBulkUploadBatches({ cacheOverride: true }),
|
|
@@ -323,8 +323,7 @@ const expenseAutomationMissingReceiptsView = createSlice({
|
|
|
323
323
|
* dismiss the Unmatched skeleton.
|
|
324
324
|
*/
|
|
325
325
|
const currentId = draft.bulkUpload.currentBatchId;
|
|
326
|
-
if (draft.bulkUpload.phase === 'matching' &&
|
|
327
|
-
currentId != null) {
|
|
326
|
+
if (draft.bulkUpload.phase === 'matching' && currentId != null) {
|
|
328
327
|
const existing = draft.bulkUpload.batchDetailsById[currentId];
|
|
329
328
|
if (existing?.status === 'completed') {
|
|
330
329
|
draft.bulkUpload.phase = 'completed';
|
|
@@ -345,7 +344,15 @@ const expenseAutomationMissingReceiptsView = createSlice({
|
|
|
345
344
|
};
|
|
346
345
|
},
|
|
347
346
|
prepare(batchId, attachmentId, transactionId, transactionType, fileName) {
|
|
348
|
-
return {
|
|
347
|
+
return {
|
|
348
|
+
payload: {
|
|
349
|
+
batchId,
|
|
350
|
+
attachmentId,
|
|
351
|
+
transactionId,
|
|
352
|
+
transactionType,
|
|
353
|
+
fileName,
|
|
354
|
+
},
|
|
355
|
+
};
|
|
349
356
|
},
|
|
350
357
|
},
|
|
351
358
|
confirmBulkUploadMatchSuccess(draft, action) {
|
|
@@ -492,7 +499,7 @@ const expenseAutomationMissingReceiptsView = createSlice({
|
|
|
492
499
|
},
|
|
493
500
|
},
|
|
494
501
|
fetchCompletedTransactionsSuccess(draft, action) {
|
|
495
|
-
const { transactionIds, nextPageToken, totalCount, selectedPeriod, isInitialLoad } = action.payload;
|
|
502
|
+
const { transactionIds, nextPageToken, totalCount, selectedPeriod, isInitialLoad, } = action.payload;
|
|
496
503
|
const periodId = toMonthYearPeriodId(selectedPeriod);
|
|
497
504
|
const cacheKey = getCompletedTransactionsCacheKey(periodId, draft.bulkUpload.sortKey, draft.bulkUpload.sortOrder, draft.bulkUpload.completedSubTab);
|
|
498
505
|
if (isInitialLoad) {
|
|
@@ -712,7 +712,10 @@ const expenseAutomationTransactionsView = createSlice({
|
|
|
712
712
|
uploadTransactionCategorizationReceiptSuccess: {
|
|
713
713
|
reducer(draft, action) {
|
|
714
714
|
const { transactionPayload, selectedTab } = action.payload;
|
|
715
|
-
draft.transactionCategorizationView[selectedTab].uploadReceiptStatusById[transactionPayload.transaction_id] = {
|
|
715
|
+
draft.transactionCategorizationView[selectedTab].uploadReceiptStatusById[transactionPayload.transaction_id] = {
|
|
716
|
+
fetchState: 'Completed',
|
|
717
|
+
error: undefined,
|
|
718
|
+
};
|
|
716
719
|
},
|
|
717
720
|
prepare(selectedTab, transactionPayload, updateType = 'merge') {
|
|
718
721
|
return { payload: { selectedTab, transactionPayload, updateType } };
|
|
@@ -2,9 +2,9 @@ import orderBy from 'lodash/orderBy';
|
|
|
2
2
|
import { toMonthYearPeriodId } from '../../../commonStateTypes/timePeriod';
|
|
3
3
|
import { getCurrentTenant } from '../../../entity/tenant/tenantSelector';
|
|
4
4
|
import { getSupportedTransactionById, getSupportedTransactionsByIds, } from '../../../entity/transaction/transactionSelector';
|
|
5
|
-
import { getAllSteps } from '../selectorTypes/expenseAutomationViewSelectorTypes';
|
|
6
5
|
import { isBatchListStatusCompleted } from '../payload/missingReceiptsPayload';
|
|
7
6
|
import { getCompletedTransactionsCacheKey } from '../reducers/missingReceiptsViewReducer';
|
|
7
|
+
import { getAllSteps } from '../selectorTypes/expenseAutomationViewSelectorTypes';
|
|
8
8
|
import { isUnmatchedTabFileStatus, } from '../types/missingReceiptsViewState';
|
|
9
9
|
export function getExpenseAutomationMissingReceiptsView(state) {
|
|
10
10
|
const { expenseAutomationMissingReceiptsViewState, expenseAutomationViewState, transactionState, monthEndCloseChecksState, } = state;
|
|
@@ -50,12 +50,12 @@ export function getExpenseAutomationMissingReceiptsView(state) {
|
|
|
50
50
|
const completionStatus = missingReceiptsCompletionStatus != null
|
|
51
51
|
? missingReceiptsCompletionStatus
|
|
52
52
|
: 'incomplete';
|
|
53
|
-
const { bulkUpload, pendingMissingReceiptsTabNavigation
|
|
53
|
+
const { bulkUpload, pendingMissingReceiptsTabNavigation } = expenseAutomationMissingReceiptsViewState;
|
|
54
54
|
const currentBatchStatus = bulkUpload.currentBatchId != null
|
|
55
55
|
? bulkUpload.batchStatusById[bulkUpload.currentBatchId]
|
|
56
56
|
: undefined;
|
|
57
57
|
const batchList = monthYearPeriodId != null
|
|
58
|
-
? bulkUpload.batchListByPeriod[monthYearPeriodId] ?? []
|
|
58
|
+
? (bulkUpload.batchListByPeriod[monthYearPeriodId] ?? [])
|
|
59
59
|
: [];
|
|
60
60
|
/**
|
|
61
61
|
* Primary "Unmatched" batch = first completed batch in platform list order, preferring the
|
|
@@ -104,7 +104,7 @@ export function getExpenseAutomationMissingReceiptsView(state) {
|
|
|
104
104
|
}
|
|
105
105
|
switch (bulkUpload.sortKey) {
|
|
106
106
|
case 'vendor':
|
|
107
|
-
return (matchedTransaction.vendorName ?? matchedTransaction.description)?.toLowerCase() ?? null;
|
|
107
|
+
return ((matchedTransaction.vendorName ?? matchedTransaction.description)?.toLowerCase() ?? null);
|
|
108
108
|
case 'category': {
|
|
109
109
|
const line = matchedTransaction.lines?.[0];
|
|
110
110
|
return line?.account?.accountName?.toLowerCase() ?? null;
|
|
@@ -296,9 +296,7 @@ function resolveBatchFile(file, batchId, transactionState) {
|
|
|
296
296
|
filePreviewUrl: file.filePreviewUrl,
|
|
297
297
|
status: file.status,
|
|
298
298
|
matchedTransaction,
|
|
299
|
-
candidates: candidates != null && candidates.length > 0
|
|
300
|
-
? candidates
|
|
301
|
-
: undefined,
|
|
299
|
+
candidates: candidates != null && candidates.length > 0 ? candidates : undefined,
|
|
302
300
|
matchSource: file.matchSource,
|
|
303
301
|
};
|
|
304
302
|
}
|
|
@@ -28,7 +28,12 @@ const UNMATCHED_TAB_FILE_STATUSES = ['possible_matches', 'no_match'];
|
|
|
28
28
|
export function isUnmatchedTabFileStatus(status) {
|
|
29
29
|
return UNMATCHED_TAB_FILE_STATUSES.includes(status);
|
|
30
30
|
}
|
|
31
|
-
const BULK_UPLOAD_PHASES = [
|
|
31
|
+
const BULK_UPLOAD_PHASES = [
|
|
32
|
+
'idle',
|
|
33
|
+
'uploading',
|
|
34
|
+
'matching',
|
|
35
|
+
'completed',
|
|
36
|
+
];
|
|
32
37
|
export const toBulkUploadPhase = (v) => stringToUnion(v.trim().toLowerCase(), BULK_UPLOAD_PHASES);
|
|
33
38
|
const BULK_UPLOAD_RESULTS_TABS = ['completed', 'unmatched'];
|
|
34
39
|
export const toBulkUploadResultsTab = (v) => stringToUnion(v.trim().toLowerCase(), BULK_UPLOAD_RESULTS_TABS);
|
|
@@ -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 = [
|
|
@@ -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 = profitAndLossClassesViewState.uiState.classViewLayout === 'horizontal'
|
|
65
|
+
? getProfitAndLossClassesHorizontalView(classFilter, accountState, classState, sectionsState, profitAndLossClassesViewState, thisPeriod)
|
|
66
|
+
: getProfitAndLossClassesHorizontalView(classFilter, accountState, classState, sectionsState, profitAndLossClassesViewState, 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,282 @@
|
|
|
1
|
+
import { toAmountWC } from '../../commonStateTypes/amount';
|
|
2
|
+
import { getSectionClassesViewReport } from '../../entity/sectionClassesViewV2/sectionClassesViewSelector';
|
|
3
|
+
import { ALL_PANDL_REPORT_VIEW_SECTION_IDS, } from './profitAndLossClassesViewSelectorTypes';
|
|
4
|
+
const DEFAULT_CURRENCY = { currencyCode: 'USD', currencySymbol: '$' };
|
|
5
|
+
export const profitAndLossHorizontalIdsInOrder = [
|
|
6
|
+
'income',
|
|
7
|
+
'cogs',
|
|
8
|
+
'grossProfit',
|
|
9
|
+
'expenses',
|
|
10
|
+
'earningsBeforeInterestAndTax',
|
|
11
|
+
'otherIncome',
|
|
12
|
+
'otherExpenses',
|
|
13
|
+
'netOtherIncome',
|
|
14
|
+
'netIncome',
|
|
15
|
+
];
|
|
16
|
+
const SECTION_TITLES = {
|
|
17
|
+
income: 'Income',
|
|
18
|
+
cogs: 'Cost of Goods Sold',
|
|
19
|
+
grossProfit: 'Gross Profit',
|
|
20
|
+
expenses: 'Expenses',
|
|
21
|
+
earningsBeforeInterestAndTax: 'Net Operating Income',
|
|
22
|
+
otherIncome: 'Other Income',
|
|
23
|
+
otherExpenses: 'Other Expenses',
|
|
24
|
+
netOtherIncome: 'Net Other Income',
|
|
25
|
+
netIncome: 'Net Income',
|
|
26
|
+
};
|
|
27
|
+
export const getProfitAndLossClassesHorizontalView = (filter, accountState, classState, sectionsState, profitAndLossClassesViewState, selectedPeriod) => {
|
|
28
|
+
const fetchState = reduceFetchState([
|
|
29
|
+
profitAndLossClassesViewState.fetchState.month,
|
|
30
|
+
profitAndLossClassesViewState.fetchState.quarter,
|
|
31
|
+
profitAndLossClassesViewState.fetchState.year,
|
|
32
|
+
]);
|
|
33
|
+
const reportId = 'profit_and_loss_by_classes';
|
|
34
|
+
// Build class columns from the class hierarchy (top-level only)
|
|
35
|
+
const classColumns = buildClassColumns(profitAndLossClassesViewState.classHierarchy, profitAndLossClassesViewState.uiState.classesToFilterOut);
|
|
36
|
+
const sections = {};
|
|
37
|
+
const calculatedSections = {};
|
|
38
|
+
if (fetchState.fetchState === 'Completed' && selectedPeriod != null) {
|
|
39
|
+
// Get section reports using existing selector infrastructure
|
|
40
|
+
const sectionReports = {};
|
|
41
|
+
ALL_PANDL_REPORT_VIEW_SECTION_IDS.forEach((sectionId) => {
|
|
42
|
+
sectionReports[sectionId] = getSectionClassesViewReport(accountState, classState, sectionsState, { reportId, sectionId }, filter);
|
|
43
|
+
});
|
|
44
|
+
// Pivot each section from class→account to account→class
|
|
45
|
+
const sectionIds = [
|
|
46
|
+
'income',
|
|
47
|
+
'cogs',
|
|
48
|
+
'expenses',
|
|
49
|
+
'otherIncome',
|
|
50
|
+
'otherExpenses',
|
|
51
|
+
];
|
|
52
|
+
sectionIds.forEach((sectionId) => {
|
|
53
|
+
const sectionReport = sectionReports[sectionId];
|
|
54
|
+
if (sectionReport != null) {
|
|
55
|
+
sections[sectionId] = pivotSectionToHorizontal(sectionReport, classColumns, selectedPeriod, SECTION_TITLES[sectionId] ?? sectionId);
|
|
56
|
+
}
|
|
57
|
+
});
|
|
58
|
+
// Calculate derived sections
|
|
59
|
+
const incomeSection = sections['income'];
|
|
60
|
+
const cogsSection = sections['cogs'];
|
|
61
|
+
const expensesSection = sections['expenses'];
|
|
62
|
+
const otherIncomeSection = sections['otherIncome'];
|
|
63
|
+
const otherExpensesSection = sections['otherExpenses'];
|
|
64
|
+
// Gross Profit = Income - COGS
|
|
65
|
+
if (incomeSection != null && cogsSection != null) {
|
|
66
|
+
calculatedSections['grossProfit'] = computeCalculatedSection(incomeSection.classTotals, cogsSection.classTotals, incomeSection.sectionTotal, cogsSection.sectionTotal, 'subtract', SECTION_TITLES['grossProfit']);
|
|
67
|
+
}
|
|
68
|
+
// EBIT = Gross Profit - Expenses
|
|
69
|
+
const grossProfit = calculatedSections['grossProfit'];
|
|
70
|
+
if (grossProfit != null && expensesSection != null) {
|
|
71
|
+
calculatedSections['earningsBeforeInterestAndTax'] =
|
|
72
|
+
computeCalculatedSection(grossProfit.classTotals, expensesSection.classTotals, grossProfit.sectionTotal, expensesSection.sectionTotal, 'subtract', SECTION_TITLES['earningsBeforeInterestAndTax']);
|
|
73
|
+
}
|
|
74
|
+
// Net Other Income = Other Income - Other Expenses
|
|
75
|
+
if (otherIncomeSection != null && otherExpensesSection != null) {
|
|
76
|
+
calculatedSections['netOtherIncome'] = computeCalculatedSection(otherIncomeSection.classTotals, otherExpensesSection.classTotals, otherIncomeSection.sectionTotal, otherExpensesSection.sectionTotal, 'subtract', SECTION_TITLES['netOtherIncome']);
|
|
77
|
+
}
|
|
78
|
+
// Net Income = EBIT + Net Other Income
|
|
79
|
+
const ebit = calculatedSections['earningsBeforeInterestAndTax'];
|
|
80
|
+
const netOtherIncome = calculatedSections['netOtherIncome'];
|
|
81
|
+
if (ebit != null && netOtherIncome != null) {
|
|
82
|
+
calculatedSections['netIncome'] = computeCalculatedSection(ebit.classTotals, netOtherIncome.classTotals, ebit.sectionTotal, netOtherIncome.sectionTotal, 'add', SECTION_TITLES['netIncome']);
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
// Build synthetic header COABalances for rendering class names as column headers
|
|
86
|
+
const headerBalances = buildHeaderBalances(classColumns, filter.timeframe, selectedPeriod);
|
|
87
|
+
return {
|
|
88
|
+
reportId,
|
|
89
|
+
reportTitle: 'Profit and Loss by Class',
|
|
90
|
+
firstMonthOfFY: profitAndLossClassesViewState.firstMonthOfFY,
|
|
91
|
+
fetchState: fetchState.fetchState,
|
|
92
|
+
bookCloseDate: profitAndLossClassesViewState.bookCloseDate,
|
|
93
|
+
dataAvailable: profitAndLossClassesViewState.dataAvailable,
|
|
94
|
+
selectedPeriod,
|
|
95
|
+
classColumns,
|
|
96
|
+
sections,
|
|
97
|
+
calculatedSections,
|
|
98
|
+
idsInOrder: profitAndLossHorizontalIdsInOrder,
|
|
99
|
+
uiState: profitAndLossClassesViewState.uiState,
|
|
100
|
+
headerBalances,
|
|
101
|
+
};
|
|
102
|
+
};
|
|
103
|
+
/**
|
|
104
|
+
* Build column definitions from class hierarchy (top-level classes only).
|
|
105
|
+
*/
|
|
106
|
+
function buildClassColumns(classHierarchy, classesToFilterOut) {
|
|
107
|
+
return classHierarchy
|
|
108
|
+
.filter((c) => !classesToFilterOut.some((filteredId) => filteredId[0] === c.classId[0]))
|
|
109
|
+
.map((c) => ({
|
|
110
|
+
classId: c.classId[0],
|
|
111
|
+
className: c.className,
|
|
112
|
+
nestedClassId: c.classId,
|
|
113
|
+
qboId: c.qboId,
|
|
114
|
+
}));
|
|
115
|
+
}
|
|
116
|
+
/**
|
|
117
|
+
* Pivot a section from class→account→balances to account→class→balance (single period).
|
|
118
|
+
*/
|
|
119
|
+
function pivotSectionToHorizontal(section, classColumns, selectedPeriod, title) {
|
|
120
|
+
// Map: accountId -> { accountName, classId -> balance }
|
|
121
|
+
const accountMap = new Map();
|
|
122
|
+
// Also track class totals
|
|
123
|
+
const classTotalMap = new Map();
|
|
124
|
+
classColumns.forEach((col) => classTotalMap.set(col.classId, 0));
|
|
125
|
+
// Iterate over each class in the section
|
|
126
|
+
section.classes.forEach((classReport) => {
|
|
127
|
+
const classId = classReport.id[0];
|
|
128
|
+
// Only process classes that are in our columns
|
|
129
|
+
if (!classColumns.some((col) => col.classId === classId)) {
|
|
130
|
+
return;
|
|
131
|
+
}
|
|
132
|
+
// Get the class-level balance for this period (total for the class in this section)
|
|
133
|
+
const classBalance = findBalanceForPeriod(classReport.childrenBalancesTotal.balances, selectedPeriod);
|
|
134
|
+
classTotalMap.set(classId, classBalance);
|
|
135
|
+
// Iterate through accounts in this class
|
|
136
|
+
collectAccountsFromClass(classReport, classId, selectedPeriod, accountMap);
|
|
137
|
+
});
|
|
138
|
+
// Build account rows
|
|
139
|
+
const accounts = [];
|
|
140
|
+
accountMap.forEach((accountData, accountId) => {
|
|
141
|
+
const classBalances = classColumns.map((col) => ({
|
|
142
|
+
classId: col.classId,
|
|
143
|
+
balance: toAmountWC(accountData.classBalances.get(col.classId) ?? 0, DEFAULT_CURRENCY),
|
|
144
|
+
}));
|
|
145
|
+
const rowTotal = classBalances.reduce((sum, cb) => sum + cb.balance.amount, 0);
|
|
146
|
+
accounts.push({
|
|
147
|
+
accountId,
|
|
148
|
+
accountName: accountData.accountName,
|
|
149
|
+
classBalances,
|
|
150
|
+
rowTotal: toAmountWC(rowTotal, DEFAULT_CURRENCY),
|
|
151
|
+
});
|
|
152
|
+
});
|
|
153
|
+
// Build class totals
|
|
154
|
+
const classTotals = classColumns.map((col) => ({
|
|
155
|
+
classId: col.classId,
|
|
156
|
+
balance: toAmountWC(classTotalMap.get(col.classId) ?? 0, DEFAULT_CURRENCY),
|
|
157
|
+
}));
|
|
158
|
+
const sectionTotal = classTotals.reduce((sum, ct) => sum + ct.balance.amount, 0);
|
|
159
|
+
return {
|
|
160
|
+
title,
|
|
161
|
+
accounts,
|
|
162
|
+
classTotals,
|
|
163
|
+
sectionTotal: toAmountWC(sectionTotal, DEFAULT_CURRENCY),
|
|
164
|
+
};
|
|
165
|
+
}
|
|
166
|
+
/**
|
|
167
|
+
* Recursively collect account balances from a NestedClassReportV2 into accountMap.
|
|
168
|
+
*/
|
|
169
|
+
function collectAccountsFromClass(classReport, classId, selectedPeriod, accountMap) {
|
|
170
|
+
// Process accounts directly on this class
|
|
171
|
+
classReport.class.accounts.forEach((nestedAccount) => {
|
|
172
|
+
collectAccountsFromNestedAccount(nestedAccount, classId, selectedPeriod, accountMap);
|
|
173
|
+
});
|
|
174
|
+
}
|
|
175
|
+
/**
|
|
176
|
+
* Recursively collect accounts from NestedAccountReport (handles sub-accounts).
|
|
177
|
+
*/
|
|
178
|
+
function collectAccountsFromNestedAccount(nestedAccount, classId, selectedPeriod, accountMap) {
|
|
179
|
+
const accountId = nestedAccount.account.accountId;
|
|
180
|
+
const accountName = nestedAccount.account.accountName;
|
|
181
|
+
const balance = findBalanceForPeriod(nestedAccount.account.balancesInTimeframe.balances, selectedPeriod);
|
|
182
|
+
if (!accountMap.has(accountId)) {
|
|
183
|
+
accountMap.set(accountId, {
|
|
184
|
+
accountName,
|
|
185
|
+
classBalances: new Map(),
|
|
186
|
+
});
|
|
187
|
+
}
|
|
188
|
+
const accountData = accountMap.get(accountId);
|
|
189
|
+
if (accountData == null) {
|
|
190
|
+
return;
|
|
191
|
+
}
|
|
192
|
+
const existing = accountData.classBalances.get(classId) ?? 0;
|
|
193
|
+
accountData.classBalances.set(classId, existing + balance);
|
|
194
|
+
// Process sub-accounts
|
|
195
|
+
nestedAccount.children.forEach((child) => {
|
|
196
|
+
collectAccountsFromNestedAccount(child, classId, selectedPeriod, accountMap);
|
|
197
|
+
});
|
|
198
|
+
}
|
|
199
|
+
/**
|
|
200
|
+
* Find the balance amount for a specific period from a COABalance array.
|
|
201
|
+
*/
|
|
202
|
+
function findBalanceForPeriod(balances, selectedPeriod) {
|
|
203
|
+
for (const bal of balances) {
|
|
204
|
+
const b = bal;
|
|
205
|
+
if (b.startDate != null && b.endDate != null) {
|
|
206
|
+
if (b.startDate.isSame(selectedPeriod.startDate, 'day') &&
|
|
207
|
+
b.endDate.isSame(selectedPeriod.endDate, 'day')) {
|
|
208
|
+
return b.balance?.amount ?? 0;
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
return 0;
|
|
213
|
+
}
|
|
214
|
+
/**
|
|
215
|
+
* Compute a calculated section by adding or subtracting two sets of class totals.
|
|
216
|
+
*/
|
|
217
|
+
function computeCalculatedSection(aTotals, bTotals, aTotal, bTotal, operation, title) {
|
|
218
|
+
const classTotals = aTotals.map((a) => {
|
|
219
|
+
const bMatch = bTotals.find((b) => b.classId === a.classId);
|
|
220
|
+
const bAmount = bMatch?.balance.amount ?? 0;
|
|
221
|
+
const resultAmount = operation === 'add'
|
|
222
|
+
? a.balance.amount + bAmount
|
|
223
|
+
: a.balance.amount - bAmount;
|
|
224
|
+
return {
|
|
225
|
+
classId: a.classId,
|
|
226
|
+
balance: toAmountWC(resultAmount, DEFAULT_CURRENCY),
|
|
227
|
+
};
|
|
228
|
+
});
|
|
229
|
+
const sectionTotalAmount = operation === 'add'
|
|
230
|
+
? aTotal.amount + bTotal.amount
|
|
231
|
+
: aTotal.amount - bTotal.amount;
|
|
232
|
+
return {
|
|
233
|
+
title,
|
|
234
|
+
classTotals,
|
|
235
|
+
sectionTotal: toAmountWC(sectionTotalAmount, DEFAULT_CURRENCY),
|
|
236
|
+
};
|
|
237
|
+
}
|
|
238
|
+
/**
|
|
239
|
+
* Build synthetic COABalance array for header rendering.
|
|
240
|
+
* One entry per class column + one for "Total".
|
|
241
|
+
*/
|
|
242
|
+
function buildHeaderBalances(classColumns, timeframe, selectedPeriod) {
|
|
243
|
+
if (selectedPeriod == null) {
|
|
244
|
+
return [];
|
|
245
|
+
}
|
|
246
|
+
const { endDate, startDate } = selectedPeriod;
|
|
247
|
+
const balances = classColumns.map((col) => ({
|
|
248
|
+
balance: toAmountWC(0, DEFAULT_CURRENCY),
|
|
249
|
+
balanceTimeFrame: timeframe,
|
|
250
|
+
endDate,
|
|
251
|
+
startDate,
|
|
252
|
+
type: 'default',
|
|
253
|
+
label: col.className,
|
|
254
|
+
}));
|
|
255
|
+
// Add a "Total" column
|
|
256
|
+
balances.push({
|
|
257
|
+
balance: toAmountWC(0, DEFAULT_CURRENCY),
|
|
258
|
+
balanceTimeFrame: timeframe,
|
|
259
|
+
endDate,
|
|
260
|
+
startDate,
|
|
261
|
+
type: 'default',
|
|
262
|
+
label: 'Total',
|
|
263
|
+
});
|
|
264
|
+
return balances;
|
|
265
|
+
}
|
|
266
|
+
function reduceFetchState(fetchStateList) {
|
|
267
|
+
const isAnyProgress = fetchStateList.some((s) => s.fetchState === 'In-Progress');
|
|
268
|
+
const isAllCompleted = fetchStateList.every((s) => s.fetchState === 'Completed');
|
|
269
|
+
const isAnyError = fetchStateList.some((s) => s.fetchState === 'Error');
|
|
270
|
+
const error = fetchStateList.find((s) => s.error != null)?.error;
|
|
271
|
+
let fetchState = 'Not-Started';
|
|
272
|
+
if (isAnyProgress) {
|
|
273
|
+
fetchState = 'In-Progress';
|
|
274
|
+
}
|
|
275
|
+
else if (isAllCompleted) {
|
|
276
|
+
fetchState = 'Completed';
|
|
277
|
+
}
|
|
278
|
+
else if (isAnyError) {
|
|
279
|
+
fetchState = 'Error';
|
|
280
|
+
}
|
|
281
|
+
return { fetchState, error };
|
|
282
|
+
}
|
package/lib/esm/view/profitAndLossClassesView/profitAndLossClassesByClassHorizontalSelectorTypes.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|