bkper-js 2.28.0 → 2.29.0

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/CHANGELOG.md CHANGED
@@ -5,9 +5,29 @@ See what's new and what has changed in bkper-js
5
5
  ## 2026
6
6
 
7
7
  **February 2026**
8
+
8
9
  - Added `User.getGivenName`
10
+ - Added `BooksDataTableBuilder`
11
+ - Added `AccountsDataTableBuilder`
12
+ - Added `GroupsDataTableBuilder`
13
+ - Added `TransactionsDataTableBuilder`
14
+ - Added `Book.createAccountsDataTable`
15
+ - Added `Book.createGroupsDataTable`
16
+ - Added `Book.createTransactionsDataTable`
17
+ - Added `TransactionsDataTableBuilder.ids`
18
+ - Added `TransactionsDataTableBuilder.properties`
19
+ - Added `TransactionsDataTableBuilder.urls`
20
+ - Added `TransactionsDataTableBuilder.recordedAt`
21
+ - Added `AccountsDataTableBuilder.hiddenProperties`
22
+ - Added `BooksDataTableBuilder.hiddenProperties`
23
+ - Added `GroupsDataTableBuilder.hiddenProperties`
24
+ - Added `GroupsDataTableBuilder.tree`
25
+ - Added `TransactionsDataTableBuilder.hiddenProperties`
26
+ - Added `BalancesDataTableBuilder.hiddenProperties`
27
+
9
28
 
10
29
  **January 2026**
30
+
11
31
  - Added `App.setUsers`
12
32
  - Added `App.getUsers`
13
33
  - Added `App.setDevelopers`
@@ -41,16 +61,18 @@ See what's new and what has changed in bkper-js
41
61
  ## 2025
42
62
 
43
63
  **December 2025**
64
+
44
65
  - Added `File.update`
45
66
  - Added `EventType.FILE_UPDATED`
46
67
 
47
68
  **November 2025**
69
+
48
70
  - **v2.15.2 - INTERNAL REFACTOR:**
49
- - Introduced `ResourceProperty` abstract class for model entities that support custom properties
50
- - Moved shared property methods to ResourceProperty
51
- - Refactor 7 model classes to extend ResourceProperty instead of Resource
52
- - Eliminate ~350 lines of duplicated property management code
53
- - Maintained full backward compatibility - no breaking changes to existing APIs
71
+ - Introduced `ResourceProperty` abstract class for model entities that support custom properties
72
+ - Moved shared property methods to ResourceProperty
73
+ - Refactor 7 model classes to extend ResourceProperty instead of Resource
74
+ - Eliminate ~350 lines of duplicated property management code
75
+ - Maintained full backward compatibility - no breaking changes to existing APIs
54
76
  - Added `ResourceProperty.setVisibleProperty`
55
77
  - Added `ResourceProperty.setVisibleProperties`
56
78
  - Added `ResourceProperty.getVisibleProperties`
@@ -66,11 +88,11 @@ See what's new and what has changed in bkper-js
66
88
  **September 2025**
67
89
 
68
90
  - **v2.8.0 - INTERNAL REFACTOR:**
69
- - Introduced abstract `Resource` class for all model entities
70
- - Improved config management with `getConfig()` pattern for config resolution
71
- - Enhanced type safety with explicit Config type usage throughout
72
- - Standardized `json()` method across resources for consistent JSON serialization
73
- - Maintained full backward compatibility - no breaking changes to existing APIs
91
+ - Introduced abstract `Resource` class for all model entities
92
+ - Improved config management with `getConfig()` pattern for config resolution
93
+ - Enhanced type safety with explicit Config type usage throughout
94
+ - Standardized `json()` method across resources for consistent JSON serialization
95
+ - Maintained full backward compatibility - no breaking changes to existing APIs
74
96
  - Added `Account.isBalanceVerified`
75
97
  - Added `App.getOwnerWebsiteUrl`
76
98
  - Added `App.getReadme`
