@zeniai/client-epic-state 4.19.87-beta0ND → 4.19.87-beta2AD

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.
Files changed (52) hide show
  1. package/lib/entity/aiCfo/aiCfoSelector.d.ts +1 -2
  2. package/lib/epic.d.ts +2 -1
  3. package/lib/epic.js +2 -1
  4. package/lib/esm/epic.js +2 -1
  5. package/lib/esm/index.js +4 -5
  6. package/lib/esm/view/aiCfoView/aiCfoViewReducer.js +83 -1
  7. package/lib/esm/view/aiCfoView/aiCfoViewSelector.js +8 -2
  8. package/lib/esm/view/aiCfoView/epics/fetchSuggestedQuestionsEpic.js +26 -0
  9. package/lib/esm/view/financeStatement/financeStatementSelector.js +0 -5
  10. package/lib/esm/view/profitAndLossClassesView/profitAndLossClassesViewReducer.js +1 -5
  11. package/lib/esm/view/spendManagement/billPay/billList/billListSelector.js +10 -0
  12. package/lib/esm/view/spendManagement/billPay/billList/billListState.js +1 -0
  13. package/lib/esm/view/spendManagement/chargeCards/chargeCardList/chargeCardList.js +1 -0
  14. package/lib/esm/view/spendManagement/chargeCards/chargeCardList/chargeCardListSelector.js +2 -0
  15. package/lib/esm/view/spendManagement/reimbursement/remiListView/remiListSelector.js +12 -0
  16. package/lib/esm/view/spendManagement/reimbursement/remiListView/remiListState.js +1 -0
  17. package/lib/esm/view/taskManager/taskDetailView/taskDetailSelector.js +2 -2
  18. package/lib/index.d.ts +8 -8
  19. package/lib/index.js +31 -28
  20. package/lib/tsconfig.typecheck.tsbuildinfo +1 -1
  21. package/lib/view/aiCfoView/aiCfoViewPayload.d.ts +11 -0
  22. package/lib/view/aiCfoView/aiCfoViewReducer.d.ts +15 -1
  23. package/lib/view/aiCfoView/aiCfoViewReducer.js +84 -2
  24. package/lib/view/aiCfoView/aiCfoViewSelector.d.ts +4 -1
  25. package/lib/view/aiCfoView/aiCfoViewSelector.js +9 -2
  26. package/lib/view/aiCfoView/aiCfoViewState.d.ts +22 -0
  27. package/lib/view/aiCfoView/epics/fetchSuggestedQuestionsEpic.d.ts +8 -0
  28. package/lib/view/aiCfoView/epics/fetchSuggestedQuestionsEpic.js +30 -0
  29. package/lib/view/auditReportView/auditReportViewState.d.ts +1 -1
  30. package/lib/view/financeStatement/financeStatementSelector.d.ts +0 -2
  31. package/lib/view/financeStatement/financeStatementSelector.js +0 -5
  32. package/lib/view/profitAndLossClassesView/profitAndLossClassesViewReducer.d.ts +2 -4
  33. package/lib/view/profitAndLossClassesView/profitAndLossClassesViewReducer.js +2 -6
  34. package/lib/view/profitAndLossClassesView/profitAndLossClassesViewState.d.ts +0 -2
  35. package/lib/view/spendManagement/billPay/billList/billListSelector.js +10 -0
  36. package/lib/view/spendManagement/billPay/billList/billListState.d.ts +1 -1
  37. package/lib/view/spendManagement/billPay/billList/billListState.js +1 -0
  38. package/lib/view/spendManagement/chargeCards/chargeCardList/chargeCardList.d.ts +1 -1
  39. package/lib/view/spendManagement/chargeCards/chargeCardList/chargeCardList.js +1 -0
  40. package/lib/view/spendManagement/chargeCards/chargeCardList/chargeCardListSelector.js +2 -0
  41. package/lib/view/spendManagement/reimbursement/remiListView/remiListSelector.d.ts +1 -0
  42. package/lib/view/spendManagement/reimbursement/remiListView/remiListSelector.js +12 -0
  43. package/lib/view/spendManagement/reimbursement/remiListView/remiListState.d.ts +1 -1
  44. package/lib/view/spendManagement/reimbursement/remiListView/remiListState.js +1 -0
  45. package/lib/view/taskManager/taskDetailView/taskDetailSelector.js +2 -2
  46. package/package.json +1 -1
  47. package/lib/esm/view/profitAndLossClassesView/profitAndLossClassesByClassHorizontalSelector.js +0 -282
  48. package/lib/esm/view/profitAndLossClassesView/profitAndLossClassesByClassHorizontalSelectorTypes.js +0 -1
  49. package/lib/view/profitAndLossClassesView/profitAndLossClassesByClassHorizontalSelector.d.ts +0 -13
  50. package/lib/view/profitAndLossClassesView/profitAndLossClassesByClassHorizontalSelector.js +0 -286
  51. package/lib/view/profitAndLossClassesView/profitAndLossClassesByClassHorizontalSelectorTypes.d.ts +0 -56
  52. package/lib/view/profitAndLossClassesView/profitAndLossClassesByClassHorizontalSelectorTypes.js +0 -2
