bkper-js 2.0.0 → 2.2.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.
@@ -0,0 +1,587 @@
1
+ import { Amount } from "./Amount";
2
+ import { BalanceType } from "./Enums";
3
+ import * as Utils from '../utils.js';
4
+ /**
5
+ * A BalancesDataTableBuilder is used to setup and build two-dimensional arrays containing balance information.
6
+ *
7
+ * @public
8
+ */
9
+ export class BalancesDataTableBuilder {
10
+ constructor(book, balancesContainers, periodicity) {
11
+ this.maxDepth = 0;
12
+ this.expandAllAccounts = false;
13
+ this.expandAllGroups = false;
14
+ this.skipRoot = false;
15
+ this.book = book;
16
+ this.balancesContainers = balancesContainers;
17
+ this.periodicity = periodicity;
18
+ this.balanceType = BalanceType.TOTAL;
19
+ this.shouldFormatDate = false;
20
+ this.shouldHideDates = false;
21
+ this.shouldHideNames = false;
22
+ this.shouldFormatValue = false;
23
+ this.shouldTranspose = false;
24
+ this.shouldTrial = false;
25
+ this.shouldPeriod = false;
26
+ this.shouldRaw = false;
27
+ this.shouldAddProperties = false;
28
+ }
29
+ getBalance(balance, permanent) {
30
+ return this.getRepresentativeBalance(balance, permanent).toNumber();
31
+ }
32
+ getRepresentativeBalance(balance, permanent) {
33
+ if (balance == null) {
34
+ return new Amount(0);
35
+ }
36
+ if (permanent) {
37
+ return balance.times(-1);
38
+ }
39
+ return balance;
40
+ }
41
+ getBalanceText(balance, permanent) {
42
+ return this.book.formatValue(this.getRepresentativeBalance(balance, permanent));
43
+ }
44
+ /**
45
+ * Defines whether the dates should be formatted based on date pattern and periodicity of the [[Book]].
46
+ *
47
+ * @returns This builder with respective formatting option, for chaining.
48
+ */
49
+ formatDates(format) {
50
+ this.shouldFormatDate = format;
51
+ return this;
52
+ }
53
+ /**
54
+ * Defines whether the value should be formatted based on decimal separator of the [[Book]].
55
+ *
56
+ * @returns This builder with respective formatting option, for chaining.
57
+ */
58
+ formatValues(format) {
59
+ this.shouldFormatValue = format;
60
+ return this;
61
+ }
62
+ /**
63
+ * Defines whether Groups should expand its child accounts. true to expand itself, -1 to expand all subgroups. -2 to expand all accounts.
64
+ *
65
+ *
66
+ * @returns This builder with respective expanded option, for chaining.
67
+ */
68
+ expanded(expanded) {
69
+ if (typeof expanded == "boolean" && expanded == true) {
70
+ this.maxDepth = 1;
71
+ this.skipRoot = true;
72
+ }
73
+ else if (expanded == -1) {
74
+ this.expandAllGroups = true;
75
+ }
76
+ else if (expanded == -2) {
77
+ this.expandAllAccounts = true;
78
+ }
79
+ else if (typeof expanded == "number" && expanded > 0) {
80
+ this.maxDepth = expanded;
81
+ }
82
+ return this;
83
+ }
84
+ /**
85
+ * Fluent method to set the [[BalanceType]] for the builder.
86
+ *
87
+ * @param type The type of balance for this data table
88
+ *
89
+ * For **TOTAL** [[BalanceType]], the table format looks like:
90
+ *
91
+ * ```
92
+ * _____________________
93
+ * | Expenses | -4568.23 |
94
+ * | Income | 5678.93 |
95
+ * | ... | ... |
96
+ * |___________|__________|
97
+ *
98
+ * ```
99
+ * Two columns, and each [[Account]] or [[Group]] per line.
100
+ *
101
+ * For **PERIOD** or **CUMULATIVE** [[BalanceType]], the table will be a time table, and the format looks like:
102
+ *
103
+ * ```
104
+ * _____________________________________________
105
+ * | | Expenses | Income | ... |
106
+ * | 15/01/2014 | -2345.23 | 3452.93 | ... |
107
+ * | 15/02/2014 | -2345.93 | 3456.46 | ... |
108
+ * | 15/03/2014 | -2456.45 | 3567.87 | ... |
109
+ * | ... | ... | ... | ... |
110
+ * |____________|___________|_________|__________|
111
+ *
112
+ * ```
113
+ *
114
+ * First column will be the Date column, and one column for each [[Account]] or [[Group]].
115
+ *
116
+ * @returns This builder with respective balance type, for chaining.
117
+ */
118
+ type(type) {
119
+ this.balanceType = type;
120
+ return this;
121
+ }
122
+ /**
123
+ * Defines whether should rows and columns should be transposed.
124
+ *
125
+ * For **TOTAL** [[BalanceType]], the **transposed** table looks like:
126
+ *
127
+ * ```
128
+ * _____________________________
129
+ * | Expenses | Income | ... |
130
+ * | -4568.23 | 5678.93 | ... |
131
+ * |___________|_________|_______|
132
+ *
133
+ * ```
134
+ * Two rows, and each [[Account]] or [[Group]] per column.
135
+ *
136
+ *
137
+ * For **PERIOD** or **CUMULATIVE** [[BalanceType]], the **transposed** table will be a time table, and the format looks like:
138
+ *
139
+ * ```
140
+ * _______________________________________________________________
141
+ * | | 15/01/2014 | 15/02/2014 | 15/03/2014 | ... |
142
+ * | Expenses | -2345.23 | -2345.93 | -2456.45 | ... |
143
+ * | Income | 3452.93 | 3456.46 | 3567.87 | ... |
144
+ * | ... | ... | ... | ... | ... |
145
+ * |____________|____________|____________|____________|___________|
146
+ *
147
+ * ```
148
+ *
149
+ * First column will be each [[Account]] or [[Group]], and one column for each Date.
150
+ *
151
+ * @returns This builder with respective transposed option, for chaining.
152
+ */
153
+ transposed(transposed) {
154
+ this.shouldTranspose = transposed;
155
+ return this;
156
+ }
157
+ /**
158
+ * Defines whether the dates should be hidden for **PERIOD** or **CUMULATIVE** [[BalanceType]].
159
+ *
160
+ * @returns This builder with respective hide dates option, for chaining.
161
+ */
162
+ hideDates(hide) {
163
+ this.shouldHideDates = hide;
164
+ return this;
165
+ }
166
+ /**
167
+ * Defines whether the [[Accounts]] and [[Groups]] names should be hidden.
168
+ *
169
+ * @returns This builder with respective hide names option, for chaining.
170
+ */
171
+ hideNames(hide) {
172
+ this.shouldHideNames = hide;
173
+ return this;
174
+ }
175
+ /**
176
+ * Defines whether include custom [[Accounts]] and [[Groups]] properties.
177
+ *
178
+ * @returns This builder with respective include properties option, for chaining.
179
+ */
180
+ properties(include) {
181
+ this.shouldAddProperties = include;
182
+ return this;
183
+ }
184
+ /**
185
+ * Defines whether should split **TOTAL** [[BalanceType]] into debit and credit.
186
+ *
187
+ * @returns This builder with respective trial option, for chaining.
188
+ */
189
+ trial(trial) {
190
+ this.shouldTrial = trial;
191
+ return this;
192
+ }
193
+ /**
194
+ * Defines whether should force use of period balances for **TOTAL** [[BalanceType]].
195
+ *
196
+ * @returns This builder with respective trial option, for chaining.
197
+ */
198
+ period(period) {
199
+ this.shouldPeriod = period;
200
+ return this;
201
+ }
202
+ /**
203
+ * Defines whether should show raw balances, no matter the credit nature of the Account or Group.
204
+ *
205
+ * @returns This builder with respective trial option, for chaining.
206
+ */
207
+ raw(raw) {
208
+ this.shouldRaw = raw;
209
+ return this;
210
+ }
211
+ /**
212
+ *
213
+ * Builds an two-dimensional array with the balances.
214
+ *
215
+ */
216
+ build() {
217
+ if (this.balanceType == BalanceType.TOTAL) {
218
+ return this.buildTotalDataTable_();
219
+ }
220
+ else {
221
+ return this.buildTimeDataTable_();
222
+ }
223
+ }
224
+ ////////////////////////
225
+ addPropertyKeys(propertyKeys, container) {
226
+ for (const key of container.getPropertyKeys()) {
227
+ if (propertyKeys.indexOf(key) <= -1) {
228
+ propertyKeys.push(key);
229
+ }
230
+ }
231
+ }
232
+ flattenContainers(containersFlat, propertyKeys) {
233
+ for (const container of this.balancesContainers) {
234
+ if (this.expandAllAccounts) {
235
+ this.flattenAllAccounts(container, containersFlat, propertyKeys);
236
+ containersFlat.sort(this.sortContainersFunction);
237
+ }
238
+ else if (this.expandAllGroups) {
239
+ this.flattenAllGroups(container, containersFlat, propertyKeys);
240
+ }
241
+ else {
242
+ this.flattenMaxDepth(container, containersFlat, propertyKeys);
243
+ }
244
+ }
245
+ }
246
+ flattenAllAccounts(container, containersFlat, propertyKeys) {
247
+ if (container.isFromGroup()) {
248
+ for (const child of container.getBalancesContainers()) {
249
+ this.flattenAllAccounts(child, containersFlat, propertyKeys);
250
+ }
251
+ }
252
+ else {
253
+ containersFlat.push(container);
254
+ if (this.shouldAddProperties) {
255
+ this.addPropertyKeys(propertyKeys, container);
256
+ }
257
+ }
258
+ }
259
+ sortContainersFunction(a, b) {
260
+ let ret = 0;
261
+ if (a.isPermanent() && !b.isPermanent()) {
262
+ ret = -1;
263
+ }
264
+ else if (!a.isPermanent() && b.isPermanent()) {
265
+ ret = 1;
266
+ }
267
+ if (ret == 0) {
268
+ if (a.getParent() && !b.getParent()) {
269
+ ret = -1;
270
+ }
271
+ else if (!a.getParent() && b.getParent()) {
272
+ ret = 1;
273
+ }
274
+ }
275
+ if (ret == 0) {
276
+ ret = getBalanceTypeOrdinal(a) - getBalanceTypeOrdinal(b);
277
+ }
278
+ if (ret == 0) {
279
+ ret = a.getName().toLowerCase().localeCompare(b.getName().toLowerCase());
280
+ }
281
+ function getBalanceTypeOrdinal(bc) {
282
+ // ASSET(true, false, "asset"),
283
+ if (bc.isPermanent() && !bc.isCredit()) {
284
+ return 0;
285
+ }
286
+ // LIABILITY(true, true, "liability"),
287
+ if (bc.isPermanent() && bc.isCredit()) {
288
+ return 1;
289
+ }
290
+ // INCOMING(false, true, "incoming"),
291
+ if (!bc.isPermanent() && bc.isCredit()) {
292
+ return 2;
293
+ }
294
+ if (!bc.isPermanent() && !bc.isCredit()) {
295
+ return 3;
296
+ }
297
+ return 4;
298
+ }
299
+ return ret;
300
+ }
301
+ flattenMaxDepth(container, containersFlat, propertyKeys) {
302
+ let depth = container.getDepth();
303
+ if (depth <= this.maxDepth) {
304
+ if (!this.skipRoot && !this.shouldTranspose) {
305
+ //@ts-ignore
306
+ container.json.name = Utils_.repeatString(" ", depth * 4) + container.json.name;
307
+ }
308
+ if (!this.skipRoot || depth != 0) {
309
+ containersFlat.push(container);
310
+ if (this.shouldAddProperties) {
311
+ this.addPropertyKeys(propertyKeys, container);
312
+ }
313
+ }
314
+ const children = container.getBalancesContainers();
315
+ if (children && children.length > 0) {
316
+ children.sort(this.sortContainersFunction);
317
+ for (const child of children) {
318
+ this.flattenMaxDepth(child, containersFlat, propertyKeys);
319
+ }
320
+ }
321
+ }
322
+ }
323
+ flattenAllGroups(container, containersFlat, propertyKeys) {
324
+ if (container.isFromGroup()) {
325
+ if (!this.shouldTranspose) {
326
+ let depth = container.getDepth();
327
+ //@ts-ignore
328
+ container.json.name = Utils_.repeatString(" ", depth * 4) + container.json.name;
329
+ }
330
+ containersFlat.push(container);
331
+ if (this.shouldAddProperties) {
332
+ this.addPropertyKeys(propertyKeys, container);
333
+ }
334
+ if (container.hasGroupBalances()) {
335
+ const children = container.getBalancesContainers();
336
+ children.sort(this.sortContainersFunction);
337
+ for (const child of children) {
338
+ this.flattenAllGroups(child, containersFlat, propertyKeys);
339
+ }
340
+ }
341
+ }
342
+ }
343
+ buildTotalDataTable_() {
344
+ var table = new Array();
345
+ if (this.balancesContainers == null) {
346
+ return table;
347
+ }
348
+ this.balancesContainers.sort((a, b) => {
349
+ if (a != null && b != null) {
350
+ return a.getName().toLowerCase().localeCompare(b.getName().toLowerCase());
351
+ }
352
+ return -1;
353
+ });
354
+ let propertyKeys = [];
355
+ let containers = new Array();
356
+ this.flattenContainers(containers, propertyKeys);
357
+ if (this.shouldAddProperties) {
358
+ propertyKeys.sort();
359
+ let header = ['name', 'balance'];
360
+ for (const key of propertyKeys) {
361
+ header.push(key);
362
+ }
363
+ table.push(header);
364
+ }
365
+ for (var i = 0; i < containers.length; i++) {
366
+ var balances = containers[i];
367
+ if (balances != null) {
368
+ var line = new Array();
369
+ var name = balances.getName();
370
+ line.push(name);
371
+ if (this.shouldTrial) {
372
+ if (this.shouldFormatValue) {
373
+ if (this.shouldPeriod) {
374
+ line.push(balances.getPeriodDebitText());
375
+ line.push(balances.getPeriodCreditText());
376
+ }
377
+ else {
378
+ line.push(balances.getCumulativeDebitText());
379
+ line.push(balances.getCumulativeCreditText());
380
+ }
381
+ }
382
+ else {
383
+ if (this.shouldPeriod) {
384
+ line.push(balances.getPeriodDebit().toNumber());
385
+ line.push(balances.getPeriodCredit().toNumber());
386
+ }
387
+ else {
388
+ line.push(balances.getCumulativeDebit().toNumber());
389
+ line.push(balances.getCumulativeCredit().toNumber());
390
+ }
391
+ }
392
+ }
393
+ else {
394
+ if (this.shouldFormatValue) {
395
+ if (this.shouldPeriod) {
396
+ if (this.shouldRaw) {
397
+ line.push(balances.getPeriodBalanceRawText());
398
+ }
399
+ else {
400
+ line.push(this.getBalanceText(balances.getPeriodBalanceRaw(), balances.isPermanent()));
401
+ }
402
+ }
403
+ else {
404
+ if (this.shouldRaw) {
405
+ line.push(balances.getCumulativeBalanceRawText());
406
+ }
407
+ else {
408
+ line.push(this.getBalanceText(balances.getCumulativeBalanceRaw(), balances.isPermanent()));
409
+ }
410
+ }
411
+ }
412
+ else {
413
+ if (this.shouldPeriod) {
414
+ if (this.shouldRaw) {
415
+ line.push(balances.getPeriodBalanceRaw().toNumber());
416
+ }
417
+ else {
418
+ line.push(this.getBalance(balances.getPeriodBalanceRaw(), balances.isPermanent()));
419
+ }
420
+ }
421
+ else {
422
+ if (this.shouldRaw) {
423
+ line.push(balances.getCumulativeBalanceRaw().toNumber());
424
+ }
425
+ else {
426
+ line.push(this.getBalance(balances.getCumulativeBalanceRaw(), balances.isPermanent()));
427
+ }
428
+ }
429
+ }
430
+ }
431
+ if (this.shouldAddProperties) {
432
+ const properties = balances.getProperties();
433
+ for (const key of propertyKeys) {
434
+ let propertyValue = properties[key];
435
+ if (propertyValue) {
436
+ line.push(propertyValue);
437
+ continue;
438
+ }
439
+ line.push('');
440
+ }
441
+ }
442
+ table.push(line);
443
+ }
444
+ }
445
+ if (this.shouldHideNames) {
446
+ table = table.map(row => row.slice(1));
447
+ }
448
+ if (this.shouldTranspose && table.length > 0) {
449
+ table = table[0].map((col, i) => table.map(row => row[i]));
450
+ }
451
+ return table;
452
+ }
453
+ buildTimeDataTable_() {
454
+ var table = new Array();
455
+ var dataIndexMap = new Object();
456
+ var cumulativeBalance = this.balanceType == BalanceType.CUMULATIVE;
457
+ var header = new Array();
458
+ header.push("");
459
+ if (this.balancesContainers == null) {
460
+ return table;
461
+ }
462
+ let propertyKeys = [];
463
+ let containers = new Array();
464
+ this.flattenContainers(containers, propertyKeys);
465
+ for (const container of containers) {
466
+ header.push(container.getName());
467
+ var balances = container.getBalances();
468
+ if (balances != null) {
469
+ for (const balance of balances) {
470
+ var fuzzyDate = balance.getFuzzyDate();
471
+ var indexEntry = dataIndexMap[fuzzyDate];
472
+ if (indexEntry == null) {
473
+ indexEntry = {};
474
+ indexEntry.date = balance.getDate();
475
+ dataIndexMap[fuzzyDate] = indexEntry;
476
+ }
477
+ var amount;
478
+ if (cumulativeBalance) {
479
+ amount = balance.getCumulativeBalanceRaw();
480
+ }
481
+ else {
482
+ amount = balance.getPeriodBalanceRaw();
483
+ }
484
+ indexEntry[container.getName()] = this.shouldRaw ? amount : this.getRepresentativeBalance(amount, container.isPermanent());
485
+ }
486
+ }
487
+ }
488
+ table.push(header);
489
+ var rows = new Array();
490
+ for (var fuzzy in dataIndexMap) {
491
+ var rowObject = dataIndexMap[fuzzy];
492
+ var row = new Array();
493
+ row.push(rowObject.date);
494
+ for (const container of containers) {
495
+ var amount = rowObject[container.getName()];
496
+ if (amount == null) {
497
+ amount = "null_amount";
498
+ }
499
+ else {
500
+ amount = new Amount(amount);
501
+ if (this.shouldFormatValue) {
502
+ amount = Utils.formatValue(amount, this.book.getDecimalSeparator(), this.book.getFractionDigits());
503
+ }
504
+ else {
505
+ amount = amount.toNumber();
506
+ }
507
+ }
508
+ row.push(amount);
509
+ }
510
+ rows.push(row);
511
+ }
512
+ rows.sort(function (a, b) { return a[0].getTime() - b[0].getTime(); });
513
+ var lastRow = null;
514
+ for (var i = 0; i < rows.length; i++) {
515
+ var row = rows[i];
516
+ if (i == 0) {
517
+ //first row, all null values will be 0
518
+ for (var j = 1; j < row.length; j++) {
519
+ var cell = row[j];
520
+ if (cell == "null_amount") {
521
+ var amount = new Amount(0);
522
+ if (this.shouldFormatValue) {
523
+ amount = Utils.formatValue(amount, this.book.getDecimalSeparator(), this.book.getFractionDigits());
524
+ }
525
+ else {
526
+ amount = amount.toNumber();
527
+ }
528
+ row[j] = amount;
529
+ }
530
+ }
531
+ }
532
+ else {
533
+ for (var j = 1; j < row.length; j++) {
534
+ var cell = row[j];
535
+ if (cell == "null_amount" && cumulativeBalance) {
536
+ if (lastRow) {
537
+ row[j] = lastRow[j];
538
+ }
539
+ }
540
+ else if (cell == "null_amount") {
541
+ var amount = new Amount(0);
542
+ if (this.shouldFormatValue) {
543
+ amount = Utils.formatValue(amount, this.book.getDecimalSeparator(), this.book.getFractionDigits());
544
+ }
545
+ else {
546
+ amount = amount.toNumber();
547
+ }
548
+ row[j] = amount;
549
+ }
550
+ }
551
+ }
552
+ lastRow = row;
553
+ table.push(row);
554
+ }
555
+ if (this.shouldFormatDate && table.length > 0) {
556
+ var pattern = Utils.getDateFormatterPattern(this.book.getDatePattern(), this.periodicity);
557
+ for (var j = 1; j < table.length; j++) {
558
+ var row = table[j];
559
+ if (row.length > 0) {
560
+ //first column
561
+ row[0] = Utils.formatDate(row[0], pattern, this.book.getTimeZone());
562
+ }
563
+ }
564
+ }
565
+ if (this.shouldAddProperties) {
566
+ propertyKeys.sort();
567
+ for (const key of propertyKeys) {
568
+ var propertyRow = [key];
569
+ for (const container of containers) {
570
+ propertyRow.push(container.getProperty(key) || '');
571
+ }
572
+ table.push(propertyRow);
573
+ }
574
+ }
575
+ if (this.shouldHideNames) {
576
+ table.shift();
577
+ }
578
+ if (this.shouldHideDates) {
579
+ table = table.map(row => row.slice(1));
580
+ }
581
+ if (this.shouldTranspose && table.length > 0) {
582
+ table = table[0].map((col, i) => table.map(row => row[i]));
583
+ }
584
+ return table;
585
+ }
586
+ }
587
+ //# sourceMappingURL=BalancesDataTableBuilder.js.map
@@ -24,30 +24,40 @@ import { Agent } from "./Agent.js";
24
24
  /**
25
25
  * This is the main entry point of the [bkper-js](https://www.npmjs.com/package/bkper-js) library.
26
26
  *
27
- * You start by setting the API [[Config]] object.
27
+ * You start by setting the API [[Config]] object using the static setConfig method.
28
28
  *
29
29
  * Example:
30
30
  *
31
31
  * ```javascript
32
- * Bkper.get().setConfig({
32
+ * Bkper.setConfig({
33
33
  * apiKeyProvider: () => process.env.BKPER_API_KEY,
34
34
  * oauthTokenProvider: () => process.env.BKPER_OAUTH_TOKEN
35
- * })
35
+ * });
36
+ *
37
+ * const bkper = new Bkper();
38
+ * const book = await bkper.getBook('bookId');
36
39
  * ```
37
40
  *
38
- * Once the config is set, you can start using the library.
41
+ * Once the config is set, you can create instances and start using the library.
39
42
  *
40
43
  * @public
41
44
  */
