@zeniai/client-epic-state 4.19.90-beta1AD → 4.19.90-beta2ND
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/entity/aiCfo/aiCfoSelector.d.ts +2 -1
- package/lib/entity/reimbursement/reimbursementPayload.d.ts +2 -0
- package/lib/entity/reimbursement/reimbursementPayload.js +7 -0
- package/lib/entity/reimbursement/reimbursementState.d.ts +2 -0
- package/lib/entity/transaction/payloadTypes/transactionPayload.d.ts +0 -3
- package/lib/entity/transaction/payloadTypes/transactionPayload.js +0 -11
- package/lib/entity/transaction/stateTypes/transaction.d.ts +0 -3
- package/lib/epic.d.ts +1 -2
- package/lib/epic.js +1 -2
- package/lib/esm/entity/reimbursement/reimbursementPayload.js +7 -0
- package/lib/esm/entity/transaction/payloadTypes/transactionPayload.js +0 -11
- package/lib/esm/epic.js +1 -2
- package/lib/esm/index.js +5 -4
- package/lib/esm/view/aiCfoView/aiCfoViewReducer.js +1 -82
- package/lib/esm/view/aiCfoView/aiCfoViewSelector.js +2 -8
- package/lib/esm/view/financeStatement/financeStatementReducer.js +11 -8
- package/lib/esm/view/financeStatement/financeStatementSelector.js +13 -4
- package/lib/esm/view/profitAndLossClassesView/profitAndLossClassesByClassHorizontalSelector.js +281 -0
- package/lib/esm/view/profitAndLossClassesView/profitAndLossClassesByClassHorizontalSelectorTypes.js +1 -0
- package/lib/esm/view/profitAndLossClassesView/profitAndLossClassesViewReducer.js +5 -1
- package/lib/esm/view/spendManagement/billPay/billList/billListSelector.js +0 -10
- package/lib/esm/view/spendManagement/billPay/billList/billListState.js +0 -1
- package/lib/esm/view/spendManagement/chargeCards/chargeCardList/chargeCardList.js +0 -1
- package/lib/esm/view/spendManagement/chargeCards/chargeCardList/chargeCardListSelector.js +0 -2
- package/lib/esm/view/spendManagement/reimbursement/remiListView/remiListSelector.js +0 -12
- package/lib/esm/view/spendManagement/reimbursement/remiListView/remiListState.js +0 -1
- package/lib/esm/view/taskManager/taskDetailView/taskDetailSelector.js +2 -2
- package/lib/index.d.ts +8 -8
- package/lib/index.js +28 -31
- package/lib/tsconfig.typecheck.tsbuildinfo +1 -1
- package/lib/view/aiCfoView/aiCfoViewPayload.d.ts +0 -7
- package/lib/view/aiCfoView/aiCfoViewReducer.d.ts +1 -15
- package/lib/view/aiCfoView/aiCfoViewReducer.js +2 -83
- package/lib/view/aiCfoView/aiCfoViewSelector.d.ts +1 -4
- package/lib/view/aiCfoView/aiCfoViewSelector.js +2 -9
- package/lib/view/aiCfoView/aiCfoViewState.d.ts +1 -18
- package/lib/view/auditReportView/auditReportViewState.d.ts +1 -1
- package/lib/view/financeStatement/financeStatementReducer.js +11 -8
- package/lib/view/financeStatement/financeStatementSelector.d.ts +2 -0
- package/lib/view/financeStatement/financeStatementSelector.js +13 -4
- package/lib/view/profitAndLossClassesView/profitAndLossClassesByClassHorizontalSelector.d.ts +13 -0
- package/lib/view/profitAndLossClassesView/profitAndLossClassesByClassHorizontalSelector.js +285 -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/lib/view/spendManagement/billPay/billList/billListSelector.js +0 -10
- package/lib/view/spendManagement/billPay/billList/billListState.d.ts +1 -1
- package/lib/view/spendManagement/billPay/billList/billListState.js +0 -1
- package/lib/view/spendManagement/chargeCards/chargeCardList/chargeCardList.d.ts +1 -1
- package/lib/view/spendManagement/chargeCards/chargeCardList/chargeCardList.js +0 -1
- package/lib/view/spendManagement/chargeCards/chargeCardList/chargeCardListSelector.js +0 -2
- package/lib/view/spendManagement/reimbursement/remiListView/remiListSelector.d.ts +0 -1
- package/lib/view/spendManagement/reimbursement/remiListView/remiListSelector.js +0 -12
- package/lib/view/spendManagement/reimbursement/remiListView/remiListState.d.ts +1 -1
- package/lib/view/spendManagement/reimbursement/remiListView/remiListState.js +0 -1
- package/lib/view/taskManager/taskDetailView/taskDetailSelector.js +2 -2
- package/package.json +1 -1
- package/lib/esm/view/aiCfoView/epics/fetchSuggestedQuestionsEpic.js +0 -29
- package/lib/view/aiCfoView/epics/fetchSuggestedQuestionsEpic.d.ts +0 -8
- package/lib/view/aiCfoView/epics/fetchSuggestedQuestionsEpic.js +0 -33
|
@@ -1,19 +1,4 @@
|
|
|
1
1
|
import { createSlice } from '@reduxjs/toolkit';
|
|
2
|
-
function removeSessionIdFromPageKeyMap(draft, sessionId) {
|
|
3
|
-
const map = draft.uiState.chatSessionIdByPageKey;
|
|
4
|
-
for (const key of Object.keys(map)) {
|
|
5
|
-
if (map[key] === sessionId) {
|
|
6
|
-
delete map[key];
|
|
7
|
-
}
|
|
8
|
-
}
|
|
9
|
-
}
|
|
10
|
-
function mirrorCurrentSessionToPageKeyMapIfActive(draft) {
|
|
11
|
-
const key = draft.uiState.aiCfoSidePanelHostPageKey;
|
|
12
|
-
const sessionId = draft.uiState.currentChatSessionId;
|
|
13
|
-
if (key != null && sessionId != null) {
|
|
14
|
-
draft.uiState.chatSessionIdByPageKey[key] = sessionId;
|
|
15
|
-
}
|
|
16
|
-
}
|
|
17
2
|
export const initialAiCfoViewState = {
|
|
18
3
|
fetchState: 'Not-Started',
|
|
19
4
|
error: undefined,
|
|
@@ -21,8 +6,6 @@ export const initialAiCfoViewState = {
|
|
|
21
6
|
currentInput: '',
|
|
22
7
|
scrollPositionByChatSessionId: {},
|
|
23
8
|
currentChatSessionId: undefined,
|
|
24
|
-
aiCfoSidePanelHostPageKey: undefined,
|
|
25
|
-
chatSessionIdByPageKey: {},
|
|
26
9
|
agentId: undefined,
|
|
27
10
|
chatHistoryNextPageToken: {},
|
|
28
11
|
chatSessionsNextPageToken: { nextPageToken: null, hasMore: false },
|
|
@@ -46,7 +29,6 @@ export const initialAiCfoViewState = {
|
|
|
46
29
|
fetchChatSessionHistoryByChatSessionId: {},
|
|
47
30
|
responseStateByChatSessionId: {},
|
|
48
31
|
stopSubmitStateByChatSessionId: {},
|
|
49
|
-
suggestedQuestionsByPageContext: {},
|
|
50
32
|
};
|
|
51
33
|
const aiCfoView = createSlice({
|
|
52
34
|
name: 'aiCfoView',
|
|
@@ -180,7 +162,6 @@ const aiCfoView = createSlice({
|
|
|
180
162
|
setSession(draft, action) {
|
|
181
163
|
draft.uiState.currentChatSessionId = action.payload.sessionId;
|
|
182
164
|
draft.uiState.agentId = action.payload.agentId;
|
|
183
|
-
mirrorCurrentSessionToPageKeyMapIfActive(draft);
|
|
184
165
|
},
|
|
185
166
|
createSession: {
|
|
186
167
|
reducer(draft, action) {
|
|
@@ -204,7 +185,6 @@ const aiCfoView = createSlice({
|
|
|
204
185
|
nextPageToken: null,
|
|
205
186
|
hasMore: false,
|
|
206
187
|
};
|
|
207
|
-
mirrorCurrentSessionToPageKeyMapIfActive(draft);
|
|
208
188
|
},
|
|
209
189
|
createSessionFailure(draft, action) {
|
|
210
190
|
draft.createSessionState.fetchState = 'Error';
|
|
@@ -242,7 +222,6 @@ const aiCfoView = createSlice({
|
|
|
242
222
|
nextPageToken: null,
|
|
243
223
|
hasMore: false,
|
|
244
224
|
};
|
|
245
|
-
mirrorCurrentSessionToPageKeyMapIfActive(draft);
|
|
246
225
|
},
|
|
247
226
|
createSessionAndSubmitSuccess(draft) {
|
|
248
227
|
// Note: currentChatSessionId, agentId, and chatHistoryNextPageToken are set by initializeNewSessionState
|
|
@@ -359,7 +338,6 @@ const aiCfoView = createSlice({
|
|
|
359
338
|
draft.uiState.currentChatSessionId = undefined;
|
|
360
339
|
draft.uiState.agentId = undefined;
|
|
361
340
|
}
|
|
362
|
-
removeSessionIdFromPageKeyMap(draft, chatSessionId);
|
|
363
341
|
delete draft.uiState.chatHistoryNextPageToken[chatSessionId];
|
|
364
342
|
delete draft.uiState.scrollPositionByChatSessionId[chatSessionId];
|
|
365
343
|
delete draft.fetchChatSessionHistoryByChatSessionId[chatSessionId];
|
|
@@ -382,65 +360,6 @@ const aiCfoView = createSlice({
|
|
|
382
360
|
},
|
|
383
361
|
clearCurrentSessionId(draft) {
|
|
384
362
|
draft.uiState.currentChatSessionId = undefined;
|
|
385
|
-
const key = draft.uiState.aiCfoSidePanelHostPageKey;
|
|
386
|
-
if (key != null) {
|
|
387
|
-
delete draft.uiState.chatSessionIdByPageKey[key];
|
|
388
|
-
}
|
|
389
|
-
},
|
|
390
|
-
applyAiCfoSidePanelHostPageTransition(draft, action) {
|
|
391
|
-
const { newAiCfoSidePanelHostPageKey, nextCurrentChatSessionId } = action.payload;
|
|
392
|
-
const prevKey = draft.uiState.aiCfoSidePanelHostPageKey;
|
|
393
|
-
const curId = draft.uiState.currentChatSessionId;
|
|
394
|
-
if (prevKey != null &&
|
|
395
|
-
prevKey !== newAiCfoSidePanelHostPageKey &&
|
|
396
|
-
curId != null) {
|
|
397
|
-
draft.uiState.chatSessionIdByPageKey[prevKey] = curId;
|
|
398
|
-
}
|
|
399
|
-
draft.uiState.aiCfoSidePanelHostPageKey = newAiCfoSidePanelHostPageKey;
|
|
400
|
-
draft.uiState.currentChatSessionId =
|
|
401
|
-
nextCurrentChatSessionId != null ? nextCurrentChatSessionId : undefined;
|
|
402
|
-
draft.uiState.currentInput = '';
|
|
403
|
-
mirrorCurrentSessionToPageKeyMapIfActive(draft);
|
|
404
|
-
},
|
|
405
|
-
clearAiCfoSidePanelHostPageContext(draft) {
|
|
406
|
-
const key = draft.uiState.aiCfoSidePanelHostPageKey;
|
|
407
|
-
const curId = draft.uiState.currentChatSessionId;
|
|
408
|
-
if (key != null && curId != null) {
|
|
409
|
-
draft.uiState.chatSessionIdByPageKey[key] = curId;
|
|
410
|
-
}
|
|
411
|
-
draft.uiState.aiCfoSidePanelHostPageKey = undefined;
|
|
412
|
-
},
|
|
413
|
-
fetchSuggestedQuestions(draft, action) {
|
|
414
|
-
const { pageContext } = action.payload;
|
|
415
|
-
const prev = draft.suggestedQuestionsByPageContext[pageContext];
|
|
416
|
-
draft.suggestedQuestionsByPageContext[pageContext] = {
|
|
417
|
-
fetchState: 'In-Progress',
|
|
418
|
-
pageContext,
|
|
419
|
-
suggestedQuestions: prev?.suggestedQuestions ?? [],
|
|
420
|
-
generatedAt: prev?.generatedAt,
|
|
421
|
-
error: undefined,
|
|
422
|
-
};
|
|
423
|
-
},
|
|
424
|
-
fetchSuggestedQuestionsSuccess(draft, action) {
|
|
425
|
-
const { pageContext, generatedAt, suggestedQuestions } = action.payload;
|
|
426
|
-
draft.suggestedQuestionsByPageContext[pageContext] = {
|
|
427
|
-
fetchState: 'Completed',
|
|
428
|
-
pageContext,
|
|
429
|
-
generatedAt,
|
|
430
|
-
suggestedQuestions,
|
|
431
|
-
error: undefined,
|
|
432
|
-
};
|
|
433
|
-
},
|
|
434
|
-
fetchSuggestedQuestionsFailure(draft, action) {
|
|
435
|
-
const { pageContext, error } = action.payload;
|
|
436
|
-
const prev = draft.suggestedQuestionsByPageContext[pageContext];
|
|
437
|
-
draft.suggestedQuestionsByPageContext[pageContext] = {
|
|
438
|
-
fetchState: 'Error',
|
|
439
|
-
pageContext,
|
|
440
|
-
suggestedQuestions: prev?.suggestedQuestions ?? [],
|
|
441
|
-
generatedAt: prev?.generatedAt,
|
|
442
|
-
error,
|
|
443
|
-
};
|
|
444
363
|
},
|
|
445
364
|
clearAiCfoView(draft) {
|
|
446
365
|
Object.assign(draft, initialAiCfoViewState);
|
|
@@ -452,5 +371,5 @@ const aiCfoView = createSlice({
|
|
|
452
371
|
},
|
|
453
372
|
},
|
|
454
373
|
});
|
|
455
|
-
export const { submitQuestion, submitQuestionSuccess, submitQuestionFailure, updateResponseState, updateAiCfoViewScrollPosition, updateCurrentInput, clearInput, setSession, createSession, createSessionSuccess, createSessionFailure, createSessionAndSubmit, initializeNewSessionState, createSessionAndSubmitSuccess, createSessionAndSubmitFailure, fetchChatSessionsForUser, fetchChatSessionsForUserSuccess, fetchChatSessionsForUserFailure, fetchChatHistory, fetchChatHistorySuccess, fetchChatHistoryFailure, clearCurrentSessionId, clearLastContextMessage, stopSubmit, stopSubmitSuccess, stopSubmitFailure, stopSubmitQuestion, stopSubmitQuestionSuccess, stopSubmitQuestionFailure, acceptMasterTOS, acceptMasterTOSSuccess, acceptMasterTOSFailure, deleteChatSession, deleteChatSessionSuccess, deleteChatSessionFailure, clearDeleteChatSessionStatus, clearAiCfoView, updateCotCollapsedState,
|
|
374
|
+
export const { submitQuestion, submitQuestionSuccess, submitQuestionFailure, updateResponseState, updateAiCfoViewScrollPosition, updateCurrentInput, clearInput, setSession, createSession, createSessionSuccess, createSessionFailure, createSessionAndSubmit, initializeNewSessionState, createSessionAndSubmitSuccess, createSessionAndSubmitFailure, fetchChatSessionsForUser, fetchChatSessionsForUserSuccess, fetchChatSessionsForUserFailure, fetchChatHistory, fetchChatHistorySuccess, fetchChatHistoryFailure, clearCurrentSessionId, clearLastContextMessage, stopSubmit, stopSubmitSuccess, stopSubmitFailure, stopSubmitQuestion, stopSubmitQuestionSuccess, stopSubmitQuestionFailure, acceptMasterTOS, acceptMasterTOSSuccess, acceptMasterTOSFailure, deleteChatSession, deleteChatSessionSuccess, deleteChatSessionFailure, clearDeleteChatSessionStatus, clearAiCfoView, updateCotCollapsedState, } = aiCfoView.actions;
|
|
456
375
|
export default aiCfoView.reducer;
|
|
@@ -1,8 +1,6 @@
|
|
|
1
|
-
import { initialAiCfoState } from '../../entity/aiCfo/aiCfoReducer';
|
|
2
1
|
import { getAiCfoSelectorView, } from '../../entity/aiCfo/aiCfoSelector';
|
|
3
|
-
import { initialAiCfoViewState } from './aiCfoViewReducer';
|
|
4
2
|
export const getAiCfoView = (state) => {
|
|
5
|
-
const { fetchState, error, uiState, createSessionState, createSessionAndSubmitState, deleteChatSessionStateByChatSessionId, stopSubmitStateByChatSessionId, responseStateByChatSessionId, fetchChatSessionHistoryByChatSessionId, masterTOSAcceptanceState,
|
|
3
|
+
const { fetchState, error, uiState, createSessionState, createSessionAndSubmitState, deleteChatSessionStateByChatSessionId, stopSubmitStateByChatSessionId, responseStateByChatSessionId, fetchChatSessionHistoryByChatSessionId, masterTOSAcceptanceState, } = state.aiCfoViewState;
|
|
6
4
|
return {
|
|
7
5
|
fetchState,
|
|
8
6
|
error,
|
|
@@ -14,11 +12,7 @@ export const getAiCfoView = (state) => {
|
|
|
14
12
|
uiState,
|
|
15
13
|
fetchChatSessionHistoryByChatSessionId,
|
|
16
14
|
masterTOSAcceptanceState,
|
|
17
|
-
|
|
18
|
-
...getAiCfoSelectorView(state.aiCfoState ?? initialAiCfoState),
|
|
15
|
+
...getAiCfoSelectorView(state.aiCfoState),
|
|
19
16
|
version: 1,
|
|
20
17
|
};
|
|
21
18
|
};
|
|
22
|
-
export function getSuggestedQuestionsForPageContext(state, pageContext) {
|
|
23
|
-
return state.aiCfoViewState?.suggestedQuestionsByPageContext?.[pageContext];
|
|
24
|
-
}
|
|
@@ -44,19 +44,20 @@ const financeStatement = createSlice({
|
|
|
44
44
|
updateFinanceStatementThisPeriod(draft, action) {
|
|
45
45
|
const { firstMonthOfFY, coaBalances, maxNumOfPeriodsToHighlight } = action.payload;
|
|
46
46
|
const { timeframe, selectedCOABalancesRange } = draft;
|
|
47
|
-
|
|
48
|
-
|
|
47
|
+
const safeCoaBalances = coaBalances ?? [];
|
|
48
|
+
if (safeCoaBalances.length > 0) {
|
|
49
|
+
const prevThisPeriod = extractThisPeriod(action.payload.firstMonthOfFY, timeframe, selectedCOABalancesRange, safeCoaBalances);
|
|
49
50
|
if (prevThisPeriod != null) {
|
|
50
51
|
const selectedCoaBalancesRangeWithThisPeriod = {
|
|
51
52
|
...selectedCOABalancesRange,
|
|
52
53
|
thisPeriod: prevThisPeriod,
|
|
53
54
|
};
|
|
54
|
-
const newThisPeriod = getMatchingThisPeriod(action.payload.firstMonthOfFY, timeframe, action.payload.thisPeriod,
|
|
55
|
+
const newThisPeriod = getMatchingThisPeriod(action.payload.firstMonthOfFY, timeframe, action.payload.thisPeriod, safeCoaBalances);
|
|
55
56
|
if (newThisPeriod != null) {
|
|
56
57
|
const selectionRanges = getSelectedAndHighlightedRangesForThisPeriod({
|
|
57
58
|
firstMonthOfFY,
|
|
58
59
|
thisPeriod: newThisPeriod,
|
|
59
|
-
coaBalances,
|
|
60
|
+
coaBalances: safeCoaBalances,
|
|
60
61
|
timeframe,
|
|
61
62
|
maxNumOfPeriodsToSelect: maxNumOfPeriodsToHighlight,
|
|
62
63
|
currentSelection: {
|
|
@@ -75,7 +76,9 @@ const financeStatement = createSlice({
|
|
|
75
76
|
draft.selectedReportId = action.payload;
|
|
76
77
|
},
|
|
77
78
|
updateFinanceStatementAdditionalBalancesSelection(draft, action) {
|
|
78
|
-
const { firstMonthOfFY, additionalBalances, coaBalances, maxNumOfPeriodsToHighlight, } = action.payload;
|
|
79
|
+
const { firstMonthOfFY, additionalBalances: additionalBalancesPayload, coaBalances, maxNumOfPeriodsToHighlight, } = action.payload;
|
|
80
|
+
const safeCoaBalances = coaBalances ?? [];
|
|
81
|
+
const additionalBalances = additionalBalancesPayload ?? [];
|
|
79
82
|
let tempAdditionalBalances = [...additionalBalances];
|
|
80
83
|
if (additionalBalances.includes('this_period_vs_last_period') ||
|
|
81
84
|
additionalBalances.includes('this_period_vs_last_period_percent')) {
|
|
@@ -91,8 +94,8 @@ const financeStatement = createSlice({
|
|
|
91
94
|
draft.isAdditionalBalancesShown =
|
|
92
95
|
additionalBalances.length != 0 ? true : false;
|
|
93
96
|
const { timeframe, selectedCOABalancesRange } = draft;
|
|
94
|
-
if (
|
|
95
|
-
const thisPeriod = extractThisPeriod(action.payload.firstMonthOfFY, timeframe, selectedCOABalancesRange,
|
|
97
|
+
if (safeCoaBalances.length > 0) {
|
|
98
|
+
const thisPeriod = extractThisPeriod(action.payload.firstMonthOfFY, timeframe, selectedCOABalancesRange, safeCoaBalances);
|
|
96
99
|
if (thisPeriod != null) {
|
|
97
100
|
const selectedCoaBalancesRangeWithThisPeriod = {
|
|
98
101
|
...selectedCOABalancesRange,
|
|
@@ -101,7 +104,7 @@ const financeStatement = createSlice({
|
|
|
101
104
|
const selectionRanges = getSelectedAndHighlightedRangesForThisPeriod({
|
|
102
105
|
firstMonthOfFY,
|
|
103
106
|
thisPeriod: thisPeriod,
|
|
104
|
-
coaBalances,
|
|
107
|
+
coaBalances: safeCoaBalances,
|
|
105
108
|
timeframe,
|
|
106
109
|
maxNumOfPeriodsToHighlight: maxNumOfPeriodsToHighlight,
|
|
107
110
|
currentSelection: {
|
|
@@ -8,6 +8,7 @@ import { extractThisPeriod } from '../../commonStateTypes/viewAndReport/thisPeri
|
|
|
8
8
|
import { getBalanceSheet } from '../balanceSheet/balanceSheetSelector';
|
|
9
9
|
import { getCashFlow } from '../cashFlow/cashFlowSelector';
|
|
10
10
|
import { getProfitAndLossReport, } from '../profitAndLoss/profitAndLossSelector';
|
|
11
|
+
import { getProfitAndLossClassesHorizontalView } from '../profitAndLossClassesView/profitAndLossClassesByClassHorizontalSelector';
|
|
11
12
|
import { getProfitAndLossClassesView } from '../profitAndLossClassesView/profitAndLossClassesViewSelector';
|
|
12
13
|
function getDateRangeForFinanceReports(profitAndLossState, balanceSheetState, cashFlowState) {
|
|
13
14
|
const datesSorted = [
|
|
@@ -42,11 +43,15 @@ export const getFinanceStatement = createSelector((state) => state.accountState,
|
|
|
42
43
|
if (dataAvailable != null) {
|
|
43
44
|
const noFilter = newBalancesFilterForDateRange(firstMonthOfFY, financeStatementState.timeframe, dataAvailable, 'ascending_date', []);
|
|
44
45
|
const profitAndLossForTimeframeTicks = getProfitAndLossReport(noFilter, undefined, accountState, accountGroupState, sectionAccountsViewState, profitAndLossState, forecastState);
|
|
45
|
-
|
|
46
|
+
const expensesSection = profitAndLossForTimeframeTicks.sections.expenses;
|
|
47
|
+
const incomeSection = profitAndLossForTimeframeTicks.sections.income;
|
|
48
|
+
const expensesBalances = expensesSection?.balances;
|
|
49
|
+
const incomeBalances = incomeSection?.balances;
|
|
50
|
+
if (expensesSection != null) {
|
|
46
51
|
balancesInTimeframe =
|
|
47
|
-
|
|
48
|
-
?
|
|
49
|
-
:
|
|
52
|
+
(expensesBalances?.length ?? 0) > 0
|
|
53
|
+
? expensesBalances ?? []
|
|
54
|
+
: incomeBalances ?? [];
|
|
50
55
|
allTimeframeTicks = balancesInTimeframe.map((balance) => toTimeframeTick(balance));
|
|
51
56
|
}
|
|
52
57
|
}
|
|
@@ -60,6 +65,9 @@ export const getFinanceStatement = createSelector((state) => state.accountState,
|
|
|
60
65
|
const profitAndLossReport = getProfitAndLossReport(filter, undefined, accountState, accountGroupState, sectionAccountsViewState, profitAndLossState, forecastState);
|
|
61
66
|
const classFilter = newBalancesFilterClassesView(filter.firstMonthOfFY, filter.timeframe, filter.balancesRange.numberOfPeriods, filter.balancesRange.thisPeriod, filter.balancesRange.orderBy, filter.additionalBalances, profitAndLossClassesViewState.uiState.classesToFilterOut);
|
|
62
67
|
const profitAndLossByClassReport = getProfitAndLossClassesView(classFilter, accountState, classState, sectionsState, profitAndLossClassesViewState);
|
|
68
|
+
const profitAndLossByClassHorizontalReport = profitAndLossClassesViewState.uiState.classViewLayout === 'horizontal'
|
|
69
|
+
? getProfitAndLossClassesHorizontalView(classFilter, accountState, classState, sectionsState, profitAndLossClassesViewState, thisPeriod)
|
|
70
|
+
: getProfitAndLossClassesHorizontalView(classFilter, accountState, classState, sectionsState, profitAndLossClassesViewState, undefined);
|
|
63
71
|
const balanceSheetReport = getBalanceSheet(filter, accountState, accountGroupState, sectionAccountsViewState, balanceSheetState);
|
|
64
72
|
const cashFlowReport = getCashFlow(filter, accountState, accountGroupState, sectionAccountsViewState, cashFlowState);
|
|
65
73
|
const allReports = [
|
|
@@ -107,6 +115,7 @@ export const getFinanceStatement = createSelector((state) => state.accountState,
|
|
|
107
115
|
dataAvailable,
|
|
108
116
|
profitAndLossReport,
|
|
109
117
|
profitAndLossByClassReport,
|
|
118
|
+
profitAndLossByClassHorizontalReport,
|
|
110
119
|
balanceSheetReport,
|
|
111
120
|
cashFlowReport,
|
|
112
121
|
filter,
|
package/lib/esm/view/profitAndLossClassesView/profitAndLossClassesByClassHorizontalSelector.js
ADDED
|
@@ -0,0 +1,281 @@
|
|
|
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, 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, 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
|
+
// Sum all sliced period balances (same slice as vertical columns; multi-period = range total)
|
|
133
|
+
const classBalance = sumBalancesInSlice(classReport.childrenBalancesTotal.balances);
|
|
134
|
+
classTotalMap.set(classId, classBalance);
|
|
135
|
+
// Iterate through accounts in this class
|
|
136
|
+
collectAccountsFromClass(classReport, classId, 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, accountMap) {
|
|
170
|
+
// Process accounts directly on this class
|
|
171
|
+
classReport.class.accounts.forEach((nestedAccount) => {
|
|
172
|
+
collectAccountsFromNestedAccount(nestedAccount, classId, accountMap);
|
|
173
|
+
});
|
|
174
|
+
}
|
|
175
|
+
/**
|
|
176
|
+
* Recursively collect accounts from NestedAccountReport (handles sub-accounts).
|
|
177
|
+
*/
|
|
178
|
+
function collectAccountsFromNestedAccount(nestedAccount, classId, accountMap) {
|
|
179
|
+
const accountId = nestedAccount.account.accountId;
|
|
180
|
+
const accountName = nestedAccount.account.accountName;
|
|
181
|
+
const balance = sumBalancesInSlice(nestedAccount.account.balancesInTimeframe.balances);
|
|
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, accountMap);
|
|
197
|
+
});
|
|
198
|
+
}
|
|
199
|
+
/**
|
|
200
|
+
* Total amount for the current report slice. `balances` is already narrowed by
|
|
201
|
+
* `getCOABalances` / `sliceCOABalances` to the selected range; summing matches
|
|
202
|
+
* multi-period selections and avoids mismatches when `thisPeriod` does not
|
|
203
|
+
* align with a row (e.g. slice fallback) or when several period rows are shown.
|
|
204
|
+
*/
|
|
205
|
+
function sumBalancesInSlice(balances) {
|
|
206
|
+
let sum = 0;
|
|
207
|
+
for (const bal of balances) {
|
|
208
|
+
const b = bal;
|
|
209
|
+
sum += b.balance?.amount ?? 0;
|
|
210
|
+
}
|
|
211
|
+
return sum;
|
|
212
|
+
}
|
|
213
|
+
/**
|
|
214
|
+
* Compute a calculated section by adding or subtracting two sets of class totals.
|
|
215
|
+
*/
|
|
216
|
+
function computeCalculatedSection(aTotals, bTotals, aTotal, bTotal, operation, title) {
|
|
217
|
+
const classTotals = aTotals.map((a) => {
|
|
218
|
+
const bMatch = bTotals.find((b) => b.classId === a.classId);
|
|
219
|
+
const bAmount = bMatch?.balance.amount ?? 0;
|
|
220
|
+
const resultAmount = operation === 'add'
|
|
221
|
+
? a.balance.amount + bAmount
|
|
222
|
+
: a.balance.amount - bAmount;
|
|
223
|
+
return {
|
|
224
|
+
classId: a.classId,
|
|
225
|
+
balance: toAmountWC(resultAmount, DEFAULT_CURRENCY),
|
|
226
|
+
};
|
|
227
|
+
});
|
|
228
|
+
const sectionTotalAmount = operation === 'add'
|
|
229
|
+
? aTotal.amount + bTotal.amount
|
|
230
|
+
: aTotal.amount - bTotal.amount;
|
|
231
|
+
return {
|
|
232
|
+
title,
|
|
233
|
+
classTotals,
|
|
234
|
+
sectionTotal: toAmountWC(sectionTotalAmount, DEFAULT_CURRENCY),
|
|
235
|
+
};
|
|
236
|
+
}
|
|
237
|
+
/**
|
|
238
|
+
* Build synthetic COABalance array for header rendering.
|
|
239
|
+
* One entry per class column + one for "Total".
|
|
240
|
+
*/
|
|
241
|
+
function buildHeaderBalances(classColumns, timeframe, selectedPeriod) {
|
|
242
|
+
if (selectedPeriod == null) {
|
|
243
|
+
return [];
|
|
244
|
+
}
|
|
245
|
+
const { endDate, startDate } = selectedPeriod;
|
|
246
|
+
const balances = classColumns.map((col) => ({
|
|
247
|
+
balance: toAmountWC(0, DEFAULT_CURRENCY),
|
|
248
|
+
balanceTimeFrame: timeframe,
|
|
249
|
+
endDate,
|
|
250
|
+
startDate,
|
|
251
|
+
type: 'default',
|
|
252
|
+
label: col.className,
|
|
253
|
+
}));
|
|
254
|
+
// Add a "Total" column
|
|
255
|
+
balances.push({
|
|
256
|
+
balance: toAmountWC(0, DEFAULT_CURRENCY),
|
|
257
|
+
balanceTimeFrame: timeframe,
|
|
258
|
+
endDate,
|
|
259
|
+
startDate,
|
|
260
|
+
type: 'default',
|
|
261
|
+
label: 'Total',
|
|
262
|
+
});
|
|
263
|
+
return balances;
|
|
264
|
+
}
|
|
265
|
+
function reduceFetchState(fetchStateList) {
|
|
266
|
+
const isAnyProgress = fetchStateList.some((s) => s.fetchState === 'In-Progress');
|
|
267
|
+
const isAllCompleted = fetchStateList.every((s) => s.fetchState === 'Completed');
|
|
268
|
+
const isAnyError = fetchStateList.some((s) => s.fetchState === 'Error');
|
|
269
|
+
const error = fetchStateList.find((s) => s.error != null)?.error;
|
|
270
|
+
let fetchState = 'Not-Started';
|
|
271
|
+
if (isAnyProgress) {
|
|
272
|
+
fetchState = 'In-Progress';
|
|
273
|
+
}
|
|
274
|
+
else if (isAllCompleted) {
|
|
275
|
+
fetchState = 'Completed';
|
|
276
|
+
}
|
|
277
|
+
else if (isAnyError) {
|
|
278
|
+
fetchState = 'Error';
|
|
279
|
+
}
|
|
280
|
+
return { fetchState, error };
|
|
281
|
+
}
|
package/lib/esm/view/profitAndLossClassesView/profitAndLossClassesByClassHorizontalSelectorTypes.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -23,6 +23,7 @@ export const initialState = {
|
|
|
23
23
|
nodeCollapseState: {},
|
|
24
24
|
scrollPosition: undefined,
|
|
25
25
|
accountViewMode: 'account_group',
|
|
26
|
+
classViewLayout: 'vertical',
|
|
26
27
|
classesToFilterOut: [],
|
|
27
28
|
},
|
|
28
29
|
firstMonthOfFY: 1,
|
|
@@ -94,6 +95,9 @@ const profitAndLossClassesView = createSlice({
|
|
|
94
95
|
updateAccountViewMode(draft, action) {
|
|
95
96
|
draft.uiState.accountViewMode = action.payload.viewMode;
|
|
96
97
|
},
|
|
98
|
+
updateClassViewLayout(draft, action) {
|
|
99
|
+
draft.uiState.classViewLayout = action.payload.classViewLayout;
|
|
100
|
+
},
|
|
97
101
|
resetProfitAndLossClassesNodeCollapseState(draft) {
|
|
98
102
|
draft.uiState.nodeCollapseState = {};
|
|
99
103
|
},
|
|
@@ -102,7 +106,7 @@ const profitAndLossClassesView = createSlice({
|
|
|
102
106
|
},
|
|
103
107
|
},
|
|
104
108
|
});
|
|
105
|
-
export const { fetchProfitAndLossClassesView, fetchProfitAndLossForTimeframeClassesView, updateProfitAndLossForTimeframeClassesView, updateProfitAndLossForTimeframeClassesViewFailure, updateClassesToFilterOut, updateProfitAndLossClassesViewUIState, updateAccountViewMode, resetProfitAndLossClassesNodeCollapseState, clearProfitAndLossClassesView, } = profitAndLossClassesView.actions;
|
|
109
|
+
export const { fetchProfitAndLossClassesView, fetchProfitAndLossForTimeframeClassesView, updateProfitAndLossForTimeframeClassesView, updateProfitAndLossForTimeframeClassesViewFailure, updateClassesToFilterOut, updateProfitAndLossClassesViewUIState, updateAccountViewMode, updateClassViewLayout, resetProfitAndLossClassesNodeCollapseState, clearProfitAndLossClassesView, } = profitAndLossClassesView.actions;
|
|
106
110
|
export default profitAndLossClassesView.reducer;
|
|
107
111
|
const doUpdatedProfitAndLossClassesView = (draft, timeframe, pandLReport) => {
|
|
108
112
|
const report = mapReportPayloadV2ToReportV2(pandLReport.report);
|
|
@@ -416,14 +416,6 @@ export const getBillListOnSort = (sortKey, sortOrder, currentTab, transactions)
|
|
|
416
416
|
transactionsWithNoSortKeyValue.push(transaction);
|
|
417
417
|
}
|
|
418
418
|
break;
|
|
419
|
-
case 'invoiceNumber':
|
|
420
|
-
if (transaction.documentId != null) {
|
|
421
|
-
transactionsWithSortKeyValue.push(transaction);
|
|
422
|
-
}
|
|
423
|
-
else {
|
|
424
|
-
transactionsWithNoSortKeyValue.push(transaction);
|
|
425
|
-
}
|
|
426
|
-
break;
|
|
427
419
|
case 'dueDate':
|
|
428
420
|
if (currentTab === 'draft') {
|
|
429
421
|
if (Boolean(transaction.dueDate) === true) {
|
|
@@ -526,8 +518,6 @@ export const getBillListOnSort = (sortKey, sortOrder, currentTab, transactions)
|
|
|
526
518
|
return transaction.totalAmountInUSD?.amount ?? 0;
|
|
527
519
|
case 'paymentMethod':
|
|
528
520
|
return transaction.billPayInfo.billPaymentMethodType.name;
|
|
529
|
-
case 'invoiceNumber':
|
|
530
|
-
return transaction.documentId;
|
|
531
521
|
}
|
|
532
522
|
}, getColumnWiseSortOrder(sortOrder));
|
|
533
523
|
return [
|
|
@@ -219,8 +219,6 @@ const getCardsBySortKey = (card, sortKey) => {
|
|
|
219
219
|
return card.cardName.toLowerCase();
|
|
220
220
|
case 'cardType':
|
|
221
221
|
return card.type.code;
|
|
222
|
-
case 'accountType':
|
|
223
|
-
return card.type.code.includes('credit') ? 'credit' : 'debit';
|
|
224
222
|
case 'status':
|
|
225
223
|
return card.status.code;
|
|
226
224
|
case 'utilisation':
|