@@ -0,0 +1,247 @@
1
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
2
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
3
+ return new (P || (P = Promise))(function (resolve, reject) {
4
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
5
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
6
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
7
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
8
+ });
9
+ };
10
+ import { AccountType } from '../model/Enums.js';
11
+ import { convertInMatrix } from '../utils.js';
12
+ /**
13
+ * A AccountsDataTableBuilder is used to setup and build two-dimensional arrays containing accounts.
14
+ *
15
+ * @public
16
+ */
17
+ export class AccountsDataTableBuilder {
18
+ constructor(accounts) {
19
+ this.accounts = accounts;
20
+ this.shouldIncludeArchived = false;
21
+ this.shouldAddGroups = false;
22
+ this.shouldAddProperties = false;
23
+ this.shouldAddIds = false;
24
+ this.shouldAddHiddenProperties = false;
25
+ this.propertyKeys = [];
26
+ }
27
+ /**
28
+ * Defines whether the archived accounts should be included.
29
+ *
30
+ * @param include - Whether to include archived accounts
31
+ *
32
+ * @returns This builder with respective include archived option, for chaining.
33
+ */
34
+ archived(include) {
35
+ this.shouldIncludeArchived = include;
36
+ return this;
37
+ }
38
+ /**
39
+ * Defines whether include account groups.
40
+ *
41
+ * @param include - Whether to include groups
42
+ *
43
+ * @returns This builder with respective include groups option, for chaining.
44
+ */
45
+ groups(include) {
46
+ this.shouldAddGroups = include;
47
+ return this;
48
+ }
49
+ /**
50
+ * Defines whether include custom account properties.
51
+ *
52
+ * @param include - Whether to include properties
53
+ *
54
+ * @returns This builder with respective include properties option, for chaining.
55
+ */
56
+ properties(include) {
57
+ this.shouldAddProperties = include;
58
+ return this;
59
+ }
60
+ /**
61
+ * Defines whether include account ids.
62
+ *
63
+ * @param include - Whether to include ids
64
+ *
65
+ * @returns This builder with respective include ids option, for chaining.
66
+ */
67
+ ids(include) {
68
+ this.shouldAddIds = include;
69
+ return this;
70
+ }
71
+ /**
72
+ * Defines whether to include hidden properties (keys ending with underscore "_").
73
+ * Only relevant when {@link properties} is enabled.
74
+ * Default is false — hidden properties are excluded.
75
+ *
76
+ * @param include - Whether to include hidden properties
77
+ *
78
+ * @returns This builder with respective option, for chaining.
79
+ */
80
+ hiddenProperties(include) {
81
+ this.shouldAddHiddenProperties = include;
82
+ return this;
83
+ }
84
+ getPropertyKeys() {
85
+ if (this.propertyKeys.length === 0) {
86
+ for (const account of this.accounts) {
87
+ for (const key of account.getPropertyKeys()) {
88
+ if (!this.shouldAddHiddenProperties && key.endsWith('_')) {
89
+ continue;
90
+ }
91
+ if (this.propertyKeys.indexOf(key) <= -1) {
92
+ this.propertyKeys.push(key);
93
+ }
94
+ }
95
+ }
96
+ this.propertyKeys = this.propertyKeys.sort();
97
+ }
98
+ return this.propertyKeys;
99
+ }
100
+ getTypeIndex(type) {
101
+ if (type === AccountType.ASSET) {
102
+ return 0;
103
+ }
104
+ if (type === AccountType.LIABILITY) {
105
+ return 1;
106
+ }
107
+ if (type === AccountType.INCOMING) {
108
+ return 2;
109
+ }
110
+ return 3;
111
+ }
112
+ getMaxNumberOfGroups() {
113
+ return __awaiter(this, void 0, void 0, function* () {
114
+ let maxNumberOfGroups = 0;
115
+ for (const account of this.accounts) {
116
+ const groups = yield account.getGroups();
117
+ if (groups.length > maxNumberOfGroups) {
118
+ maxNumberOfGroups = groups.length;
119
+ }
120
+ }
121
+ return maxNumberOfGroups;
122
+ });
123
+ }
124
+ /**
125
+ * Sorts groups for an account in hierarchy-path order:
126
+ * 1. Hierarchical groups (those with parent or children) come first, ordered by:
127
+ * - Root group name (alphabetically)
128
+ * - Depth within the hierarchy (parent before child)
129
+ * 2. Free groups (no parent and no children) come last, sorted alphabetically
130
+ */
131
+ sortGroupsHierarchyPath_(groups) {
132
+ // Partition into hierarchical vs free groups
133
+ const hierarchicalGroups = [];
134
+ const freeGroups = [];
135
+ for (const group of groups) {
136
+ if (group.getParent() != null || group.hasChildren()) {
137
+ hierarchicalGroups.push(group);
138
+ }
139
+ else {
140
+ freeGroups.push(group);
141
+ }
142
+ }
143
+ // Group hierarchical groups by their root
144
+ const byRoot = new Map();
145
+ for (const group of hierarchicalGroups) {
146
+ const root = group.getRoot();
147
+ const rootId = root.getId() || '';
148
+ if (!byRoot.has(rootId)) {
149
+ byRoot.set(rootId, []);
150
+ }
151
+ byRoot.get(rootId).push(group);
152
+ }
153
+ // Sort chains: first by root name alphabetically, then by depth within each chain
154
+ const sortedChains = Array.from(byRoot.entries())
155
+ .sort((a, b) => {
156
+ const rootA = a[1][0].getRoot();
157
+ const rootB = b[1][0].getRoot();
158
+ return rootA.getNormalizedName().localeCompare(rootB.getNormalizedName());
159
+ })
160
+ .map(([_, chainGroups]) => chainGroups.sort((a, b) => a.getDepth() - b.getDepth()));
161
+ // Sort free groups alphabetically
162
+ freeGroups.sort((a, b) => a.getNormalizedName().localeCompare(b.getNormalizedName()));
163
+ // Combine: hierarchical chains first, then free groups
164
+ const result = [];
165
+ for (const chain of sortedChains) {
166
+ result.push(...chain);
167
+ }
168
+ result.push(...freeGroups);
169
+ return result;
170
+ }
171
+ /**
172
+ * Builds a two-dimensional array containing all accounts.
173
+ *
174
+ * @returns A promise resolving to a two-dimensional array containing all accounts
175
+ */
176
+ build() {
177
+ return __awaiter(this, void 0, void 0, function* () {
178
+ let table = new Array();
179
+ let accounts = this.accounts;
180
+ if (!this.shouldIncludeArchived) {
181
+ accounts = this.accounts.filter(a => !a.isArchived());
182
+ }
183
+ let headers = [];
184
+ if (this.shouldAddIds) {
185
+ headers.push('Account Id');
186
+ }
187
+ headers.push('Name');
188
+ headers.push('Type');
189
+ if (this.shouldAddGroups) {
190
+ const maxGroups = yield this.getMaxNumberOfGroups();
191
+ for (let i = 0; i < maxGroups; i++) {
192
+ headers.push('Group');
193
+ }
194
+ }
195
+ accounts.sort((a1, a2) => {
196
+ let ret = this.getTypeIndex(a1.getType()) - this.getTypeIndex(a2.getType());
197
+ if (ret === 0) {
198
+ ret = a1.getNormalizedName().localeCompare(a2.getNormalizedName());
199
+ }
200
+ return ret;
201
+ });
202
+ let propertyKeys = [];
203
+ if (this.shouldAddProperties) {
204
+ propertyKeys = this.getPropertyKeys();
205
+ }
206
+ for (const account of accounts) {
207
+ const line = [];
208
+ if (this.shouldAddIds) {
209
+ line.push(account.getId());
210
+ }
211
+ line.push(account.getName());
212
+ line.push(account.getType());
213
+ if (this.shouldAddGroups) {
214
+ const groups = this.sortGroupsHierarchyPath_(yield account.getGroups());
215
+ for (const group of groups) {
216
+ line.push(group.getName());
217
+ }
218
+ }
219
+ if (this.shouldAddGroups && this.shouldAddProperties) {
220
+ const numOfBlankCells = headers.length - line.length;
221
+ for (let i = 0; i < numOfBlankCells; i++) {
222
+ line.push('');
223
+ }
224
+ }
225
+ if (this.shouldAddProperties) {
226
+ const properties = account.getProperties();
227
+ for (const key of propertyKeys) {
228
+ const propertyValue = properties[key];
229
+ if (propertyValue) {
230
+ line.push(propertyValue);
231
+ continue;
232
+ }
233
+ line.push('');
234
+ }
235
+ }
236
+ table.push(line);
237
+ }
238
+ if (this.shouldAddProperties) {
239
+ headers = headers.concat(propertyKeys);
240
+ }
241
+ table.unshift(headers);
242
+ convertInMatrix(table);
243
+ return table;
244
+ });
245
+ }
246
+ }
247
+ //# sourceMappingURL=AccountsDataTableBuilder.js.map
@@ -1,5 +1,5 @@
1
- import { Amount } from "./Amount.js";
2
- import { BalanceType } from "./Enums.js";
1
+ import { Amount } from '../model/Amount.js';
2
+ import { BalanceType } from '../model/Enums.js';
3
3
  import * as Utils from '../utils.js';
4
4
  /**
5
5
  * A BalancesDataTableBuilder is used to setup and build two-dimensional arrays containing balance information.
@@ -25,6 +25,7 @@ export class BalancesDataTableBuilder {
25
25
  this.shouldPeriod = false;
26
26
  this.shouldRaw = false;
27
27
  this.shouldAddProperties = false;
28
+ this.shouldAddHiddenProperties = false;
28
29
  }
29
30
  getBalance(balance, permanent) {
30
31
  return this.getRepresentativeBalance(balance, permanent).toNumber();
@@ -73,7 +74,7 @@ export class BalancesDataTableBuilder {
73
74
  * @returns This builder with respective expanded option, for chaining.
74
75
  */
75
76
  expanded(expanded) {
76
- if (typeof expanded == "boolean" && expanded == true) {
77
+ if (typeof expanded == 'boolean' && expanded == true) {
77
78
  this.maxDepth = 1;
78
79
  this.skipRoot = true;
79
80
  }
@@ -83,7 +84,7 @@ export class BalancesDataTableBuilder {
83
84
  else if (expanded == -2) {
84
85
  this.expandAllAccounts = true;
85
86
  }
86
- else if (typeof expanded == "number" && expanded > 0) {
87
+ else if (typeof expanded == 'number' && expanded > 0) {
87
88
  this.maxDepth = expanded;
88
89
  }
89
90
  return this;
@@ -188,6 +189,19 @@ export class BalancesDataTableBuilder {
188
189
  this.shouldAddProperties = include;
189
190
  return this;
190
191
  }
192
+ /**
193
+ * Defines whether to include hidden properties (keys ending with underscore "_").
194
+ * Only relevant when {@link properties} is enabled.
195
+ * Default is false — hidden properties are excluded.
196
+ *
197
+ * @param include - Whether to include hidden properties
198
+ *
199
+ * @returns This builder with respective option, for chaining.
200
+ */
201
+ hiddenProperties(include) {
202
+ this.shouldAddHiddenProperties = include;
203
+ return this;
204
+ }
191
205
  /**
192
206
  * Defines whether should split **TOTAL** [[BalanceType]] into debit and credit.
193
207
  *
@@ -231,6 +245,9 @@ export class BalancesDataTableBuilder {
231
245
  ////////////////////////
232
246
  addPropertyKeys(propertyKeys, container) {
233
247
  for (const key of container.getPropertyKeys()) {
248
+ if (!this.shouldAddHiddenProperties && key.endsWith('_')) {
249
+ continue;
250
+ }
234
251
  if (propertyKeys.indexOf(key) <= -1) {
235
252
  propertyKeys.push(key);
236
253
  }
@@ -309,7 +326,8 @@ export class BalancesDataTableBuilder {
309
326
  let depth = container.getDepth();
310
327
  if (depth <= this.maxDepth) {
311
328
  if (!this.skipRoot && !this.shouldTranspose) {
312
- container.payload.name = Utils.repeatString(" ", depth * 4) + container.payload.name;
329
+ container.payload.name =
330
+ Utils.repeatString(' ', depth * 4) + container.payload.name;
313
331
  }
314
332
  if (!this.skipRoot || depth != 0) {
315
333
  containersFlat.push(container);
@@ -330,7 +348,8 @@ export class BalancesDataTableBuilder {
330
348
  if (container.isFromGroup()) {
331
349
  if (!this.shouldTranspose) {
332
350
  let depth = container.getDepth();
333
- container.payload.name = Utils.repeatString(" ", depth * 4) + container.payload.name;
351
+ container.payload.name =
352
+ Utils.repeatString(' ', depth * 4) + container.payload.name;
334
353
  }
335
354
  containersFlat.push(container);
336
355
  if (this.shouldAddProperties) {
@@ -460,7 +479,7 @@ export class BalancesDataTableBuilder {
460
479
  var dataIndexMap = new Object();
461
480
  var cumulativeBalance = this.balanceType == BalanceType.CUMULATIVE;
462
481
  var header = new Array();
463
- header.push("");
482
+ header.push('');
464
483
  if (this.balancesContainers == null) {
465
484
  return table;
466
485
  }
@@ -486,7 +505,9 @@ export class BalancesDataTableBuilder {
486
505
  else {
487
506
  amount = balance.getPeriodBalanceRaw();
488
507
  }
489
- indexEntry[container.getName()] = this.shouldRaw ? amount : this.getRepresentativeBalance(amount, container.isPermanent());
508
+ indexEntry[container.getName()] = this.shouldRaw
509
+ ? amount
510
+ : this.getRepresentativeBalance(amount, container.isPermanent());
490
511
  }
491
512
  }
492
513
  }
@@ -499,7 +520,7 @@ export class BalancesDataTableBuilder {
499
520
  for (const container of containers) {
500
521
  var amount = rowObject[container.getName()];
501
522
  if (amount == null) {
502
- amount = "null_amount";
523
+ amount = 'null_amount';
503
524
  }
504
525
  else {
505
526
  amount = new Amount(amount);
@@ -514,7 +535,9 @@ export class BalancesDataTableBuilder {
514
535
  }
515
536
  rows.push(row);
516
537
  }
517
- rows.sort(function (a, b) { return a[0].getTime() - b[0].getTime(); });
538
+ rows.sort(function (a, b) {
539
+ return a[0].getTime() - b[0].getTime();
540
+ });
518
541
  var lastRow = null;
519
542
  for (var i = 0; i < rows.length; i++) {
520
543
  var row = rows[i];
@@ -522,7 +545,7 @@ export class BalancesDataTableBuilder {
522
545
  //first row, all null values will be 0
523
546
  for (var j = 1; j < row.length; j++) {
524
547
  var cell = row[j];
525
- if (cell == "null_amount") {
548
+ if (cell == 'null_amount') {
526
549
  var amount = new Amount(0);
527
550
  if (this.shouldFormatValue) {
528
551
  amount = Utils.formatValue(amount, this.book.getDecimalSeparator(), this.book.getFractionDigits());
@@ -537,12 +560,12 @@ export class BalancesDataTableBuilder {
537
560
  else {
538
561
  for (var j = 1; j < row.length; j++) {
539
562
  var cell = row[j];
540
- if (cell == "null_amount" && cumulativeBalance) {
563
+ if (cell == 'null_amount' && cumulativeBalance) {
541
564
  if (lastRow) {
542
565
  row[j] = lastRow[j];
543
566
  }
544
567
  }
545
- else if (cell == "null_amount") {
568
+ else if (cell == 'null_amount') {
546
569
  var amount = new Amount(0);
547
570
  if (this.shouldFormatValue) {
548
571
  amount = Utils.formatValue(amount, this.book.getDecimalSeparator(), this.book.getFractionDigits());
@@ -0,0 +1,127 @@
1
+ import { convertInMatrix } from '../utils.js';
2
+ /**
3
+ * A BooksDataTableBuilder is used to setup and build two-dimensional arrays containing books.
4
+ *
5
+ * @public
6
+ */
7
+ export class BooksDataTableBuilder {
8
+ constructor(books) {
9
+ this.shouldAddProperties = false;
10
+ this.shouldAddIds = false;
11
+ this.shouldAddHiddenProperties = false;
12
+ this.propertyKeys = [];
13
+ this.books = books;
14
+ }
15
+ /**
16
+ * Defines whether to include custom book properties.
17
+ *
18
+ * @param include - Whether to include properties
19
+ *
20
+ * @returns This builder with respective include properties option, for chaining.
21
+ */
22
+ properties(include) {
23
+ this.shouldAddProperties = include;
24
+ return this;
25
+ }
26
+ /**
27
+ * Defines whether to include book ids.
28
+ *
29
+ * @param include - Whether to include ids
30
+ *
31
+ * @returns This builder with respective include ids option, for chaining.
32
+ */
33
+ ids(include) {
34
+ this.shouldAddIds = include;
35
+ return this;
36
+ }
37
+ /**
38
+ * Defines whether to include hidden properties (keys ending with underscore "_").
39
+ * Only relevant when {@link properties} is enabled.
40
+ * Default is false — hidden properties are excluded.
41
+ *
42
+ * @param include - Whether to include hidden properties
43
+ *
44
+ * @returns This builder with respective option, for chaining.
45
+ */
46
+ hiddenProperties(include) {
47
+ this.shouldAddHiddenProperties = include;
48
+ return this;
49
+ }
50
+ mapPropertyKeys() {
51
+ this.propertyKeys = [];
52
+ for (const book of this.books) {
53
+ for (const key of book.getPropertyKeys()) {
54
+ if (!this.shouldAddHiddenProperties && key.endsWith('_')) {
55
+ continue;
56
+ }
57
+ if (this.propertyKeys.indexOf(key) <= -1) {
58
+ this.propertyKeys.push(key);
59
+ }
60
+ }
61
+ }
62
+ this.propertyKeys = this.propertyKeys.sort();
63
+ }
64
+ /**
65
+ * Builds a two-dimensional array containing all Books.
66
+ *
67
+ * @returns A two-dimensional array containing all Books
68
+ */
69
+ build() {
70
+ var _a, _b;
71
+ const table = new Array();
72
+ this.books.sort((a, b) => {
73
+ var _a, _b;
74
+ const collA = (_a = a.getCollection()) === null || _a === void 0 ? void 0 : _a.getName();
75
+ const collB = (_b = b.getCollection()) === null || _b === void 0 ? void 0 : _b.getName();
76
+ // Books with collection before books without
77
+ if (collA && !collB)
78
+ return -1;
79
+ if (!collA && collB)
80
+ return 1;
81
+ let ret = (collA || '').localeCompare(collB || '');
82
+ if (ret === 0) {
83
+ ret = (a.getName() || '').localeCompare(b.getName() || '');
84
+ }
85
+ return ret;
86
+ });
87
+ let headers = [];
88
+ if (this.shouldAddIds) {
89
+ headers.push('Book Id');
90
+ }
91
+ headers.push('Name');
92
+ headers.push('Collection');
93
+ headers.push('Date Pattern');
94
+ headers.push('Decimal Separator');
95
+ headers.push('Fraction Digits');
96
+ headers.push('Period');
97
+ headers.push('Owner');
98
+ if (this.shouldAddProperties) {
99
+ this.mapPropertyKeys();
100
+ headers = headers.concat(this.propertyKeys);
101
+ }
102
+ for (const book of this.books) {
103
+ const line = [];
104
+ if (this.shouldAddIds) {
105
+ line.push(book.getId());
106
+ }
107
+ line.push(book.getName() || '');
108
+ line.push(((_a = book.getCollection()) === null || _a === void 0 ? void 0 : _a.getName()) || '');
109
+ line.push(book.getDatePattern() || '');
110
+ line.push(book.getDecimalSeparator() || '');
111
+ line.push((_b = book.getFractionDigits()) !== null && _b !== void 0 ? _b : '');
112
+ line.push(book.getPeriod() || '');
113
+ line.push(book.getOwnerName() || '');
114
+ if (this.shouldAddProperties) {
115
+ const properties = book.getProperties();
116
+ for (const key of this.propertyKeys) {
117
+ line.push(properties[key] || '');
118
+ }
119
+ }
120
+ table.push(line);
121
+ }
122
+ table.unshift(headers);
123
+ convertInMatrix(table);
124
+ return table;
125
+ }
126
+ }
127
+ //# sourceMappingURL=BooksDataTableBuilder.js.map