@@ -98,11 +98,11 @@ exports.allTaskStatus = [
98
98
  },
99
99
  {
100
100
  code: 'done',
101
- name: 'Done',
101
+ name: 'In Review',
102
102
  },
103
103
  {
104
104
  code: 'resolved',
105
- name: 'Resolved',
105
+ name: 'Complete',
106
106
  },
107
107
  ];
108
108
  exports.allTaskPriority = [
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zeniai/client-epic-state",
3
- "version": "4.19.87-beta0ND",
3
+ "version": "4.19.87-beta2AD",
4
4
  "description": "Shared module between Web & Mobile containing required abstractions for state management, async network communication. ",
5
5
  "main": "lib/index.js",
6
6
  "module": "lib/esm/index.js",
@@ -1,282 +0,0 @@
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
- }
@@ -1,13 +0,0 @@
1
- import { COABalancesFilterClassesView } from '../../commonStateTypes/coaBalance/coaBalancesFilterClassesView';
2
- import { AccountState } from '../../entity/account/accountState';
3
- import { ClassState } from '../../entity/class/classState';
4
- import { SectionClassesViewStateV2 } from '../../entity/sectionClassesViewV2/sectionClassesViewState';
5
- import { ZeniDate } from '../../zeniDayJS';
6
- import { ProfitAndLossByClassHorizontalReport } from './profitAndLossClassesByClassHorizontalSelectorTypes';
7
- import { PandLReportViewCalculatedSectionID, PandLReportViewSectionID } from './profitAndLossClassesViewSelectorTypes';
8
- import { ProfitAndLossClassesViewState } from './profitAndLossClassesViewState';
9
- export declare const profitAndLossHorizontalIdsInOrder: (PandLReportViewSectionID | PandLReportViewCalculatedSectionID)[];
10
- export declare const getProfitAndLossClassesHorizontalView: (filter: COABalancesFilterClassesView, accountState: AccountState, classState: ClassState, sectionsState: SectionClassesViewStateV2, profitAndLossClassesViewState: ProfitAndLossClassesViewState, selectedPeriod: {
11
- endDate: ZeniDate;
12
- startDate: ZeniDate;
13
- } | undefined) => ProfitAndLossByClassHorizontalReport;
@@ -1,286 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.getProfitAndLossClassesHorizontalView = exports.profitAndLossHorizontalIdsInOrder = void 0;
4
- const amount_1 = require("../../commonStateTypes/amount");
5
- const sectionClassesViewSelector_1 = require("../../entity/sectionClassesViewV2/sectionClassesViewSelector");
6
- const profitAndLossClassesViewSelectorTypes_1 = require("./profitAndLossClassesViewSelectorTypes");
7
- const DEFAULT_CURRENCY = { currencyCode: 'USD', currencySymbol: '$' };
8
- exports.profitAndLossHorizontalIdsInOrder = [
9
- 'income',
10
- 'cogs',
11
- 'grossProfit',
12
- 'expenses',
13
- 'earningsBeforeInterestAndTax',
14
- 'otherIncome',
15
- 'otherExpenses',
16
- 'netOtherIncome',
17
- 'netIncome',
18
- ];
19
- const SECTION_TITLES = {
20
- income: 'Income',
21
- cogs: 'Cost of Goods Sold',
22
- grossProfit: 'Gross Profit',
23
- expenses: 'Expenses',
24
- earningsBeforeInterestAndTax: 'Net Operating Income',
25
- otherIncome: 'Other Income',
26
- otherExpenses: 'Other Expenses',
27
- netOtherIncome: 'Net Other Income',
28
- netIncome: 'Net Income',
29
- };
30
- const getProfitAndLossClassesHorizontalView = (filter, accountState, classState, sectionsState, profitAndLossClassesViewState, selectedPeriod) => {
31
- const fetchState = reduceFetchState([
32
- profitAndLossClassesViewState.fetchState.month,
33
- profitAndLossClassesViewState.fetchState.quarter,
34
- profitAndLossClassesViewState.fetchState.year,
35
- ]);
36
- const reportId = 'profit_and_loss_by_classes';
37
- // Build class columns from the class hierarchy (top-level only)
38
- const classColumns = buildClassColumns(profitAndLossClassesViewState.classHierarchy, profitAndLossClassesViewState.uiState.classesToFilterOut);
39
- const sections = {};
40
- const calculatedSections = {};
41
- if (fetchState.fetchState === 'Completed' && selectedPeriod != null) {
42
- // Get section reports using existing selector infrastructure
43
- const sectionReports = {};
44
- profitAndLossClassesViewSelectorTypes_1.ALL_PANDL_REPORT_VIEW_SECTION_IDS.forEach((sectionId) => {
45
- sectionReports[sectionId] = (0, sectionClassesViewSelector_1.getSectionClassesViewReport)(accountState, classState, sectionsState, { reportId, sectionId }, filter);
46
- });
47
- // Pivot each section from class→account to account→class
48
- const sectionIds = [
49
- 'income',
50
- 'cogs',
51
- 'expenses',
52
- 'otherIncome',
53
- 'otherExpenses',
54
- ];
55
- sectionIds.forEach((sectionId) => {
56
- const sectionReport = sectionReports[sectionId];
57
- if (sectionReport != null) {
58
- sections[sectionId] = pivotSectionToHorizontal(sectionReport, classColumns, selectedPeriod, SECTION_TITLES[sectionId] ?? sectionId);
59
- }
60
- });
61
- // Calculate derived sections
62
- const incomeSection = sections['income'];
63
- const cogsSection = sections['cogs'];
64
- const expensesSection = sections['expenses'];
65
- const otherIncomeSection = sections['otherIncome'];
66
- const otherExpensesSection = sections['otherExpenses'];
67
- // Gross Profit = Income - COGS
68
- if (incomeSection != null && cogsSection != null) {
69
- calculatedSections['grossProfit'] = computeCalculatedSection(incomeSection.classTotals, cogsSection.classTotals, incomeSection.sectionTotal, cogsSection.sectionTotal, 'subtract', SECTION_TITLES['grossProfit']);
70
- }
71
- // EBIT = Gross Profit - Expenses
72
- const grossProfit = calculatedSections['grossProfit'];
73
- if (grossProfit != null && expensesSection != null) {
74
- calculatedSections['earningsBeforeInterestAndTax'] =
75
- computeCalculatedSection(grossProfit.classTotals, expensesSection.classTotals, grossProfit.sectionTotal, expensesSection.sectionTotal, 'subtract', SECTION_TITLES['earningsBeforeInterestAndTax']);
76
- }
77
- // Net Other Income = Other Income - Other Expenses
78
- if (otherIncomeSection != null && otherExpensesSection != null) {
79
- calculatedSections['netOtherIncome'] = computeCalculatedSection(otherIncomeSection.classTotals, otherExpensesSection.classTotals, otherIncomeSection.sectionTotal, otherExpensesSection.sectionTotal, 'subtract', SECTION_TITLES['netOtherIncome']);
80
- }
81
- // Net Income = EBIT + Net Other Income
82
- const ebit = calculatedSections['earningsBeforeInterestAndTax'];
83
- const netOtherIncome = calculatedSections['netOtherIncome'];
84
- if (ebit != null && netOtherIncome != null) {
85
- calculatedSections['netIncome'] = computeCalculatedSection(ebit.classTotals, netOtherIncome.classTotals, ebit.sectionTotal, netOtherIncome.sectionTotal, 'add', SECTION_TITLES['netIncome']);
86
- }
87
- }
88
- // Build synthetic header COABalances for rendering class names as column headers
89
- const headerBalances = buildHeaderBalances(classColumns, filter.timeframe, selectedPeriod);
90
- return {
91
- reportId,
92
- reportTitle: 'Profit and Loss by Class',
93
- firstMonthOfFY: profitAndLossClassesViewState.firstMonthOfFY,
94
- fetchState: fetchState.fetchState,
95
- bookCloseDate: profitAndLossClassesViewState.bookCloseDate,
96
- dataAvailable: profitAndLossClassesViewState.dataAvailable,
97
- selectedPeriod,
98
- classColumns,
99
- sections,
100
- calculatedSections,
101
- idsInOrder: exports.profitAndLossHorizontalIdsInOrder,
102
- uiState: profitAndLossClassesViewState.uiState,
103
- headerBalances,
104
- };
105
- };
106
- exports.getProfitAndLossClassesHorizontalView = getProfitAndLossClassesHorizontalView;
107
- /**
108
- * Build column definitions from class hierarchy (top-level classes only).
109
- */
110
- function buildClassColumns(classHierarchy, classesToFilterOut) {
111
- return classHierarchy
112
- .filter((c) => !classesToFilterOut.some((filteredId) => filteredId[0] === c.classId[0]))
113
- .map((c) => ({
114
- classId: c.classId[0],
115
- className: c.className,
116
- nestedClassId: c.classId,
117
- qboId: c.qboId,
118
- }));
119
- }
120
- /**
121
- * Pivot a section from class→account→balances to account→class→balance (single period).
122
- */
123
- function pivotSectionToHorizontal(section, classColumns, selectedPeriod, title) {
124
- // Map: accountId -> { accountName, classId -> balance }
125
- const accountMap = new Map();
126
- // Also track class totals
127
- const classTotalMap = new Map();
128
- classColumns.forEach((col) => classTotalMap.set(col.classId, 0));
129
- // Iterate over each class in the section
130
- section.classes.forEach((classReport) => {
131
- const classId = classReport.id[0];
132
- // Only process classes that are in our columns
133
- if (!classColumns.some((col) => col.classId === classId)) {
134
- return;
135
- }
136
- // Get the class-level balance for this period (total for the class in this section)
137
- const classBalance = findBalanceForPeriod(classReport.childrenBalancesTotal.balances, selectedPeriod);
138
- classTotalMap.set(classId, classBalance);
139
- // Iterate through accounts in this class
140
- collectAccountsFromClass(classReport, classId, selectedPeriod, accountMap);
141
- });
142
- // Build account rows
143
- const accounts = [];
144
- accountMap.forEach((accountData, accountId) => {
145
- const classBalances = classColumns.map((col) => ({
146
- classId: col.classId,
147
- balance: (0, amount_1.toAmountWC)(accountData.classBalances.get(col.classId) ?? 0, DEFAULT_CURRENCY),
148
- }));
149
- const rowTotal = classBalances.reduce((sum, cb) => sum + cb.balance.amount, 0);
150
- accounts.push({
151
- accountId,
152
- accountName: accountData.accountName,
153
- classBalances,
154
- rowTotal: (0, amount_1.toAmountWC)(rowTotal, DEFAULT_CURRENCY),
155
- });
156
- });
157
- // Build class totals
158
- const classTotals = classColumns.map((col) => ({
159
- classId: col.classId,
160
- balance: (0, amount_1.toAmountWC)(classTotalMap.get(col.classId) ?? 0, DEFAULT_CURRENCY),
161
- }));
162
- const sectionTotal = classTotals.reduce((sum, ct) => sum + ct.balance.amount, 0);
163
- return {
164
- title,
165
- accounts,
166
- classTotals,
167
- sectionTotal: (0, amount_1.toAmountWC)(sectionTotal, DEFAULT_CURRENCY),
168
- };
169
- }
170
- /**
171
- * Recursively collect account balances from a NestedClassReportV2 into accountMap.
172
- */
173
- function collectAccountsFromClass(classReport, classId, selectedPeriod, accountMap) {
174
- // Process accounts directly on this class
175
- classReport.class.accounts.forEach((nestedAccount) => {
176
- collectAccountsFromNestedAccount(nestedAccount, classId, selectedPeriod, accountMap);
177
- });
178
- }
179
- /**
180
- * Recursively collect accounts from NestedAccountReport (handles sub-accounts).
181
- */
182
- function collectAccountsFromNestedAccount(nestedAccount, classId, selectedPeriod, accountMap) {
183
- const accountId = nestedAccount.account.accountId;
184
- const accountName = nestedAccount.account.accountName;
185
- const balance = findBalanceForPeriod(nestedAccount.account.balancesInTimeframe.balances, selectedPeriod);
186
- if (!accountMap.has(accountId)) {
187
- accountMap.set(accountId, {
188
- accountName,
189
- classBalances: new Map(),
190
- });
191
- }
192
- const accountData = accountMap.get(accountId);
193
- if (accountData == null) {
194
- return;
195
- }
196
- const existing = accountData.classBalances.get(classId) ?? 0;
197
- accountData.classBalances.set(classId, existing + balance);
198
- // Process sub-accounts
199
- nestedAccount.children.forEach((child) => {
200
- collectAccountsFromNestedAccount(child, classId, selectedPeriod, accountMap);
201
- });
202
- }
203
- /**
204
- * Find the balance amount for a specific period from a COABalance array.
205
- */
206
- function findBalanceForPeriod(balances, selectedPeriod) {
207
- for (const bal of balances) {
208
- const b = bal;
209
- if (b.startDate != null && b.endDate != null) {
210
- if (b.startDate.isSame(selectedPeriod.startDate, 'day') &&
211
- b.endDate.isSame(selectedPeriod.endDate, 'day')) {
212
- return b.balance?.amount ?? 0;
213
- }
214
- }
215
- }
216
- return 0;
217
- }
218
- /**
219
- * Compute a calculated section by adding or subtracting two sets of class totals.
220
- */
221
- function computeCalculatedSection(aTotals, bTotals, aTotal, bTotal, operation, title) {
222
- const classTotals = aTotals.map((a) => {
223
- const bMatch = bTotals.find((b) => b.classId === a.classId);
224
- const bAmount = bMatch?.balance.amount ?? 0;
225
- const resultAmount = operation === 'add'
226
- ? a.balance.amount + bAmount
227
- : a.balance.amount - bAmount;
228
- return {
229
- classId: a.classId,
230
- balance: (0, amount_1.toAmountWC)(resultAmount, DEFAULT_CURRENCY),
231
- };
232
- });
233
- const sectionTotalAmount = operation === 'add'
234
- ? aTotal.amount + bTotal.amount
235
- : aTotal.amount - bTotal.amount;
236
- return {
237
- title,
238
- classTotals,
239
- sectionTotal: (0, amount_1.toAmountWC)(sectionTotalAmount, DEFAULT_CURRENCY),
240
- };
241
- }
242
- /**
243
- * Build synthetic COABalance array for header rendering.
244
- * One entry per class column + one for "Total".
245
- */
246
- function buildHeaderBalances(classColumns, timeframe, selectedPeriod) {
247
- if (selectedPeriod == null) {
248
- return [];
249
- }
250
- const { endDate, startDate } = selectedPeriod;
251
- const balances = classColumns.map((col) => ({
252
- balance: (0, amount_1.toAmountWC)(0, DEFAULT_CURRENCY),
253
- balanceTimeFrame: timeframe,
254
- endDate,
255
- startDate,
256
- type: 'default',
257
- label: col.className,
258
- }));
259
- // Add a "Total" column
260
- balances.push({
261
- balance: (0, amount_1.toAmountWC)(0, DEFAULT_CURRENCY),
262
- balanceTimeFrame: timeframe,
263
- endDate,
264
- startDate,
265
- type: 'default',
266
- label: 'Total',
267
- });
268
- return balances;
269
- }
270
- function reduceFetchState(fetchStateList) {
271
- const isAnyProgress = fetchStateList.some((s) => s.fetchState === 'In-Progress');
272
- const isAllCompleted = fetchStateList.every((s) => s.fetchState === 'Completed');
273
- const isAnyError = fetchStateList.some((s) => s.fetchState === 'Error');
274
- const error = fetchStateList.find((s) => s.error != null)?.error;
275
- let fetchState = 'Not-Started';
276
- if (isAnyProgress) {
277
- fetchState = 'In-Progress';
278
- }
279
- else if (isAllCompleted) {
280
- fetchState = 'Completed';
281
- }
282
- else if (isAnyError) {
283
- fetchState = 'Error';
284
- }
285
- return { fetchState, error };
286
- }
@@ -1,56 +0,0 @@
1
- import { Amount } from '../../commonStateTypes/amount';
2
- import { NestedClassID } from '../../commonStateTypes/classesView/nestedClassID';
3
- import { COABalance } from '../../commonStateTypes/coaBalance/coaBalance';
4
- import { FetchState, ID } from '../../commonStateTypes/common';
5
- import { DataAvailable } from '../../commonStateTypes/dataAvailable';
6
- import { Month } from '../../commonStateTypes/timePeriod';
7
- import { ZeniDate } from '../../zeniDayJS';
8
- import { PandLReportViewCalculatedSectionID, PandLReportViewSectionID } from './profitAndLossClassesViewSelectorTypes';
9
- import { ProfitAndLossClassesViewUIState } from './profitAndLossClassesViewState';
10
- export interface ClassColumnDefinition {
11
- classId: string;
12
- className: string;
13
- nestedClassId: NestedClassID;
14
- qboId?: ID;
15
- }
16
- export interface HorizontalClassBalance {
17
- balance: Amount;
18
- classId: string;
19
- }
20
- export interface HorizontalAccountRow {
21
- accountId: string;
22
- accountName: string;
23
- classBalances: HorizontalClassBalance[];
24
- rowTotal: Amount;
25
- }
26
- export interface HorizontalSectionReport {
27
- accounts: HorizontalAccountRow[];
28
- classTotals: HorizontalClassBalance[];
29
- sectionTotal: Amount;
30
- title: string;
31
- }
32
- export interface HorizontalCalculatedSection {
33
- classTotals: HorizontalClassBalance[];
34
- sectionTotal: Amount;
35
- title: string;
36
- }
37
- export interface ProfitAndLossByClassHorizontalReport {
38
- calculatedSections: Partial<Record<PandLReportViewCalculatedSectionID, HorizontalCalculatedSection>>;
39
- classColumns: ClassColumnDefinition[];
40
- fetchState: FetchState;
41
- firstMonthOfFY: Month;
42
- /** Synthetic COABalance array for header rendering — one per class column + total */
43
- headerBalances: COABalance[];
44
- idsInOrder: (PandLReportViewSectionID | PandLReportViewCalculatedSectionID)[];
45
- reportId: string;
46
- reportTitle: string;
47
- sections: Partial<Record<PandLReportViewSectionID, HorizontalSectionReport>>;
48
- selectedPeriod: {
49
- endDate: ZeniDate;
50
- startDate: ZeniDate;
51
- label?: string;
52
- } | undefined;
53
- uiState: ProfitAndLossClassesViewUIState;
54
- bookCloseDate?: ZeniDate;
55
- dataAvailable?: DataAvailable;
56
- }
@@ -1,2 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });