@zeniai/client-epic-state 4.20.0 → 4.20.1-beta11ND

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.
@@ -0,0 +1,9 @@
1
+ import { COABalanceTimeFrame } from '../../commonStateTypes/coaBalance/coaBalance';
2
+ import { COABalancesSlice } from '../../commonStateTypes/coaBalance/coaBalancesFilter';
3
+ import { Month } from '../../commonStateTypes/timePeriod';
4
+ /**
5
+ * Empty `COABalancesSlice` for horizontal P&L-by-class section / calculated headers when
6
+ * enrichment has not produced balances yet, or for UI mapping fallbacks.
7
+ * Structure matches {@link enrichProfitAndLossByClassHorizontalReport} output.
8
+ */
9
+ export declare function getEmptyHorizontalSectionBalancesSlice(firstMonthOfFY: Month, timeframe?: COABalanceTimeFrame): COABalancesSlice;
@@ -0,0 +1,20 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.getEmptyHorizontalSectionBalancesSlice = getEmptyHorizontalSectionBalancesSlice;
4
+ /**
5
+ * Empty `COABalancesSlice` for horizontal P&L-by-class section / calculated headers when
6
+ * enrichment has not produced balances yet, or for UI mapping fallbacks.
7
+ * Structure matches {@link enrichProfitAndLossByClassHorizontalReport} output.
8
+ */
9
+ function getEmptyHorizontalSectionBalancesSlice(firstMonthOfFY, timeframe = 'month') {
10
+ return {
11
+ balances: [],
12
+ additionalBalances: [],
13
+ filter: {
14
+ firstMonthOfFY,
15
+ timeframe,
16
+ balancesRange: { numberOfPeriods: 0, orderBy: 'ascending_date' },
17
+ additionalBalances: [],
18
+ },
19
+ };
20
+ }
@@ -52,16 +52,11 @@ const getProfitAndLossClassesHorizontalView = (filter, accountState, classState,
52
52
  const calculatedSections = {};
53
53
  let reportCurrency = currencyHelper_1.defaultCustomerCurrency;
54
54
  if (fetchState.fetchState === 'Completed' && selectedPeriod != null) {
55
- // Get section reports using existing selector infrastructure
56
- const sectionReports = {};
57
- HORIZONTAL_PANDL_SECTION_IDS.forEach((sectionId) => {
58
- sectionReports[sectionId] = (0, sectionClassesViewSelector_1.getSectionClassesViewReport)(accountState, classState, sectionsState, { reportId, sectionId }, filter);
59
- });
60
55
  reportCurrency =
61
56
  profitAndLossClassesViewState.currency ?? currencyHelper_1.defaultCustomerCurrency;
62
- // Pivot each section from class→account to account→class
57
+ // Fetch each section and pivot class→account to account→class in one pass
63
58
  HORIZONTAL_PANDL_SECTION_IDS.forEach((sectionId) => {
64
- const sectionReport = sectionReports[sectionId];
59
+ const sectionReport = (0, sectionClassesViewSelector_1.getSectionClassesViewReport)(accountState, classState, sectionsState, { reportId, sectionId }, filter);
65
60
  if (sectionReport != null) {
66
61
  sections[sectionId] = pivotSectionToHorizontal(sectionReport, classColumns, SECTION_TITLES[sectionId] ?? sectionId, reportCurrency);
67
62
  }
@@ -265,7 +260,7 @@ function sumBalancesInSlice(balances) {
265
260
  if (balances.length === 0) {
266
261
  return 0;
267
262
  }
268
- const summed = (0, getSummationBalance_1.getSummationFreeRangeTotalBalance)([...balances]);
263
+ const summed = (0, getSummationBalance_1.getSummationFreeRangeTotalBalance)(balances);
269
264
  return summed?.balance.amount ?? 0;
270
265
  }
271
266
  /**
@@ -2,6 +2,7 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.enrichProfitAndLossByClassHorizontalReport = enrichProfitAndLossByClassHorizontalReport;
4
4
  const currencyHelper_1 = require("../../commonStateTypes/currencyHelper");
5
+ const horizontalSectionEmptyBalancesSlice_1 = require("./horizontalSectionEmptyBalancesSlice");
5
6
  const profitAndLossClassesByClassHorizontalSelectorTypes_1 = require("./profitAndLossClassesByClassHorizontalSelectorTypes");
6
7
  /**
7
8
  * Populates `sectionHeaderBalancesSlice`, and per-account `accountReportData`, so the
@@ -28,30 +29,31 @@ function enrichHorizontalSection(report, section) {
28
29
  return total?.balance.amount ?? 0;
29
30
  });
30
31
  section.sectionHeaderBalancesSlice = buildHorizontalClassColumnBalancesSlice(report, classAmounts, section.sectionTotal.amount);
31
- const childrenRowIndicesByParent = buildHorizontalAccountChildIndicesByParent(section.accounts);
32
+ const parentIndices = computeHorizontalAccountParentIndices(section.accounts);
33
+ const childrenRowIndicesByParent = buildHorizontalAccountChildIndicesByParent(parentIndices);
32
34
  const childrenRecord = {};
33
35
  childrenRowIndicesByParent.forEach((childIndices, parentIndex) => {
34
36
  childrenRecord[parentIndex] = childIndices;
35
37
  });
36
38
  section.treeLayout = {
37
39
  rootAccountRowIndices: section.accounts
38
- .map((_, i) => findHorizontalAccountParentIndex(section.accounts, i) === -1 ? i : -1)
40
+ .map((_, i) => (parentIndices[i] === -1 ? i : -1))
39
41
  .filter((i) => i >= 0),
40
42
  childrenRowIndicesByParent: childrenRecord,
41
43
  };
42
- for (let i = 0; i < section.accounts.length; i++) {
43
- const row = section.accounts[i];
44
- const classRowAmounts = report.classColumns.map((col) => {
45
- const cb = row.classBalances.find((b) => b.classId === col.classId);
46
- return cb?.balance.amount ?? 0;
47
- });
44
+ const siblingsPerRow = buildSiblingIndicesPerRow(section.accounts, parentIndices);
45
+ const hasChildFlags = computeHorizontalHasChildFlags(parentIndices);
46
+ for (let accountIndex = 0; accountIndex < section.accounts.length; accountIndex++) {
47
+ const row = section.accounts[accountIndex];
48
+ // Same column order as `report.classColumns` (see `pivotSectionToHorizontal`).
49
+ const classRowAmounts = row.classBalances.map((classBalance) => classBalance.balance.amount);
48
50
  row.accountReportData = {
49
51
  accountId: row.accountId,
50
52
  accountName: row.accountName,
51
53
  accountType: row.accountType,
52
54
  depth: row.depth,
53
55
  balancesInTimeframe: buildHorizontalClassColumnBalancesSlice(report, classRowAmounts, row.rowTotal.amount),
54
- horizontalTreeView: buildHorizontalTreeView(section.accounts, i),
56
+ horizontalTreeView: buildHorizontalTreeViewFromPrecomputed(section.accounts, accountIndex, parentIndices, siblingsPerRow, hasChildFlags),
55
57
  };
56
58
  }
57
59
  }
@@ -69,23 +71,14 @@ function buildHorizontalClassColumnBalancesSlice(report, classAmounts, totalAmou
69
71
  const currencyCode = firstHeader?.balance.currencyCode ?? fallback.currencyCode;
70
72
  const currencySymbol = firstHeader?.balance.currencySymbol ?? fallback.currencySymbol;
71
73
  const timeframe = firstHeader?.balanceTimeFrame ?? 'month';
72
- const emptySlice = {
73
- balances: [],
74
- additionalBalances: [],
75
- filter: {
76
- firstMonthOfFY: report.firstMonthOfFY,
77
- timeframe,
78
- balancesRange: { numberOfPeriods: 0, orderBy: 'ascending_date' },
79
- additionalBalances: [],
80
- },
81
- };
74
+ const emptySlice = (0, horizontalSectionEmptyBalancesSlice_1.getEmptyHorizontalSectionBalancesSlice)(report.firstMonthOfFY, timeframe);
82
75
  if (report.selectedPeriod == null) {
83
76
  return emptySlice;
84
77
  }
85
78
  const { startDate, endDate } = report.selectedPeriod;
86
- const balances = report.classColumns.map((col, i) => ({
79
+ const balances = report.classColumns.map((col, columnIndex) => ({
87
80
  balance: {
88
- amount: classAmounts[i] ?? 0,
81
+ amount: classAmounts[columnIndex] ?? 0,
89
82
  currencyCode,
90
83
  currencySymbol,
91
84
  },
@@ -123,64 +116,143 @@ function buildHorizontalClassColumnBalancesSlice(report, classAmounts, totalAmou
123
116
  },
124
117
  };
125
118
  }
126
- function findHorizontalAccountParentIndex(dfsOrderedAccountRows, childRowIndex) {
127
- const childDepth = dfsOrderedAccountRows[childRowIndex].depth;
128
- if (childDepth <= 2) {
129
- return -1;
130
- }
131
- for (let earlierRowIndex = childRowIndex - 1; earlierRowIndex >= 0; earlierRowIndex--) {
132
- const earlierDepth = dfsOrderedAccountRows[earlierRowIndex].depth;
133
- if (earlierDepth < childDepth) {
134
- if (earlierDepth === childDepth - 1) {
135
- return earlierRowIndex;
119
+ /**
120
+ * Parent index per DFS row — O(n). Matches the scan in the former
121
+ * `findHorizontalAccountParentIndex` (depth &lt;= 2 rows have no parent).
122
+ */
123
+ function computeHorizontalAccountParentIndices(rows) {
124
+ const accountRowCount = rows.length;
125
+ const parentIndex = new Array(accountRowCount).fill(-1);
126
+ const stack = [];
127
+ for (let rowIndex = 0; rowIndex < accountRowCount; rowIndex++) {
128
+ const accountRow = rows[rowIndex];
129
+ if (accountRow == null) {
130
+ continue;
131
+ }
132
+ const depth = accountRow.depth;
133
+ while (stack.length > 0) {
134
+ const topRow = rows[stack[stack.length - 1]];
135
+ if (topRow == null) {
136
+ stack.pop();
137
+ continue;
138
+ }
139
+ if (topRow.depth < depth) {
140
+ break;
141
+ }
142
+ stack.pop();
143
+ }
144
+ if (depth > 2 && stack.length > 0) {
145
+ const peek = stack[stack.length - 1];
146
+ const parentRow = rows[peek];
147
+ if (parentRow != null && parentRow.depth === depth - 1) {
148
+ parentIndex[rowIndex] = peek;
136
149
  }
137
- return -1;
138
150
  }
151
+ stack.push(rowIndex);
139
152
  }
140
- return -1;
153
+ return parentIndex;
141
154
  }
142
- function getHorizontalAccountSiblingIndices(dfsOrderedAccountRows, rowIndex) {
143
- const parentRowIndex = findHorizontalAccountParentIndex(dfsOrderedAccountRows, rowIndex);
144
- const rowDepth = dfsOrderedAccountRows[rowIndex].depth;
145
- const siblings = [];
146
- for (let i = 0; i < dfsOrderedAccountRows.length; i++) {
147
- if (dfsOrderedAccountRows[i].depth === rowDepth &&
148
- findHorizontalAccountParentIndex(dfsOrderedAccountRows, i) ===
149
- parentRowIndex) {
150
- siblings.push(i);
155
+ /** Sibling row indices (same parent + depth), in traversal order — O(n). */
156
+ function buildSiblingIndicesPerRow(rows, parentIndices) {
157
+ const accountRowCount = rows.length;
158
+ const keyToIndices = new Map();
159
+ for (let rowIndex = 0; rowIndex < accountRowCount; rowIndex++) {
160
+ const parentRowIndex = parentIndices[rowIndex];
161
+ const accountRow = rows[rowIndex];
162
+ if (parentRowIndex == null || accountRow == null) {
163
+ continue;
164
+ }
165
+ const key = `${parentRowIndex}:${accountRow.depth}`;
166
+ let siblingGroup = keyToIndices.get(key);
167
+ if (siblingGroup == null) {
168
+ siblingGroup = [];
169
+ keyToIndices.set(key, siblingGroup);
170
+ }
171
+ siblingGroup.push(rowIndex);
172
+ }
173
+ const siblingsPerRow = new Array(accountRowCount);
174
+ for (let rowIndex = 0; rowIndex < accountRowCount; rowIndex++) {
175
+ const parentRowIndex = parentIndices[rowIndex];
176
+ const accountRow = rows[rowIndex];
177
+ if (parentRowIndex == null || accountRow == null) {
178
+ siblingsPerRow[rowIndex] = [rowIndex];
179
+ continue;
151
180
  }
181
+ const key = `${parentRowIndex}:${accountRow.depth}`;
182
+ const group = keyToIndices.get(key);
183
+ siblingsPerRow[rowIndex] = group != null ? group : [rowIndex];
152
184
  }
153
- return siblings;
185
+ return siblingsPerRow;
154
186
  }
155
- function horizontalAccountHasChildRows(dfsOrderedAccountRows, parentRowIndex) {
156
- return dfsOrderedAccountRows.some((_, rowIndex) => findHorizontalAccountParentIndex(dfsOrderedAccountRows, rowIndex) ===
157
- parentRowIndex);
187
+ function computeHorizontalHasChildFlags(parentIndices) {
188
+ const rowCount = parentIndices.length;
189
+ const flags = new Array(rowCount).fill(false);
190
+ for (let rowIndex = 0; rowIndex < rowCount; rowIndex++) {
191
+ const parentRowIndex = parentIndices[rowIndex];
192
+ if (parentRowIndex != null &&
193
+ parentRowIndex >= 0 &&
194
+ parentRowIndex < rowCount) {
195
+ flags[parentRowIndex] = true;
196
+ }
197
+ }
198
+ return flags;
158
199
  }
159
- function buildHorizontalSubAccountAncestorMetadata(dfsOrderedAccountRows, currentRowIndex) {
160
- const ancestorRowIndicesRootToLeaf = [];
200
+ function buildHorizontalSubAccountAncestorMetadataFromPrecomputed(dfsOrderedAccountRows, currentRowIndex, parentIndices, siblingsPerRow, hasChildFlags) {
201
+ const chain = [];
161
202
  let walkRowIndex = currentRowIndex;
162
203
  while (walkRowIndex >= 0) {
163
- ancestorRowIndicesRootToLeaf.unshift(walkRowIndex);
164
- walkRowIndex = findHorizontalAccountParentIndex(dfsOrderedAccountRows, walkRowIndex);
204
+ chain.unshift(walkRowIndex);
205
+ const parentRowIndex = parentIndices[walkRowIndex];
206
+ if (parentRowIndex == null) {
207
+ break;
208
+ }
209
+ walkRowIndex = parentRowIndex;
165
210
  }
166
- return ancestorRowIndicesRootToLeaf.map((rowIndex) => {
167
- const siblingIndices = getHorizontalAccountSiblingIndices(dfsOrderedAccountRows, rowIndex);
211
+ return chain.map((rowIndex) => {
212
+ const accountRow = dfsOrderedAccountRows[rowIndex];
213
+ const siblingIndices = siblingsPerRow[rowIndex];
214
+ const hasChild = hasChildFlags[rowIndex];
215
+ if (accountRow == null || siblingIndices == null) {
216
+ return {
217
+ depth: 0,
218
+ hasSibling: false,
219
+ hasChildren: hasChild === true,
220
+ isLastNode: true,
221
+ name: '',
222
+ };
223
+ }
168
224
  return {
169
- depth: dfsOrderedAccountRows[rowIndex].depth - 2,
225
+ depth: accountRow.depth - 2,
170
226
  hasSibling: siblingIndices.length > 1,
171
- hasChildren: horizontalAccountHasChildRows(dfsOrderedAccountRows, rowIndex),
227
+ hasChildren: hasChild === true,
172
228
  isLastNode: rowIndex === siblingIndices[siblingIndices.length - 1],
173
- name: dfsOrderedAccountRows[rowIndex].accountName,
229
+ name: accountRow.accountName,
174
230
  };
175
231
  });
176
232
  }
177
- function buildHorizontalAccountChildIndicesByParent(dfsOrderedAccountRows) {
233
+ function buildHorizontalTreeViewFromPrecomputed(dfsOrderedAccountRows, currentRowIndex, parentIndices, siblingsPerRow, hasChildFlags) {
234
+ const siblingIndices = siblingsPerRow[currentRowIndex];
235
+ const accountRow = dfsOrderedAccountRows[currentRowIndex];
236
+ const hasChildrenFlag = hasChildFlags[currentRowIndex];
237
+ const treeDepth = accountRow != null ? Math.max(0, accountRow.depth - 2) : 0;
238
+ const hasChildren = hasChildrenFlag === true;
239
+ const siblings = siblingIndices ?? [currentRowIndex];
240
+ return {
241
+ subAccountAncestorMetadata: buildHorizontalSubAccountAncestorMetadataFromPrecomputed(dfsOrderedAccountRows, currentRowIndex, parentIndices, siblingsPerRow, hasChildFlags),
242
+ treeDepth,
243
+ hasChildren,
244
+ hasSiblings: siblings.length > 1,
245
+ isLeaf: !hasChildren,
246
+ isLastNode: currentRowIndex === siblings[siblings.length - 1],
247
+ };
248
+ }
249
+ function buildHorizontalAccountChildIndicesByParent(parentIndices) {
178
250
  const childIndicesByParentRowIndex = new Map();
179
- for (let rowIndex = 0; rowIndex < dfsOrderedAccountRows.length; rowIndex++) {
180
- const parentRowIndex = findHorizontalAccountParentIndex(dfsOrderedAccountRows, rowIndex);
181
- if (parentRowIndex >= 0) {
251
+ for (let rowIndex = 0; rowIndex < parentIndices.length; rowIndex++) {
252
+ const parentRowIndex = parentIndices[rowIndex];
253
+ if (parentRowIndex != null && parentRowIndex >= 0) {
182
254
  let childRowIndices = childIndicesByParentRowIndex.get(parentRowIndex);
183
- if (childRowIndices === undefined) {
255
+ if (childRowIndices == null) {
184
256
  childRowIndices = [];
185
257
  childIndicesByParentRowIndex.set(parentRowIndex, childRowIndices);
186
258
  }
@@ -189,16 +261,3 @@ function buildHorizontalAccountChildIndicesByParent(dfsOrderedAccountRows) {
189
261
  }
190
262
  return childIndicesByParentRowIndex;
191
263
  }
192
- function buildHorizontalTreeView(dfsOrderedAccountRows, currentRowIndex) {
193
- const treeDepth = Math.max(0, dfsOrderedAccountRows[currentRowIndex].depth - 2);
194
- const siblingIndices = getHorizontalAccountSiblingIndices(dfsOrderedAccountRows, currentRowIndex);
195
- const hasChildren = horizontalAccountHasChildRows(dfsOrderedAccountRows, currentRowIndex);
196
- return {
197
- subAccountAncestorMetadata: buildHorizontalSubAccountAncestorMetadata(dfsOrderedAccountRows, currentRowIndex),
198
- treeDepth,
199
- hasChildren,
200
- hasSiblings: siblingIndices.length > 1,
201
- isLeaf: !hasChildren,
202
- isLastNode: currentRowIndex === siblingIndices[siblingIndices.length - 1],
203
- };
204
- }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zeniai/client-epic-state",
3
- "version": "4.20.0",
3
+ "version": "4.20.1-beta11ND",
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",