42
45
  export class Bkper {
43
46
  /**
44
- * Creates a new Bkper instance with the specified API configuration.
47
+ * Sets the global API configuration for all Bkper operations.
45
48
  *
46
- * @param config - The Config object
49
+ * @param config - The Config object containing API key and OAuth token providers
47
50
  */
48
- constructor(config) {
51
+ static setConfig(config) {
49
52
  HttpApiRequest.config = config;
50
53
  }
54
+ /**
55
+ * Creates a new Bkper instance using the global configuration set via setConfig().
56
+ * Make sure to call Bkper.setConfig() before creating instances.
57
+ */
58
+ constructor() {
59
+ // Uses global configuration set via setConfig()
60
+ }
51
61
  /**
52
62
  * Gets the [[Book]] with the specified bookId from url param.
53
63
  *
@@ -108,6 +108,26 @@ export var AccountType;
108
108
  */
109
109
  AccountType["OUTGOING"] = "OUTGOING";
110
110
  })(AccountType || (AccountType = {}));
111
+ /**
112
+ * Enum that represents balance types.
113
+ *
114
+ * @public
115
+ */
116
+ export var BalanceType;
117
+ (function (BalanceType) {
118
+ /**
119
+ * Total balance
120
+ */
121
+ BalanceType["TOTAL"] = "TOTAL";
122
+ /**
123
+ * Period balance
124
+ */
125
+ BalanceType["PERIOD"] = "PERIOD";
126
+ /**
127
+ * Cumulative balance
128
+ */
129
+ BalanceType["CUMULATIVE"] = "CUMULATIVE";
130
+ })(BalanceType || (BalanceType = {}));
111
131
  /**
112
132
  * Enum that represents a period slice.
113
133
  *
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "bkper-js",
3
- "version": "2.0.0",
3
+ "version": "2.2.0",
4
4
  "description": "Javascript client for Bkper REST API",
5
5
  "main": "./lib/index.js",
6
6
  "module": "./lib/index.js",