taxtank-core 0.28.97 → 0.28.99

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 (132) hide show
  1. package/bundles/taxtank-core.umd.js +2303 -2040
  2. package/bundles/taxtank-core.umd.js.map +1 -1
  3. package/esm2015/lib/collections/index.js +3 -1
  4. package/esm2015/lib/collections/sole/sole-business-losses.collection.js +2 -2
  5. package/esm2015/lib/db/Models/abstract-model.js +2 -1
  6. package/esm2015/lib/db/Models/observable-model.js +10 -0
  7. package/esm2015/lib/db/Models/property/property.js +3 -3
  8. package/esm2015/lib/db/Models/sole/bas-report.js +3 -2
  9. package/esm2015/lib/functions/array/index.js +2 -1
  10. package/esm2015/lib/functions/array/to-array.js +7 -0
  11. package/esm2015/lib/models/event/app-event.js +12 -1
  12. package/esm2015/lib/models/property/property.js +3 -1
  13. package/esm2015/lib/models/report/sole/sole-business/sole-business-loss-report.js +4 -2
  14. package/esm2015/lib/services/account-setup/account-setup.service.js +3 -2
  15. package/esm2015/lib/services/event/event-dispatcher.service.js +12 -1
  16. package/esm2015/lib/services/http/bank/bank-account/bank-account.service.js +2 -2
  17. package/esm2015/lib/services/http/bank/bank-connection/bank-connection.service.js +2 -2
  18. package/esm2015/lib/services/http/bank/bank-transaction/bank-transaction.service.js +2 -2
  19. package/esm2015/lib/services/http/bank/bank.service.js +2 -2
  20. package/esm2015/lib/services/http/bank/basiq/basiq.service.js +2 -2
  21. package/esm2015/lib/services/http/chart-accounts/chart-accounts-depreciations/chart-accounts-depreciations.service.js +2 -2
  22. package/esm2015/lib/services/http/chat/chat.service.js +2 -2
  23. package/esm2015/lib/services/http/chat/message/message.service.js +2 -2
  24. package/esm2015/lib/services/http/depreciation/depreciation.service.js +2 -2
  25. package/esm2015/lib/services/http/document/document-folder/document-folder.service.js +2 -2
  26. package/esm2015/lib/services/http/document/document.service.js +2 -2
  27. package/esm2015/lib/services/http/firm/client-invite/client-invite.service.js +2 -2
  28. package/esm2015/lib/services/http/firm/client-movement/client-movement.service.js +2 -2
  29. package/esm2015/lib/services/http/firm/employee/employee.service.js +2 -2
  30. package/esm2015/lib/services/http/firm/employee-invite/employee-invite.service.js +2 -2
  31. package/esm2015/lib/services/http/income-source/income-source-forecast/income-source-forecast.service.js +2 -2
  32. package/esm2015/lib/services/http/income-source/income-source.service.js +2 -2
  33. package/esm2015/lib/services/http/income-source/salary-forecast/salary-forecast.service.js +2 -2
  34. package/esm2015/lib/services/http/income-source/sole-forecast/sole-forecast.service.js +2 -2
  35. package/esm2015/lib/services/http/loan/loan.service.js +2 -2
  36. package/esm2015/lib/services/http/property/property-category/property-category.service.js +2 -2
  37. package/esm2015/lib/services/http/property/property-category-movement/property-category-movement.service.js +2 -2
  38. package/esm2015/lib/services/http/property/property-document/property-document.service.js +2 -2
  39. package/esm2015/lib/services/http/property/property-sale/property-sale.service.js +2 -2
  40. package/esm2015/lib/services/http/property/property-sale/tax-exemption/tax-exemption.service.js +2 -2
  41. package/esm2015/lib/services/http/property/property-share/property-share.service.js +2 -2
  42. package/esm2015/lib/services/http/property/property.service.js +29 -46
  43. package/esm2015/lib/services/http/rest/http-method.type.js +2 -0
  44. package/esm2015/lib/services/http/rest/index.js +3 -1
  45. package/esm2015/lib/services/http/rest/rest-method.type.js +2 -0
  46. package/esm2015/lib/services/http/rest/rest-old.service.js +225 -0
  47. package/esm2015/lib/services/http/rest/rest.service.js +144 -147
  48. package/esm2015/lib/services/http/service-notification/service-notification.service.js +2 -2
  49. package/esm2015/lib/services/http/sole/bas-report/bas-report.service.js +2 -2
  50. package/esm2015/lib/services/http/sole/sole-business/sole-business.service.js +2 -2
  51. package/esm2015/lib/services/http/sole/sole-business-activity/sole-business-activity.service.js +2 -2
  52. package/esm2015/lib/services/http/sole/sole-business-loss/sole-business-loss-rules/sole-business-loss-offset-rule.service.js +2 -2
  53. package/esm2015/lib/services/http/sole/sole-business-loss/sole-business-loss.service.js +2 -2
  54. package/esm2015/lib/services/http/sole/sole-contact/sole-contact.service.js +2 -2
  55. package/esm2015/lib/services/http/sole/sole-invoice/sole-invoice.service.js +2 -2
  56. package/esm2015/lib/services/http/sole/sole-invoice-template/sole-invoice-template.service.js +2 -2
  57. package/esm2015/lib/services/http/subscription/service-price.service.js +2 -2
  58. package/esm2015/lib/services/http/tax-review/tax-review-history/tax-review-history.service.js +2 -2
  59. package/esm2015/lib/services/http/tax-review/tax-review.service.js +2 -2
  60. package/esm2015/lib/services/http/transaction/transaction-allocation/transaction-allocation.service.js +2 -2
  61. package/esm2015/lib/services/http/transaction/transaction.service.js +2 -2
  62. package/esm2015/lib/services/http/user/user-event-setting/user-event-setting.service.js +2 -2
  63. package/esm2015/lib/services/http/user/user-event-type/user-event-type.service.js +2 -2
  64. package/esm2015/lib/services/http/user/users-invite/users-invite.service.js +2 -2
  65. package/esm2015/lib/services/http/vehicle/vehicle-claim.service.js +2 -2
  66. package/esm2015/lib/services/http/vehicle/vehicle-logbook.service.js +2 -2
  67. package/esm2015/lib/services/http/vehicle/vehicle.service.js +2 -2
  68. package/esm2015/lib/services/report/property/property-transaction-report.service.js +2 -3
  69. package/fesm2015/taxtank-core.js +1964 -1728
  70. package/fesm2015/taxtank-core.js.map +1 -1
  71. package/lib/collections/index.d.ts +2 -0
  72. package/lib/db/Models/observable-model.d.ts +8 -0
  73. package/lib/db/Models/property/property.d.ts +2 -2
  74. package/lib/db/Models/sole/bas-report.d.ts +2 -1
  75. package/lib/functions/array/index.d.ts +1 -0
  76. package/lib/functions/array/to-array.d.ts +4 -0
  77. package/lib/models/event/app-event.d.ts +9 -0
  78. package/lib/models/property/property.d.ts +2 -0
  79. package/lib/services/event/event-dispatcher.service.d.ts +9 -1
  80. package/lib/services/http/bank/bank-account/bank-account.service.d.ts +1 -1
  81. package/lib/services/http/bank/bank-connection/bank-connection.service.d.ts +1 -1
  82. package/lib/services/http/bank/bank-transaction/bank-transaction.service.d.ts +1 -1
  83. package/lib/services/http/bank/bank.service.d.ts +1 -1
  84. package/lib/services/http/bank/basiq/basiq.service.d.ts +1 -1
  85. package/lib/services/http/chart-accounts/chart-accounts-depreciations/chart-accounts-depreciations.service.d.ts +1 -1
  86. package/lib/services/http/chat/chat.service.d.ts +1 -1
  87. package/lib/services/http/chat/message/message.service.d.ts +1 -1
  88. package/lib/services/http/depreciation/depreciation.service.d.ts +1 -1
  89. package/lib/services/http/document/document-folder/document-folder.service.d.ts +1 -1
  90. package/lib/services/http/document/document.service.d.ts +1 -1
  91. package/lib/services/http/firm/client-invite/client-invite.service.d.ts +1 -1
  92. package/lib/services/http/firm/client-movement/client-movement.service.d.ts +1 -1
  93. package/lib/services/http/firm/employee/employee.service.d.ts +1 -1
  94. package/lib/services/http/firm/employee-invite/employee-invite.service.d.ts +1 -1
  95. package/lib/services/http/income-source/income-source-forecast/income-source-forecast.service.d.ts +1 -1
  96. package/lib/services/http/income-source/income-source.service.d.ts +1 -1
  97. package/lib/services/http/income-source/salary-forecast/salary-forecast.service.d.ts +1 -1
  98. package/lib/services/http/income-source/sole-forecast/sole-forecast.service.d.ts +1 -1
  99. package/lib/services/http/loan/loan.service.d.ts +1 -1
  100. package/lib/services/http/property/property-category/property-category.service.d.ts +1 -1
  101. package/lib/services/http/property/property-category-movement/property-category-movement.service.d.ts +1 -1
  102. package/lib/services/http/property/property-document/property-document.service.d.ts +1 -1
  103. package/lib/services/http/property/property-sale/property-sale.service.d.ts +1 -1
  104. package/lib/services/http/property/property-sale/tax-exemption/tax-exemption.service.d.ts +1 -1
  105. package/lib/services/http/property/property-share/property-share.service.d.ts +1 -1
  106. package/lib/services/http/property/property.service.d.ts +8 -11
  107. package/lib/services/http/rest/http-method.type.d.ts +1 -0
  108. package/lib/services/http/rest/index.d.ts +2 -0
  109. package/lib/services/http/rest/rest-method.type.d.ts +1 -0
  110. package/lib/services/http/rest/rest-old.service.d.ts +110 -0
  111. package/lib/services/http/rest/rest.service.d.ts +71 -62
  112. package/lib/services/http/service-notification/service-notification.service.d.ts +1 -1
  113. package/lib/services/http/sole/bas-report/bas-report.service.d.ts +1 -1
  114. package/lib/services/http/sole/sole-business/sole-business.service.d.ts +1 -1
  115. package/lib/services/http/sole/sole-business-activity/sole-business-activity.service.d.ts +1 -1
  116. package/lib/services/http/sole/sole-business-loss/sole-business-loss-rules/sole-business-loss-offset-rule.service.d.ts +1 -1
  117. package/lib/services/http/sole/sole-business-loss/sole-business-loss.service.d.ts +1 -1
  118. package/lib/services/http/sole/sole-contact/sole-contact.service.d.ts +1 -1
  119. package/lib/services/http/sole/sole-invoice/sole-invoice.service.d.ts +1 -1
  120. package/lib/services/http/sole/sole-invoice-template/sole-invoice-template.service.d.ts +1 -1
  121. package/lib/services/http/subscription/service-price.service.d.ts +1 -1
  122. package/lib/services/http/tax-review/tax-review-history/tax-review-history.service.d.ts +1 -1
  123. package/lib/services/http/tax-review/tax-review.service.d.ts +1 -1
  124. package/lib/services/http/transaction/transaction-allocation/transaction-allocation.service.d.ts +1 -1
  125. package/lib/services/http/transaction/transaction.service.d.ts +1 -1
  126. package/lib/services/http/user/user-event-setting/user-event-setting.service.d.ts +1 -1
  127. package/lib/services/http/user/user-event-type/user-event-type.service.d.ts +1 -1
  128. package/lib/services/http/user/users-invite/users-invite.service.d.ts +1 -1
  129. package/lib/services/http/vehicle/vehicle-claim.service.d.ts +1 -1
  130. package/lib/services/http/vehicle/vehicle-logbook.service.d.ts +1 -1
  131. package/lib/services/http/vehicle/vehicle.service.d.ts +1 -1
  132. package/package.json +1 -1
@@ -4,7 +4,7 @@ import * as i1$2 from '@angular/common';
4
4
  import { CommonModule, DatePipe } from '@angular/common';
5
5
  import * as i1 from '@angular/common/http';
6
6
  import { HttpParams, HttpErrorResponse, HTTP_INTERCEPTORS } from '@angular/common/http';
7
- import { map, mergeMap, filter, catchError, take, switchMap, finalize, skip, distinctUntilChanged, debounceTime } from 'rxjs/operators';
7
+ import { map, mergeMap, filter, catchError, take, switchMap, finalize, first as first$1, skip, distinctUntilChanged, debounceTime } from 'rxjs/operators';
8
8
  import { ReplaySubject, Subject, BehaviorSubject, throwError, Observable, of, combineLatest, forkJoin, from, merge as merge$1 } from 'rxjs';
9
9
  import { plainToClass, classToPlain, Type, Transform, Expose, Exclude } from 'class-transformer';
10
10
  import { JwtHelperService } from '@auth0/angular-jwt';
@@ -29,10 +29,10 @@ import { Validators, FormGroup, FormControl, FormArray } from '@angular/forms';
29
29
  import _ from 'lodash';
30
30
  import * as i1$1 from '@angular/router';
31
31
  import { NavigationEnd } from '@angular/router';
32
+ import merge from 'lodash/merge';
32
33
  import { loadStripe } from '@stripe/stripe-js';
33
34
  import fromPairs from 'lodash/fromPairs';
34
35
  import * as html2pdf from 'html2pdf.js';
35
- import merge from 'lodash/merge';
36
36
  import autoTable from 'jspdf-autotable';
37
37
  import jsPDF from 'jspdf';
38
38
  import isEqual from 'lodash/isEqual';
@@ -271,9 +271,14 @@ var AppEventTypeEnum;
271
271
  AppEventTypeEnum[AppEventTypeEnum["VEHICLE_LOGBOOK_BEST_PERIOD_UPDATED"] = 70] = "VEHICLE_LOGBOOK_BEST_PERIOD_UPDATED";
272
272
  })(AppEventTypeEnum || (AppEventTypeEnum = {}));
273
273
 
274
+ /**
275
+ * @TODO Alex (TT-1777): replace old logic with the new when all services ready
276
+ * @TODO Alex (TT-1777): rename old logic and keep it for custom events
277
+ */
274
278
  class EventDispatcherService {
275
279
  constructor() {
276
280
  this.eventSubject = new Subject();
281
+ this.eventSubject2 = new Subject();
277
282
  }
278
283
  /**
279
284
  * subscription to specific event type
@@ -281,12 +286,18 @@ class EventDispatcherService {
281
286
  on(eventType) {
282
287
  return this.eventSubject.pipe(filter((event) => [].concat(eventType).includes(event.type)), map((event) => event.payload));
283
288
  }
289
+ on2(eventName) {
290
+ return this.eventSubject2.pipe(filter((event) => eventName.includes(event.name)), map((event) => event.items));
291
+ }
284
292
  /**
285
293
  * deliver new event
286
294
  */
287
295
  dispatch(event) {
288
296
  this.eventSubject.next(event);
289
297
  }
298
+ dispatch2(event) {
299
+ this.eventSubject2.next(event);
300
+ }
290
301
  }
291
302
  EventDispatcherService.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.2.15", ngImport: i0, type: EventDispatcherService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
292
303
  EventDispatcherService.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "12.2.15", ngImport: i0, type: EventDispatcherService, providedIn: 'root' });
@@ -867,6 +878,13 @@ function getValue(obj, fields) {
867
878
  return value;
868
879
  }
869
880
 
881
+ /**
882
+ * Convert single object or array into array
883
+ */
884
+ function toArray(data) {
885
+ return Array.isArray(data) ? data : [data];
886
+ }
887
+
870
888
  /**
871
889
  * Common toast message class
872
890
  */
@@ -941,13 +959,9 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.15", ngImpo
941
959
  * and describe abstract methods/properties that have to be implemented in child services
942
960
  * Model - entity service is working with
943
961
  * BaseModel - base entity model that extends by Model
944
- * @TODO TT-1777 Alex: refactor all services for work with collections instead of arrays
945
- * @TODO TT-1777 Alex: implement smart system of default toast messages
946
- * @TODO TT-1777 Alex: work not only with array/collection but with single objects
947
- * @TODO TT-1777 Alex: automatic events generation (eventDispatcher)
948
- * @TODO TT-1777 Alex: optional rest methods (not all services have all 4 methods)
962
+ * @TODO TT-1777 Alex: remove when all services refactored
949
963
  */
950
- class RestService {
964
+ class RestService$1 {
951
965
  constructor(http, eventDispatcherService, environment, toastService) {
952
966
  this.http = http;
953
967
  this.eventDispatcherService = eventDispatcherService;
@@ -1144,9 +1158,9 @@ class RestService {
1144
1158
  */
1145
1159
  listenEvents() { }
1146
1160
  }
1147
- RestService.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.2.15", ngImport: i0, type: RestService, deps: [{ token: i1.HttpClient }, { token: EventDispatcherService }, { token: 'environment' }, { token: ToastService }], target: i0.ɵɵFactoryTarget.Injectable });
1148
- RestService.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "12.2.15", ngImport: i0, type: RestService, providedIn: 'root' });
1149
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.15", ngImport: i0, type: RestService, decorators: [{
1161
+ RestService$1.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.2.15", ngImport: i0, type: RestService$1, deps: [{ token: i1.HttpClient }, { token: EventDispatcherService }, { token: 'environment' }, { token: ToastService }], target: i0.ɵɵFactoryTarget.Injectable });
1162
+ RestService$1.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "12.2.15", ngImport: i0, type: RestService$1, providedIn: 'root' });
1163
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.15", ngImport: i0, type: RestService$1, decorators: [{
1150
1164
  type: Injectable,
1151
1165
  args: [{
1152
1166
  providedIn: 'root'
@@ -1584,7 +1598,19 @@ class AppEvent {
1584
1598
  this.payload = payload;
1585
1599
  }
1586
1600
  }
1601
+ /**
1602
+ * @TODO Alex (TT-1777): temp name, replace AppEvent or rename this class when all services refactored
1603
+ */
1604
+ class AppEvent2 {
1605
+ constructor(name,
1606
+ // Pass null for deleted items, otherwise always pass changed items even if you don't need it
1607
+ items) {
1608
+ this.name = name;
1609
+ this.items = items;
1610
+ }
1611
+ }
1587
1612
 
1613
+ // @TODO make it abstract
1588
1614
  class AbstractModel {
1589
1615
  hasValue(value, path = 'id') {
1590
1616
  return get(path) === value;
@@ -2016,7 +2042,16 @@ class BankAccountBalance extends AbstractModel {
2016
2042
  class BankAccountProperty$1 extends AbstractModel {
2017
2043
  }
2018
2044
 
2019
- class Property$1 extends AbstractModel {
2045
+ /**
2046
+ * Model, which children should be listened via event dispatcher service ising automatic events
2047
+ */
2048
+ class ObservableModel extends AbstractModel {
2049
+ static getEventName(method) {
2050
+ return `${this.name}_${method}`;
2051
+ }
2052
+ }
2053
+
2054
+ class Property$1 extends ObservableModel {
2020
2055
  }
2021
2056
 
2022
2057
  class PropertySubscription$1 extends AbstractModel {
@@ -4124,7 +4159,7 @@ __decorate([
4124
4159
  Type(() => User)
4125
4160
  ], SoleDetails.prototype, "user", void 0);
4126
4161
 
4127
- class BasReport$1 {
4162
+ class BasReport$1 extends AbstractModel {
4128
4163
  }
4129
4164
 
4130
4165
  class BasReport extends BasReport$1 {
@@ -4505,1971 +4540,1972 @@ class PropertySaleTaxExemptionMetadataCollection extends Collection {
4505
4540
  }
4506
4541
  }
4507
4542
 
4508
- /**
4509
- * propertySale docs - https://taxtank.atlassian.net/wiki/spaces/TAXTANK/pages/4209508353/Property+Sold+button
4510
- */
4511
- class Property extends Property$1 {
4512
- get name() {
4513
- return this.address.name;
4514
- }
4515
- get isActive() {
4516
- var _a;
4517
- return !!((_a = this.subscriptions) === null || _a === void 0 ? void 0 : _a.length);
4543
+ class PropertySaleCollection extends Collection {
4544
+ get grossCGT() {
4545
+ return this.create(this.items.filter((propertySale) => propertySale.grossCGT > 0)).sumBy('grossCGT');
4518
4546
  }
4519
- isOwn() {
4520
- return this.user.id === +localStorage.getItem('userId');
4547
+ /**
4548
+ * Property sales are CGT applicable unless it has "Principle place of residence" exemption type
4549
+ */
4550
+ getCGTApplicable() {
4551
+ return this.create(this.items.filter((propertySale) => propertySale.isCGTApplicable()));
4521
4552
  }
4522
- isSold() {
4523
- return !!this.myShare.sale;
4553
+ getByPropertyShareIds(ids) {
4554
+ return this.filterBy('share.id', ids);
4524
4555
  }
4556
+ }
4557
+
4558
+ class PropertyCollection extends Collection {
4525
4559
  /**
4526
- * Get initials of property. Required by Photoable interface
4560
+ * Get new property collection filtered by category id
4561
+ * @param id id of category for filter
4527
4562
  */
4528
- getPhotoPlaceholder() {
4529
- return this.name.split(' ')[1].slice(0, 2);
4563
+ getByCategoryId(id) {
4564
+ return new PropertyCollection(this.items.filter((property) => property.category.id === id));
4530
4565
  }
4531
4566
  /**
4532
- * Get property photo. Required by Photoable interface
4567
+ * Get new property collection filtered by active status
4533
4568
  */
4534
- getPhoto() {
4535
- return this.photo;
4569
+ getActiveProperties() {
4570
+ return new PropertyCollection(this.items.filter((property) => property.isActive));
4536
4571
  }
4537
- get capitalCostsTotalAmount() {
4538
- return this.stampDuty + this.legalFees + this.otherCapitalCosts;
4572
+ getCreatedProperties() {
4573
+ return new PropertyCollection(this.items.filter((property) => property.isOwn()));
4539
4574
  }
4540
- get currentYearValuations() {
4541
- return this.valuations.filter((valuation) => valuation.isCurrentYear());
4575
+ /**
4576
+ * Get new property collection filtered by shared
4577
+ */
4578
+ getSharedProperties() {
4579
+ return new PropertyCollection(this.items.filter((property) => !property.isOwn()));
4542
4580
  }
4543
- get marketValue() {
4544
- var _a;
4545
- return ((_a = this.actualValuation) === null || _a === void 0 ? void 0 : _a.marketValue) || 0;
4581
+ /**
4582
+ * Properties that are taxed and will be included in reports (Tax summary, My tax report, e.t.c.)
4583
+ */
4584
+ getTaxInclusive() {
4585
+ return this.create(this.items.filter((property) => property.category.isTaxInclusive));
4546
4586
  }
4547
- get currentYearForecast() {
4548
- return this.forecasts.find((forecast) => forecast.isCurrentYear());
4587
+ getUnsold() {
4588
+ return this.create(this.items.filter((property) => !property.isSold()));
4549
4589
  }
4550
- get forecastedRentalReturn() {
4551
- var _a;
4552
- return ((_a = this.currentYearForecast) === null || _a === void 0 ? void 0 : _a.rentalReturn) || 0;
4590
+ /**
4591
+ * Get total purchase price for all properties in the collection
4592
+ */
4593
+ get purchasePrice() {
4594
+ return this.sumBy('purchasePrice');
4553
4595
  }
4554
- get forecastedTaxPosition() {
4555
- var _a;
4556
- return ((_a = this.currentYearForecast) === null || _a === void 0 ? void 0 : _a.taxPosition) || 0;
4596
+ get growthPercent() {
4597
+ return this.sumBy('growthPercent');
4557
4598
  }
4558
- get forecastedCashPosition() {
4559
- var _a;
4560
- return ((_a = this.currentYearForecast) === null || _a === void 0 ? void 0 : _a.cashPosition) || 0;
4599
+ get marketValue() {
4600
+ return this.sumBy('marketValue');
4561
4601
  }
4562
4602
  get firstForecastYear() {
4563
- return this.forecasts.reduce((min, forecast) => {
4564
- return min > forecast.financialYear ? forecast.financialYear : min;
4603
+ return this.items.reduce((min, property) => {
4604
+ const current = property.firstForecastYear;
4605
+ return min > current ? current : min;
4565
4606
  }, new FinancialYear().year);
4566
4607
  }
4567
4608
  get marketValueGrowth() {
4568
- return (this.marketValue - this.purchasePrice) / this.marketValue;
4609
+ return (this.marketValue - this.purchasePrice) / this.purchasePrice;
4569
4610
  }
4570
- get myShare() {
4571
- return this.shares.find((share) => share.user.id === +localStorage.getItem('userId'));
4611
+ /**
4612
+ * list of properties
4613
+ */
4614
+ getCGTApplicable() {
4615
+ return this.create(this.items.filter((property) => property.isCGTApplicable()));
4572
4616
  }
4573
- get actualValuation() {
4574
- return this.valuations.reduce((maxDateValuation, valuation) => {
4575
- return maxDateValuation.date > valuation.date ? maxDateValuation : valuation;
4576
- }, this.valuations[0]);
4617
+ getOwnerOccupiedProperties() {
4618
+ return new PropertyCollection(this.items.filter((property) => property.category.isOwnerOccupied()));
4577
4619
  }
4578
- get claimPercent() {
4579
- return this.currentYearForecast.claimPercent;
4620
+ get earliestContractDate() {
4621
+ return this.items.reduce((min, property) => {
4622
+ return min < property.contractDate ? min : property.contractDate;
4623
+ }, new FinancialYear(new Date()).startDate);
4580
4624
  }
4581
- get claimCoefficient() {
4582
- return this.claimPercent / 100;
4625
+ /**
4626
+ * Get list of unique property categories from collection
4627
+ */
4628
+ getCategories() {
4629
+ return uniqBy(this.items.map((property) => property.category), 'id');
4583
4630
  }
4584
- get sharePercent() {
4585
- return this.myShare.percent;
4631
+ /**
4632
+ * Get property with the highest growth percent
4633
+ */
4634
+ getBestPerformanceGrowthProperty() {
4635
+ return this.items.reduce((max, current) => {
4636
+ return max.growthPercent < current.growthPercent ? current : max;
4637
+ }, this.first);
4586
4638
  }
4587
- get shareRatio() {
4588
- return this.myShare.percent / 100;
4639
+ /**
4640
+ * Get property with the lowest tax position
4641
+ */
4642
+ getBestPerformanceTaxProperty(transactions, depreciations) {
4643
+ const transactionsByProperty = transactions.groupBy('property.id');
4644
+ const depreciationsByProperty = depreciations.groupBy('property.id');
4645
+ return this.items.reduce((min, current) => {
4646
+ const minTaxPosition = min.getTaxPosition(transactionsByProperty.get(min.id), depreciationsByProperty.get(min.id));
4647
+ const currentTaxPosition = current.getTaxPosition(transactionsByProperty.get(current.id), depreciationsByProperty.get(current.id));
4648
+ return minTaxPosition > currentTaxPosition ? current : min;
4649
+ }, this.first);
4589
4650
  }
4590
- get previousCategory() {
4591
- let previousCategory;
4592
- const movementsCount = this.categoryMovements.length;
4593
- if (movementsCount > 1) {
4594
- previousCategory = this.categoryMovements[movementsCount - 2].propertyCategory;
4651
+ /**
4652
+ * Show best performance properties first
4653
+ * https://taxtank.atlassian.net/wiki/spaces/TAXTANK/pages/217677997/Property+Tank+Dashboard
4654
+ */
4655
+ sortByBestPerformance(transactions, depreciations) {
4656
+ const activeProperties = this.getActiveProperties();
4657
+ // nothing to sort when no active properties
4658
+ if (!activeProperties.length) {
4659
+ return this;
4595
4660
  }
4596
- return previousCategory;
4661
+ const bestProperties = uniqBy(this.create([
4662
+ activeProperties.getBestPerformanceGrowthProperty(),
4663
+ activeProperties.getBestPerformanceTaxProperty(transactions, depreciations)
4664
+ ]).toArray(), 'id');
4665
+ const newItems = this.remove(bestProperties).toArray();
4666
+ newItems.unshift(...bestProperties);
4667
+ return this.create(newItems);
4597
4668
  }
4598
- getCurrentSubscription() {
4599
- // always return first element because subscriptions array contains only one element
4600
- return this.subscriptions[0];
4669
+ }
4670
+
4671
+ class PropertyCategoryMovementCollection extends Collection {
4672
+ /**
4673
+ * @TODO TT-2355 Alex refactor propertyForecast, use separated api (then I can remove property from param)
4674
+ */
4675
+ getByForecast(property, forecast) {
4676
+ const financialYear = new FinancialYear(forecast.financialYear);
4677
+ return this.filterBy('property.id', property.id).filter((movement) => {
4678
+ return movement.fromDate <= financialYear.endDate && !movement.toDate || movement.toDate >= financialYear.startDate;
4679
+ });
4601
4680
  }
4602
- getForecastByYear(year) {
4603
- return this.forecasts.find((forecast) => forecast.financialYear === year);
4681
+ hasCategory(categoryId) {
4682
+ return !!this.findBy('propertyCategory.id', categoryId);
4604
4683
  }
4605
- get isShared() {
4606
- return this.shares.length > 1;
4684
+ }
4685
+
4686
+ class VehicleClaimCollection extends Collection {
4687
+ /**
4688
+ * Get remaining kilometers limit. Total limit ({@link VehicleClaim.totalKmsLimit}) - claimed kilometers from other vehicle claims
4689
+ */
4690
+ getKmsLimitForClaim(claim) {
4691
+ let collection = this;
4692
+ if (claim) {
4693
+ collection = collection.removeBy('id', claim.id);
4694
+ }
4695
+ return VehicleClaim.totalKmsLimit - collection.sumBy('kilometers');
4607
4696
  }
4608
4697
  /**
4609
- * @TODO consider to move methods related with propertySale to separated class, since used just in one module yet
4610
- * purchase costs - claimed costs, except `ppr to investment` exemption,
4611
- * in that case it's equal to market value, when property became an investment property
4698
+ * Get remaining work usage limit. Total limit ({@link VehicleClaim.totalWorkUsagePercent}) - claimed percent from other vehicle claims
4612
4699
  */
4613
- calculateCostBase(sale) {
4614
- const marketValue = new PropertySaleTaxExemptionMetadataCollection(sale.taxExemptionMetadata).getMarketValue();
4615
- if (marketValue) {
4616
- return marketValue;
4700
+ getWorkUsageLimitForClaim(claim) {
4701
+ let collection = this;
4702
+ if (claim) {
4703
+ collection = collection.removeBy('id', claim.id);
4617
4704
  }
4618
- return this.purchasePrice + this.capitalCostsTotalAmount + sale.holdingCosts + sale.structuralImprovementsWDV - sale.buildingAtCostClaimed;
4705
+ return VehicleClaim.totalWorkUsagePercent - collection.sumBy('workUsage');
4619
4706
  }
4707
+ }
4708
+
4709
+ class VehicleLogbookCollection extends Collection {
4620
4710
  /**
4621
- * gross capital gain tax: sale costs - cost base
4711
+ * Best period may be calculated only when user has logbooks minimum for VehicleLogbook.bestPeriodWeeks
4712
+ * @TODO Vik: Best period: move this and related logic to backend
4622
4713
  */
4623
- calculateCGT(sale) {
4624
- return (sale.price - sale.saleCostsTotalAmount - this.calculateCostBase(sale)) * this.shareRatio - sale.capitalLoss;
4714
+ isBestPeriodExist() {
4715
+ if (this.items.length < 2) {
4716
+ return false;
4717
+ }
4718
+ return VehicleLogbook.bestPeriodDuration < (this.last.date.getTime() - this.first.date.getTime());
4625
4719
  }
4626
4720
  /**
4627
- * net capital gain tax (includes tax exemptions)
4721
+ * Get collection of non-personal logbooks (work-related, sole-related).
4722
+ * @TODO Vik: Best period: move this and related logic to backend
4628
4723
  */
4629
- calculateNetCGT(sale) {
4630
- return this.getCGTExemptionRatio(sale) * sale.grossCGT;
4724
+ getClaimableLogbooks() {
4725
+ return this.filterBy('isPersonal', false);
4631
4726
  }
4632
4727
  /**
4633
- * guess tax exemption based on property details
4728
+ * Get Logbook Period with the biggest work usage percent
4729
+ * Best period duration is defined as VehicleLogbook.bestPeriodWeeks by the ATO
4730
+ * @TODO Vik: Best period: move this and related logic to backend
4634
4731
  */
4635
- getCGTExemption(sale) {
4636
- if (sale.taxExemption) {
4637
- return sale.taxExemption.id;
4638
- }
4639
- switch (true) {
4640
- // exemption for main residence properties
4641
- case this.category.id === PropertyCategoryListEnum.OWNER_OCCUPIED:
4642
- return TaxExemptionEnum.PPR;
4643
- // exemption for investment properties owned for at least one year
4644
- case this.isOneYearExemptionApplicable(sale):
4645
- return TaxExemptionEnum.ONE_YEAR_RULE;
4646
- default:
4647
- return null;
4732
+ getBestPeriod() {
4733
+ if (!this.isBestPeriodExist()) {
4734
+ return null;
4648
4735
  }
4649
- }
4650
- /**
4651
- * tax exemption can reduce cgt from 100% to less (up to zero)
4652
- */
4653
- getCGTExemptionRatio(sale) {
4654
- var _a;
4655
- const metadata = new PropertySaleTaxExemptionMetadataCollection(sale.taxExemptionMetadata);
4656
- switch ((_a = sale.taxExemption) === null || _a === void 0 ? void 0 : _a.id) {
4657
- // 50% exemption for investments owned for at least one year
4658
- case TaxExemptionEnum.ONE_YEAR_RULE:
4659
- return 0.5;
4660
- // investment property become main residence (exemption for main residence ownership duration)
4661
- case TaxExemptionEnum.INVESTMENT_TO_PPR:
4662
- const ownershipDays = this.getOwnershipDuration(sale);
4663
- return (ownershipDays - metadata.getPPRDays()) / ownershipDays;
4664
- // main residence become investment (exemption for home office percent usage)
4665
- case TaxExemptionEnum.PPR_TO_INVESTMENT:
4666
- // 1 year CGT discount can still apply (on the income producing % if used for 12 months or more)
4667
- const ratio = this.isOneYearExemptionApplicable(sale) ? 0.5 : 1;
4668
- return metadata.getClaimPercent() / 100 * ratio;
4669
- // full exemption
4670
- case TaxExemptionEnum.PPR:
4671
- case TaxExemptionEnum.SIX_YEARS_RULE:
4672
- case TaxExemptionEnum.TRANSFER:
4673
- case TaxExemptionEnum.OTHER:
4674
- return 0;
4675
- // no exemption
4676
- default:
4677
- return 1;
4736
+ let bestPeriod;
4737
+ // get list of all logbooks available for best period calculation
4738
+ const claimableLogbooks = this.getClaimableLogbooks().toArray();
4739
+ for (let i = 0; i < claimableLogbooks.length; i++) {
4740
+ // no sense to check next logbooks because we already get the end of the year
4741
+ if (bestPeriod && bestPeriod.isEndOfYear()) {
4742
+ break;
4743
+ }
4744
+ // get date range started from current handling logbook date
4745
+ const dateRange = claimableLogbooks[i].getPeriod();
4746
+ // get all logbooks included in current logbook period
4747
+ const logbooksInRange = this.filterByRange('date', dateRange.start, dateRange.end);
4748
+ const currentPeriod = plainToClass(LogbookPeriod, {
4749
+ from: dateRange.start,
4750
+ to: dateRange.end,
4751
+ kilometers: logbooksInRange.getClaimableLogbooks().kilometers,
4752
+ workUsage: logbooksInRange.getWorkUsage(),
4753
+ logbooks: logbooksInRange
4754
+ });
4755
+ // compare with previous best period and overwrite if needs
4756
+ if (!bestPeriod || currentPeriod.workUsage > bestPeriod.workUsage) {
4757
+ bestPeriod = currentPeriod;
4758
+ }
4759
+ else if (currentPeriod.workUsage === bestPeriod.workUsage) {
4760
+ // if work usage is the same then get period with the biggest work usage for work tank
4761
+ const oldWorkUsage = bestPeriod.logbooks.filterBy('tankType', TankTypeEnum.WORK).getWorkUsage();
4762
+ const currentWorkUsage = currentPeriod.logbooks.filterBy('tankType', TankTypeEnum.WORK).getWorkUsage();
4763
+ if (oldWorkUsage < currentWorkUsage) {
4764
+ bestPeriod = currentPeriod;
4765
+ }
4766
+ }
4678
4767
  }
4679
- }
4680
- isOneYearExemptionApplicable(sale) {
4681
- return sale.grossCGT > 0 && this.getOwnershipDuration(sale, 'years') > 0;
4768
+ return bestPeriod;
4682
4769
  }
4683
4770
  /**
4684
- * CGT is not applicable for properties acquired before 20.09.1985 (tax didn't exist before this date).
4685
- * https://taxtank.atlassian.net/wiki/spaces/TAXTANK/pages/4644110466/Tax+Return+MyTax+-+Online+Form ("Capital gains or losses" section)
4771
+ * Calculate total kilometers traveled
4686
4772
  */
4687
- isCGTApplicable() {
4688
- return this.contractDate >= Property.preCGTAssetDate;
4773
+ get kilometers() {
4774
+ return this.sumBy('kilometers');
4689
4775
  }
4690
4776
  /**
4691
- * ownership duration from purchase till sale
4777
+ * Calculate work usage (percent of business-related kilometers from total kilometers)
4778
+ * @TODO Alex: TT-2089 replace with getter
4692
4779
  */
4693
- getOwnershipDuration(sale, unitOfTime = 'days') {
4694
- return moment$1(sale.contractDate).diff(moment$1(this.contractDate), unitOfTime);
4780
+ getWorkUsage() {
4781
+ const workKilometers = this.getClaimableLogbooks().kilometers;
4782
+ return Math.round(workKilometers / this.kilometers * 100);
4695
4783
  }
4696
4784
  /**
4697
- * Tax Position = Income - Expense - Interest - Depreciation
4698
- * Where (Income - Expense - Interest) is cash position.
4699
- * https://taxtank.atlassian.net/wiki/spaces/TAXTANK/pages/217415928/Dashboard+Property
4785
+ * Get list of logbooks related to passed vehicle claim
4700
4786
  */
4701
- getTaxPosition(transactions, depreciations) {
4702
- return transactions.grossClaimAmount - Math.abs(depreciations.claimAmount);
4787
+ getByVehicleClaim(vehicleClaim) {
4788
+ return vehicleClaim.isSoleTank()
4789
+ // sole tank may have multiple vehicle claims, so we need to filter by business.id
4790
+ ? this.filterBy('business.id', vehicleClaim.business.id)
4791
+ // work tank may have only one vehicle claim, so we need to filter by tank type
4792
+ : this.filterBy('tankType', TankTypeEnum.WORK);
4703
4793
  }
4704
4794
  }
4795
+
4705
4796
  /**
4706
- * Property acquired before 20 September 1985 will generally be treated as pre-Capital Gains Tax (CGT) assets.
4707
- * Any assets acquired before this day are CGT exempt (because the tax didn't exist before this date).
4797
+ * List of objects grouped by passed property
4708
4798
  */
4709
- Property.preCGTAssetDate = new Date(1985, 9, 20);
4710
- __decorate([
4711
- Type(() => Date)
4712
- ], Property.prototype, "contractDate", void 0);
4713
- __decorate([
4714
- Type(() => Date)
4715
- ], Property.prototype, "settlementDate", void 0);
4716
- __decorate([
4717
- Type(() => Address)
4718
- ], Property.prototype, "address", void 0);
4719
- __decorate([
4720
- Type(() => PropertyCategory)
4721
- ], Property.prototype, "category", void 0);
4722
- __decorate([
4723
- Type(() => PropertyValuation)
4724
- ], Property.prototype, "valuations", void 0);
4725
- __decorate([
4726
- Type(() => PropertyForecast)
4727
- ], Property.prototype, "forecasts", void 0);
4728
- __decorate([
4729
- Type(() => PropertyCategoryMovement)
4730
- ], Property.prototype, "categoryMovements", void 0);
4731
- __decorate([
4732
- Type(() => User)
4733
- ], Property.prototype, "user", void 0);
4734
- __decorate([
4735
- Type(() => PropertySubscription)
4736
- ], Property.prototype, "subscriptions", void 0);
4737
- __decorate([
4738
- Exclude()
4739
- ], Property.prototype, "documentFile", void 0);
4740
-
4741
- class BankAccountProperty extends BankAccountProperty$1 {
4742
- }
4743
- __decorate([
4744
- Type(() => Property)
4745
- ], BankAccountProperty.prototype, "property", void 0);
4746
- __decorate([
4747
- Transform(({ value }) => value || 100),
4748
- Expose()
4749
- ], BankAccountProperty.prototype, "percent", void 0);
4750
-
4751
- class BankConnection$1 extends AbstractModel {
4799
+ class Dictionary {
4800
+ constructor(items, path = 'id') {
4801
+ this.items = {};
4802
+ if (!items.length) {
4803
+ return;
4804
+ }
4805
+ // Do nothing if provided path was not found in the 1st item
4806
+ if (!hasIn(items[0], path.split('.')[0])) {
4807
+ return;
4808
+ }
4809
+ this.groupItems(items, path);
4810
+ }
4811
+ add(key, value) {
4812
+ this.items[key] = value;
4813
+ }
4814
+ get(key) {
4815
+ return this.items[key] !== undefined ? this.items[key] : null;
4816
+ }
4817
+ groupItems(items, path) {
4818
+ items.forEach((item) => {
4819
+ let key = get(item, path);
4820
+ // if object does not have property for grouping it will be grouped as 'other'
4821
+ if (key === undefined) {
4822
+ key = 'other';
4823
+ }
4824
+ this.items[key] = item;
4825
+ });
4826
+ }
4752
4827
  }
4753
4828
 
4754
- var BankConnectionStatusEnum;
4755
- (function (BankConnectionStatusEnum) {
4756
- BankConnectionStatusEnum[BankConnectionStatusEnum["PENDING"] = 1] = "PENDING";
4757
- BankConnectionStatusEnum[BankConnectionStatusEnum["ACTIVE"] = 2] = "ACTIVE";
4758
- BankConnectionStatusEnum[BankConnectionStatusEnum["INVALID"] = 3] = "INVALID";
4759
- })(BankConnectionStatusEnum || (BankConnectionStatusEnum = {}));
4760
-
4761
- class BankConnection extends BankConnection$1 {
4829
+ class SoleBusinessLossesCollection extends Collection {
4762
4830
  /**
4763
- * Check if status of connection is inactive (invalid)
4831
+ * Business loss applied in current year, includes previous year losses and current year losses for businesses matching offset rule
4764
4832
  */
4765
- isInvalid() {
4766
- return this.status === BankConnectionStatusEnum.INVALID;
4767
- }
4768
- isPending() {
4769
- return this.status === BankConnectionStatusEnum.PENDING;
4770
- }
4771
- isActive() {
4772
- return this.status === BankConnectionStatusEnum.ACTIVE;
4833
+ calculateBusinessLossApplied(transactions) {
4834
+ // claim amounts for businesses that can be applied to be reduced by prior year business losses
4835
+ const claimAmountsByBusinessId = this.getClaimAmountsByBusinessId(transactions);
4836
+ return Object.keys(claimAmountsByBusinessId.items).reduce((sum, businessId) => {
4837
+ const loss = this.findBy('business.id', +businessId);
4838
+ const lossOpenBalance = (loss === null || loss === void 0 ? void 0 : loss.openBalance) || 0;
4839
+ // business loss can be applied to business profit or other income types profit in case in offset rule met
4840
+ return sum + ((loss === null || loss === void 0 ? void 0 : loss.offsetRule) ? lossOpenBalance : Math.min(lossOpenBalance, claimAmountsByBusinessId.get(businessId)));
4841
+ }, 0);
4773
4842
  }
4774
4843
  /**
4775
- * login required for new or disconnected external connections
4844
+ * Get business claim amounts that can be applied to be reduced by prior year business losses:
4845
+ * businesses with income or businesses with a loss, but which met the non-commercial loss rules
4846
+ * https://www.ato.gov.au/Business/Non-commercial-losses/
4776
4847
  */
4777
- isLoginRequired() {
4778
- return !!(!this.id && this.bank.externalId && !this.bank.isManual) || this.isInvalid();
4779
- }
4780
- setPending() {
4781
- this.status = BankConnectionStatusEnum.PENDING;
4848
+ getClaimAmountsByBusinessId(transactions) {
4849
+ const claimAmountsByBusinessId = new Dictionary([]);
4850
+ const transactionsByBusinessId = new CollectionDictionary(transactions, 'business.id');
4851
+ transactionsByBusinessId.keys.forEach((businessId) => {
4852
+ var _a;
4853
+ // business loss may not exist if, when creating a business, user didn't add losses for previous years
4854
+ const lossOffsetRule = (_a = this.findBy('business.id', +businessId)) === null || _a === void 0 ? void 0 : _a.offsetRule;
4855
+ const businessClaimAmount = transactionsByBusinessId
4856
+ .get(businessId)
4857
+ .getClaimAmountByBusinessId(+businessId);
4858
+ // no way to apply loss for business without profit if offset rules not met
4859
+ if (businessClaimAmount < 0 && !lossOffsetRule) {
4860
+ return;
4861
+ }
4862
+ claimAmountsByBusinessId.add(businessId, businessClaimAmount);
4863
+ });
4864
+ return claimAmountsByBusinessId;
4782
4865
  }
4783
4866
  }
4784
- __decorate([
4785
- Type(() => BasiqJob)
4786
- ], BankConnection.prototype, "basiqJob", void 0);
4787
- __decorate([
4788
- Type(() => Bank)
4789
- ], BankConnection.prototype, "bank", void 0);
4790
4867
 
4791
- class BankAccount extends BankAccount$1 {
4792
- get bank() {
4793
- return this.bankConnection.bank;
4794
- }
4795
- get bsb() {
4796
- return this.accountNumber.split(' ')[0];
4868
+ class SoleInvoiceCollection extends Collection {
4869
+ getOverdue() {
4870
+ return this.filter((invoice) => invoice.isOverdue());
4797
4871
  }
4798
- get number() {
4799
- return this.accountNumber.split(' ')[1];
4872
+ getUnpaid() {
4873
+ return this.filter((invoice) => invoice.isUnpaid());
4800
4874
  }
4801
- /**
4802
- * Get last digits of account number
4803
- */
4804
- get partialAccountNumber() {
4805
- return `xxxx${this.accountNumber.slice(-4)}`;
4875
+ getPaid() {
4876
+ return this.filter((invoice) => invoice.isPaid());
4806
4877
  }
4807
- /**
4808
- * Get current opening balance amount
4809
- */
4810
- getOpeningBalance() {
4811
- var _a;
4812
- return ((_a = this.getCurrentYearBalance()) === null || _a === void 0 ? void 0 : _a.openingBalance) || 0;
4878
+ getPending() {
4879
+ return this.filter((invoice) => invoice.isPending());
4813
4880
  }
4814
- /**
4815
- * Get bank account balance for current financial year
4816
- */
4817
- getCurrentYearBalance() {
4818
- const currentFinYear = new FinancialYear().year;
4819
- return this.balances.find((balance) => balance.financialYear === currentFinYear);
4881
+ getTransactionsIds() {
4882
+ return flatten(this.items.map((invoice) => invoice.getTransactionsIds()));
4820
4883
  }
4884
+ }
4885
+
4886
+ /**
4887
+ * Chart serie class: chart data item
4888
+ * @TODO consider rename to ChartSerieData
4889
+ */
4890
+ class ChartSerie {
4891
+ }
4892
+
4893
+ /**
4894
+ * Chart data class
4895
+ * @TODO consider rename to ChartSerie
4896
+ */
4897
+ class ChartData {
4898
+ }
4899
+ __decorate([
4900
+ Type(() => ChartSerie)
4901
+ ], ChartData.prototype, "data", void 0);
4902
+
4903
+ const MONTHS = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec', 'Jan'];
4904
+
4905
+ /**
4906
+ * @TODO extend from TransactionBaseCollection
4907
+ * Collection of transactions
4908
+ */
4909
+ class TransactionCollection extends ExportableCollection {
4821
4910
  /**
4822
- * check if bank account type is one of savings accounts
4911
+ * @TODO use TransactionBaseCollection instead
4912
+ * we use depreciations as expense transactions a lot
4823
4913
  */
4824
- isSavingsAccount() {
4825
- return this.type === BankAccountTypeEnum.INVESTMENT ||
4826
- this.type === BankAccountTypeEnum.TERM_DEPOSIT ||
4827
- this.type === BankAccountTypeEnum.SAVINGS;
4914
+ constructor(transactions = [], depreciations = []) {
4915
+ super([...transactions, ...depreciations.map((depreciation) => depreciation.toTransaction())]);
4828
4916
  }
4829
- /**
4830
- * check if bank account type is Loan
4831
- */
4832
- isLoan() {
4833
- return this.type === BankAccountTypeEnum.LOAN;
4917
+ getSoleTransactions() {
4918
+ return this.filter((transaction) => transaction.isSoleTank());
4919
+ }
4920
+ get amount() {
4921
+ return this.sumBy('amount');
4834
4922
  }
4835
4923
  /**
4836
- * check if bank account type is Credit card
4924
+ * Difference between allocated amount and total amount
4837
4925
  */
4838
- isCreditCard() {
4839
- return this.type === BankAccountTypeEnum.CREDIT_CARD;
4926
+ getUnallocatedAmount(allocations) {
4927
+ return this.items.reduce((sum, transaction) => {
4928
+ return sum + transaction.getUnallocatedAmount(allocations.filterBy('transaction.id', transaction.id));
4929
+ }, 0);
4840
4930
  }
4841
4931
  /**
4842
- * check if bank account related to work tank
4932
+ * get date of the last transaction
4843
4933
  */
4844
- isWorkTank() {
4845
- return !this.isPropertyTank() && !this.isSoleTank();
4934
+ getLastTransactionDate() {
4935
+ return new Date(Math.max.apply(Math, this.items.map((transaction) => transaction.date)));
4936
+ }
4937
+ get claimAmount() {
4938
+ return this.items.reduce((sum, transaction) => sum + transaction.claimAmount, 0);
4939
+ }
4940
+ get grossClaimAmount() {
4941
+ return this.items.reduce((sum, transaction) => sum + transaction.grossClaimAmount, 0);
4942
+ }
4943
+ get grossAmount() {
4944
+ return this.items.reduce((sum, transaction) => sum + transaction.grossAmount, 0);
4945
+ }
4946
+ getByChartAccountsCategories(categories) {
4947
+ return new TransactionCollection(this.items.filter((transaction) => categories.includes(transaction.chartAccounts.category)));
4846
4948
  }
4847
4949
  /**
4848
- * check if bank account related to work tank
4950
+ * Get transactions by month
4951
+ * @param monthIndex by which desired month should be taken
4849
4952
  */
4850
- isPropertyTank() {
4851
- return !!this.bankAccountProperties.length;
4953
+ getByMonth(monthIndex) {
4954
+ return new TransactionCollection(this.items.filter((transaction) => transaction.date.getMonth() === monthIndex));
4852
4955
  }
4853
4956
  /**
4854
- * check if bank account related to sole tank
4957
+ * Get collection of transactions metadata
4855
4958
  */
4856
- isSoleTank() {
4857
- return !!this.businessAllocations.length;
4959
+ getTransactionsMetadata() {
4960
+ const metadataArray = [];
4961
+ this.items.forEach((transaction) => {
4962
+ metadataArray.push(...transaction.metadata);
4963
+ });
4964
+ return new Collection(metadataArray);
4858
4965
  }
4859
- get tankType() {
4860
- switch (true) {
4861
- case this.isPropertyTank():
4862
- return TankTypeEnum.PROPERTY;
4863
- case this.isSoleTank():
4864
- return TankTypeEnum.SOLE;
4865
- default:
4866
- return TankTypeEnum.WORK;
4867
- }
4966
+ getIncomeTransactions() {
4967
+ return new TransactionCollection(this.items.filter((transaction) => transaction.isIncome()));
4968
+ }
4969
+ getExpenseTransactions() {
4970
+ return new TransactionCollection(this.items.filter((transaction) => transaction.isExpense() && !transaction.isInterest()));
4971
+ }
4972
+ get claimIncome() {
4973
+ return this.getIncomeTransactions().claimAmount;
4974
+ }
4975
+ get claimExpense() {
4976
+ return this.getExpenseTransactions().claimAmount;
4977
+ }
4978
+ getInterestTransactions() {
4979
+ return new TransactionCollection(this.items.filter((transaction) => transaction.isInterest()));
4980
+ }
4981
+ get claimInterest() {
4982
+ return this.getInterestTransactions().claimAmount;
4868
4983
  }
4869
4984
  /**
4870
- * Get Bank account property by id
4871
- * @param id Id of property
4985
+ * Get collection of transactions and properties filtered by properties ids
4986
+ * @param ids Ids of properties for filter
4872
4987
  */
4873
- getPropertyById(id) {
4874
- return this.bankAccountProperties.find((bankAccountProperty) => bankAccountProperty.property.id === id);
4988
+ getByPropertiesIds(ids) {
4989
+ return new TransactionCollection(this.items.filter((transaction) => {
4990
+ var _a;
4991
+ return ids.includes((_a = transaction.property) === null || _a === void 0 ? void 0 : _a.id);
4992
+ }));
4875
4993
  }
4876
4994
  /**
4877
- * check if bank account is related with passed property by id
4878
- * @param propertyId Property id for checking
4995
+ * Get new collection filtered by income source id
4996
+ * @param id id of income source for filter
4879
4997
  */
4880
- hasProperty(propertyId) {
4881
- return !!this.getPropertyById(propertyId);
4998
+ getByIncomeSourceId(id) {
4999
+ return new TransactionCollection(this.items.filter((transaction) => { var _a; return ((_a = transaction.incomeSource) === null || _a === void 0 ? void 0 : _a.id) === id; }));
4882
5000
  }
4883
5001
  /**
4884
- * Get decimal percentage for property
4885
- * @param propertyId Id of property
5002
+ * Get new collection filtered by chart accounts category
5003
+ * @param category Chart accounts category value
4886
5004
  */
4887
- getPropertyPercentage(propertyId) {
4888
- if (!this.hasProperty(propertyId)) {
4889
- return 0;
4890
- }
4891
- return this.getPropertyById(propertyId).percent / 100;
5005
+ getByChartAccountsCategory(category) {
5006
+ return new TransactionCollection(this.items.filter((transaction) => transaction.chartAccounts.category === category));
4892
5007
  }
4893
5008
  /**
4894
- * Get balance amount for property by id
4895
- * @param propertyId Id of property
5009
+ * Get new collection of property transactions
4896
5010
  */
4897
- getPropertyBalanceAmount(propertyId) {
4898
- return this.currentBalance * this.getPropertyPercentage(propertyId);
5011
+ getPropertyTransactions() {
5012
+ return new TransactionCollection(this.items.filter((transaction) => transaction.isPropertyTank()));
5013
+ }
5014
+ getDebitTransactions() {
5015
+ return new TransactionCollection(this.items.filter((transaction) => transaction.isDebit()));
5016
+ }
5017
+ getCreditTransactions() {
5018
+ return new TransactionCollection(this.items.filter((transaction) => transaction.isCredit()));
5019
+ }
5020
+ getByAllocations(allocations) {
5021
+ return new TransactionCollection(this.items.filter((transaction) => allocations.hasTransaction(transaction)));
4899
5022
  }
4900
5023
  /**
4901
- * Check if bank account is active (has 'active' status or hasn't been paid out/refinanced)
5024
+ * Get transactions related to Vehicle category
4902
5025
  */
4903
- isActive() {
4904
- return this.status === BankAccountStatusEnum.ACTIVE;
5026
+ getVehicleTransactions() {
5027
+ return this.create(this.items.filter((transaction) => {
5028
+ return transaction.isVehicleTransaction();
5029
+ }));
4905
5030
  }
4906
5031
  /**
4907
- * first import (transactions) of basiq accounts
5032
+ * Get new transaction collection filtered by tank type
4908
5033
  */
4909
- isFirstImport() {
4910
- return !this.lastTransactionDate && !this.isManual;
5034
+ getByTankType(tankType) {
5035
+ return this.create(this.items.filter((transaction) => {
5036
+ switch (tankType) {
5037
+ case TankTypeEnum.PROPERTY:
5038
+ return transaction.isPropertyTank();
5039
+ case TankTypeEnum.WORK:
5040
+ return transaction.isWorkTank();
5041
+ case TankTypeEnum.SOLE:
5042
+ return transaction.isSoleTank();
5043
+ // Transaction may be not related to any tank type (personal)
5044
+ default:
5045
+ return false;
5046
+ }
5047
+ }));
5048
+ }
5049
+ getExportHeader() {
5050
+ return ['Date', 'Description', 'Debit', 'Credit'];
5051
+ }
5052
+ getExportFooter() {
5053
+ return [
5054
+ plainToClass(ExportCell, { value: 'Total', type: ExportCellTypeEnum.STRING }),
5055
+ plainToClass(ExportCell, { value: '', type: ExportCellTypeEnum.STRING }),
5056
+ plainToClass(ExportCell, { value: this.sumBy('debit'), type: ExportCellTypeEnum.CURRENCY }),
5057
+ plainToClass(ExportCell, { value: this.sumBy('credit'), type: ExportCellTypeEnum.CURRENCY })
5058
+ ];
5059
+ }
5060
+ getExportBody() {
5061
+ return this.items.map((transaction) => {
5062
+ return [
5063
+ plainToClass(ExportCell, { value: transaction.date, type: ExportCellTypeEnum.DATE }),
5064
+ plainToClass(ExportCell, { value: transaction.description, type: ExportCellTypeEnum.STRING }),
5065
+ plainToClass(ExportCell, { value: transaction.debit, type: ExportCellTypeEnum.CURRENCY }),
5066
+ plainToClass(ExportCell, { value: transaction.credit, type: ExportCellTypeEnum.CURRENCY })
5067
+ ];
5068
+ });
4911
5069
  }
4912
5070
  /**
4913
- * Check if passed user id is owner of bank account
5071
+ * Get list of vehicle transactions filtered by vehicle claim
4914
5072
  */
4915
- isOwner(userId) {
4916
- return this.bankConnection.user.id === userId;
5073
+ getByVehicleClaim(vehicleClaim) {
5074
+ if (!vehicleClaim) {
5075
+ return this.create([]);
5076
+ }
5077
+ return vehicleClaim.isSoleTank()
5078
+ // sole tank may have multiple vehicle claims, so we need to filter by business.id
5079
+ ? this.getVehicleTransactions().filterBy('business.id', vehicleClaim.business.id)
5080
+ // work tank may have only one vehicle claim, so we need to filter by tank type
5081
+ : this.getVehicleTransactions().filterBy('tankType', TankTypeEnum.WORK);
4917
5082
  }
4918
5083
  /**
4919
- * Loan is paid if it has no unallocated transactions and the bank balance is $0.
5084
+ * Get list of vehicle transactions except KMS transactions
4920
5085
  */
4921
- isLoanPaid(taxTankBalance) {
4922
- const shouldPayoutLoanAccount = this.isActive() && this.isLoan() && taxTankBalance === 0;
4923
- // we don't check current balance for basiq accounts, because basiq doesn't provide us last transactions (can't do for closed accounts),
4924
- // that's why balance won't be 0 (updated by basiq)
4925
- if (shouldPayoutLoanAccount && this.isManual) {
4926
- return this.currentBalance === 0;
4927
- }
4928
- return shouldPayoutLoanAccount;
5086
+ getLogbookTransactions() {
5087
+ return this
5088
+ .getVehicleTransactions()
5089
+ .removeBy('chartAccounts.id', [ChartAccountsListEnum.KLMS_TRAVELLED_FOR_WORK, ChartAccountsListEnum.KLMS_TRAVELLED]);
4929
5090
  }
4930
- }
4931
- __decorate([
4932
- Type(() => BankAccountProperty)
4933
- ], BankAccount.prototype, "bankAccountProperties", void 0);
4934
- __decorate([
4935
- Type(() => SoleBusinessAllocation)
4936
- ], BankAccount.prototype, "businessAllocations", void 0);
4937
- __decorate([
4938
- Type(() => BankAccountBalance)
4939
- ], BankAccount.prototype, "balances", void 0);
4940
- __decorate([
4941
- Type(() => Loan)
4942
- ], BankAccount.prototype, "loan", void 0);
4943
- __decorate([
4944
- Type(() => BankConnection)
4945
- ], BankAccount.prototype, "bankConnection", void 0);
4946
- __decorate([
4947
- Transform(({ value }) => value === 4 ? BankAccountTypeEnum.LOAN : value)
4948
- ], BankAccount.prototype, "type", void 0);
5091
+ /**
5092
+ * Build chart data with transactions cash position.
5093
+ * Cash position = Income - Expenses (include depreciations)
5094
+ * Chart data for each month from fin year start till current month
5095
+ */
5096
+ getCashPositionChartData() {
5097
+ const chartData = [
5098
+ plainToClass(ChartData, { name: 'Income', data: [] }),
5099
+ plainToClass(ChartData, { name: 'Expense', data: [] })
5100
+ ];
5101
+ new FinancialYear().getPastMonths().forEach((month) => {
5102
+ chartData[0].data.push({
5103
+ label: MONTHS[month],
5104
+ value: this.getIncomeTransactions().getByMonth(month).claimAmount
5105
+ });
5106
+ chartData[1].data.push({
5107
+ label: MONTHS[month],
5108
+ value: Math.abs(this.getExpenseTransactions().getByMonth(month).claimAmount)
5109
+ });
5110
+ });
5111
+ return chartData;
5112
+ }
5113
+ /**
5114
+ * user pays GST only from allocated part (or paid) of income
5115
+ */
5116
+ calculateAllocatedClaimAmount(allocations) {
5117
+ let allocatedClaimAmount = 0;
5118
+ this.filterBy('isGST', true).toArray().forEach((transaction) => {
5119
+ allocatedClaimAmount += transaction.getAllocatedClaimAmount(allocations);
5120
+ });
5121
+ return allocatedClaimAmount;
5122
+ }
5123
+ calculateAllocatedGST(allocations) {
5124
+ return this.calculateAllocatedClaimAmount(allocations) * ChartAccounts.GSTRatio;
5125
+ }
5126
+ getAllocatedAmount(allocations) {
5127
+ return allocations.getByTransactionsIds(this.getIds()).sumBy('amount');
5128
+ }
5129
+ }
4949
5130
 
4950
- /**
4951
- * bank account collection UI class with frontend specific data
4952
- */
4953
- class BankAccountChartData {
4954
- constructor(bankAccounts) {
4955
- this.bankAccounts = bankAccounts;
5131
+ class TransactionAllocationCollection extends Collection {
5132
+ get amount() {
5133
+ return this.sumBy('amount');
5134
+ }
5135
+ getByTransactionsIds(ids) {
5136
+ return new TransactionAllocationCollection(this.items.filter((allocation) => ids.includes(allocation.transaction.id)));
5137
+ }
5138
+ getByBankTransactionsIds(ids) {
5139
+ return new TransactionAllocationCollection(this.items.filter((allocation) => ids.includes(allocation.bankTransaction.id)));
4956
5140
  }
4957
5141
  /**
4958
- * set value of pie chart data
5142
+ * Group allocations by bank account via bank transactions collection
4959
5143
  */
4960
- getBalancePieChartData() {
4961
- return this.bankAccounts.map((bankAccount) => {
4962
- return {
4963
- name: bankAccount.accountName,
4964
- data: Math.abs(bankAccount.currentBalance)
4965
- };
5144
+ groupByBankAccount(bankTransactions) {
5145
+ // Group bank transactions by bank account id
5146
+ const bankTransactionsByBankAccount = new CollectionDictionary(bankTransactions, 'bankAccount.id');
5147
+ // Create empty dictionary of transaction allocations
5148
+ const allocationsByBankAccount = new CollectionDictionary(new TransactionAllocationCollection([]));
5149
+ // Fill allocations dictionary with bank transactions dictionary keys and allocations related with each bank transaction collection
5150
+ bankTransactionsByBankAccount.keys.forEach((key) => {
5151
+ allocationsByBankAccount.add(key, this.getByBankTransactionsIds(bankTransactionsByBankAccount.get(key).getIds()));
4966
5152
  });
5153
+ return allocationsByBankAccount;
4967
5154
  }
4968
5155
  /**
4969
- * set value of bar chart data
5156
+ * check if collection includes allocation of passed transaction
4970
5157
  */
4971
- getBalanceBarChartData() {
4972
- return [{
4973
- name: 'Balance',
4974
- data: this.bankAccounts.map((bankAccount) => {
4975
- return {
4976
- label: bankAccount.accountName,
4977
- value: bankAccount.currentBalance
4978
- };
4979
- })
4980
- }];
5158
+ hasTransaction(transaction) {
5159
+ return !!this.items.find((allocation) => allocation.transaction.id === transaction.id);
5160
+ }
5161
+ /**
5162
+ * Check if bank transaction is related with current allocations
5163
+ */
5164
+ hasBankTransaction(bankTransaction) {
5165
+ return !!this.items.find((allocation) => allocation.bankTransaction.id === bankTransaction.id);
4981
5166
  }
4982
5167
  }
4983
5168
 
4984
5169
  /**
4985
- * Const which contains array of bank account types
4986
- */
4987
- const BANK_ACCOUNT_TYPES = [
4988
- { key: BankAccountTypeEnum.CREDIT_CARD, value: 'Credit Card Accounts' },
4989
- { key: BankAccountTypeEnum.TERM_DEPOSIT, value: 'Deposit Accounts' },
4990
- { key: BankAccountTypeEnum.INVESTMENT, value: 'Investment Accounts' },
4991
- { key: BankAccountTypeEnum.LOAN, value: 'Loan Accounts' },
4992
- { key: BankAccountTypeEnum.OFFSET, value: 'Offset' },
4993
- { key: BankAccountTypeEnum.SAVINGS, value: 'Savings Accounts' },
4994
- { key: BankAccountTypeEnum.TRANSACTION, value: 'Transaction Accounts' },
4995
- ];
4996
-
4997
- /**
4998
- * Login data object for basiq banks
5170
+ * used to combine transactions/depreciations
4999
5171
  */
5000
- class BankLoginData {
5172
+ class TransactionBaseCollection extends Collection {
5173
+ getClaimAmountByBusinessId(businessId) {
5174
+ return +this.filterBy('business.id', businessId).items.map((transaction) => transaction instanceof Depreciation ? -transaction.claimAmount : transaction['claimAmount']).reduce((sum, claimAmount) => sum + claimAmount, 0).toFixed(2);
5175
+ }
5176
+ getSoleTransactions() {
5177
+ return this.filter((transaction) => transaction.isSoleTank());
5178
+ }
5001
5179
  }
5002
5180
 
5003
- /**
5004
- * enum with months indexes.
5005
- * item value match with js Date month index from 0 to 11
5006
- * Order of items match with financial year months order
5007
- */
5008
- var MonthNumberEnum;
5009
- (function (MonthNumberEnum) {
5010
- MonthNumberEnum[MonthNumberEnum["JULY"] = 6] = "JULY";
5011
- MonthNumberEnum[MonthNumberEnum["AUGUST"] = 7] = "AUGUST";
5012
- MonthNumberEnum[MonthNumberEnum["SEPTEMBER"] = 8] = "SEPTEMBER";
5013
- MonthNumberEnum[MonthNumberEnum["OCTOBER"] = 9] = "OCTOBER";
5014
- MonthNumberEnum[MonthNumberEnum["NOVEMBER"] = 10] = "NOVEMBER";
5015
- MonthNumberEnum[MonthNumberEnum["DECEMBER"] = 11] = "DECEMBER";
5016
- MonthNumberEnum[MonthNumberEnum["JANUARY"] = 0] = "JANUARY";
5017
- MonthNumberEnum[MonthNumberEnum["FEBRUARY"] = 1] = "FEBRUARY";
5018
- MonthNumberEnum[MonthNumberEnum["MARCH"] = 2] = "MARCH";
5019
- MonthNumberEnum[MonthNumberEnum["APRIL"] = 3] = "APRIL";
5020
- MonthNumberEnum[MonthNumberEnum["MAY"] = 4] = "MAY";
5021
- MonthNumberEnum[MonthNumberEnum["JUNE"] = 5] = "JUNE";
5022
- })(MonthNumberEnum || (MonthNumberEnum = {}));
5023
-
5024
- /**
5025
- * @TODO move to pipe/translation
5026
- * enum with months short names.
5027
- * Order of items match with financial year months order
5028
- */
5029
- var MonthNameShortEnum;
5030
- (function (MonthNameShortEnum) {
5031
- MonthNameShortEnum["JULY"] = "Jul";
5032
- MonthNameShortEnum["AUGUST"] = "Aug";
5033
- MonthNameShortEnum["SEPTEMBER"] = "Sep";
5034
- MonthNameShortEnum["OCTOBER"] = "Oct";
5035
- MonthNameShortEnum["NOVEMBER"] = "Nov";
5036
- MonthNameShortEnum["DECEMBER"] = "Dec";
5037
- MonthNameShortEnum["JANUARY"] = "Jan";
5038
- MonthNameShortEnum["FEBRUARY"] = "Feb";
5039
- MonthNameShortEnum["MARCH"] = "Mar";
5040
- MonthNameShortEnum["APRIL"] = "Apr";
5041
- MonthNameShortEnum["MAY"] = "May";
5042
- MonthNameShortEnum["JUNE"] = "Jun";
5043
- })(MonthNameShortEnum || (MonthNameShortEnum = {}));
5181
+ // @TODO Alex move here all collections
5044
5182
 
5045
5183
  /**
5046
- * bank transactions collection UI class with frontend specific data
5184
+ * propertySale docs - https://taxtank.atlassian.net/wiki/spaces/TAXTANK/pages/4209508353/Property+Sold+button
5047
5185
  */
5048
- class BankTransactionChartData {
5049
- constructor(bankTransactions) {
5050
- this.bankTransactions = bankTransactions;
5186
+ class Property extends Property$1 {
5187
+ get name() {
5188
+ return this.address.name;
5051
5189
  }
5052
- /**
5053
- * get value of bar chart data
5054
- */
5055
- getCashInOutBarChartData(months) {
5056
- const chartData = this.calculateCashInOutBarChartData();
5057
- if (!months) {
5058
- return chartData;
5059
- }
5060
- return this.filterChartDataByMonths(months, chartData);
5190
+ get isActive() {
5191
+ var _a;
5192
+ return !!((_a = this.subscriptions) === null || _a === void 0 ? void 0 : _a.length);
5061
5193
  }
5062
- /**
5063
- * get value of line chart data
5064
- */
5065
- getBalanceLineChartData(months) {
5066
- const chartData = this.calculateBalanceLineChartData();
5067
- if (!months) {
5068
- return chartData;
5069
- }
5070
- return this.filterChartDataByMonths(months, chartData);
5194
+ isOwn() {
5195
+ return this.user.id === +localStorage.getItem('userId');
5196
+ }
5197
+ isSold() {
5198
+ return !!this.myShare.sale;
5071
5199
  }
5072
5200
  /**
5073
- * set bar chart data
5201
+ * Get initials of property. Required by Photoable interface
5074
5202
  */
5075
- calculateCashInOutBarChartData() {
5076
- const chartData = [{
5077
- name: 'Cash In',
5078
- data: []
5079
- }, {
5080
- name: 'Cash Out',
5081
- data: []
5082
- }];
5083
- for (const key in MonthNameShortEnum) {
5084
- if (MonthNameShortEnum.hasOwnProperty(key)) {
5085
- const bankTransactionsForMonth = this.bankTransactions.filter((bankTransaction) => {
5086
- return +bankTransaction.date.getMonth() === +MonthNumberEnum[key];
5087
- });
5088
- const cashInForMonth = bankTransactionsForMonth
5089
- .filter((bankTransaction) => bankTransaction.isCredit())
5090
- .reduce((sum, bankTransaction) => sum += bankTransaction.allocatedAmount, 0);
5091
- const cashOutForMonth = bankTransactionsForMonth
5092
- .filter((bankTransaction) => bankTransaction.isDebit())
5093
- .reduce((sum, bankTransaction) => sum += bankTransaction.allocatedAmount, 0);
5094
- chartData[0].data.push({
5095
- label: MonthNameShortEnum[key],
5096
- value: cashInForMonth
5097
- });
5098
- chartData[1].data.push({
5099
- label: MonthNameShortEnum[key],
5100
- value: cashOutForMonth
5101
- });
5102
- }
5103
- }
5104
- return chartData;
5203
+ getPhotoPlaceholder() {
5204
+ return this.name.split(' ')[1].slice(0, 2);
5105
5205
  }
5106
5206
  /**
5107
- * set line chart data
5207
+ * Get property photo. Required by Photoable interface
5108
5208
  */
5109
- calculateBalanceLineChartData() {
5110
- const chartData = [{
5111
- name: 'Balance',
5112
- data: []
5113
- }];
5114
- for (const key in MonthNameShortEnum) {
5115
- if (MonthNameShortEnum.hasOwnProperty(key)) {
5116
- const bankTransactionsForMonth = this.bankTransactions.filter((bankTransaction) => {
5117
- return +bankTransaction.date.getMonth() === +MonthNumberEnum[key];
5118
- });
5119
- const balanceForMonth = bankTransactionsForMonth.reduce((sum, bankTransaction) => {
5120
- if (bankTransaction.isCredit()) {
5121
- return sum += bankTransaction.allocatedAmount;
5122
- }
5123
- else {
5124
- return sum -= bankTransaction.allocatedAmount;
5125
- }
5126
- }, 0);
5127
- chartData[0].data.push({
5128
- label: MonthNameShortEnum[key],
5129
- value: balanceForMonth
5130
- });
5131
- }
5132
- }
5133
- return chartData;
5209
+ getPhoto() {
5210
+ return this.photo;
5134
5211
  }
5135
- /**
5136
- * filter chart data for passed months
5137
- */
5138
- filterChartDataByMonths(months, chartData) {
5139
- const monthsNames = months.map((month) => MonthNumberEnum[month]).map((key) => MonthNameShortEnum[key]);
5140
- const filteredChartData = cloneDeep$1(chartData);
5141
- filteredChartData.forEach((chartDataItem) => {
5142
- chartDataItem.data = chartDataItem.data.filter((serie) => monthsNames.includes(serie.label));
5143
- });
5144
- return filteredChartData;
5212
+ get capitalCostsTotalAmount() {
5213
+ return this.stampDuty + this.legalFees + this.otherCapitalCosts;
5145
5214
  }
5146
- }
5147
-
5148
- var BankTransactionSummaryFieldsEnum;
5149
- (function (BankTransactionSummaryFieldsEnum) {
5150
- BankTransactionSummaryFieldsEnum["AMOUNT"] = "amount";
5151
- BankTransactionSummaryFieldsEnum["ALLOCATED_AMOUNT"] = "allocatedAmount";
5152
- })(BankTransactionSummaryFieldsEnum || (BankTransactionSummaryFieldsEnum = {}));
5153
-
5154
- class Document$1 extends AbstractModel {
5155
- }
5156
-
5157
- /**
5158
- * Enum with document types which used to API url prefix
5159
- */
5160
- var DocumentApiUrlPrefixEnum;
5161
- (function (DocumentApiUrlPrefixEnum) {
5162
- DocumentApiUrlPrefixEnum["FOLDERS"] = "folders";
5163
- DocumentApiUrlPrefixEnum["PROPERTIES"] = "properties";
5164
- })(DocumentApiUrlPrefixEnum || (DocumentApiUrlPrefixEnum = {}));
5165
-
5166
- class Document extends Document$1 {
5167
- constructor() {
5168
- super(...arguments);
5169
- this.type = AssetTypeEnum.DOCUMENT;
5170
- this.entityType = AssetEntityTypeEnum.FOLDERS;
5215
+ get currentYearValuations() {
5216
+ return this.valuations.filter((valuation) => valuation.isCurrentYear());
5171
5217
  }
5172
- /**
5173
- * Get folder as document parent entity
5174
- */
5175
- getEntity() {
5176
- return this.folder;
5218
+ get marketValue() {
5219
+ var _a;
5220
+ return ((_a = this.actualValuation) === null || _a === void 0 ? void 0 : _a.marketValue) || 0;
5177
5221
  }
5178
- /**
5179
- * Get API url prefix
5180
- */
5181
- getApiUrlPrefix() {
5182
- return DocumentApiUrlPrefixEnum.FOLDERS;
5222
+ get currentYearForecast() {
5223
+ return this.forecasts.find((forecast) => forecast.isCurrentYear());
5183
5224
  }
5184
- }
5185
-
5186
- class DocumentFolder$1 extends AbstractModel {
5187
- }
5188
-
5189
- class DocumentFolder extends DocumentFolder$1 {
5190
- }
5191
- __decorate([
5192
- Type(() => Document)
5193
- ], DocumentFolder.prototype, "documents", void 0);
5194
-
5195
- /**
5196
- * BankConnection means user account at specific bank (usually each user has only one at the same bank)
5197
- * service handles BankConnection management
5198
- */
5199
- class BankConnectionService extends RestService {
5200
- constructor() {
5201
- super(...arguments);
5202
- this.modelClass = BankConnection;
5203
- this.url = 'bank-connections';
5225
+ get forecastedRentalReturn() {
5226
+ var _a;
5227
+ return ((_a = this.currentYearForecast) === null || _a === void 0 ? void 0 : _a.rentalReturn) || 0;
5204
5228
  }
5205
- listenEvents() {
5206
- this.listenToAddedBankAccounts();
5207
- this.listenNotifications();
5208
- this.listenBasiqLogin();
5229
+ get forecastedTaxPosition() {
5230
+ var _a;
5231
+ return ((_a = this.currentYearForecast) === null || _a === void 0 ? void 0 : _a.taxPosition) || 0;
5209
5232
  }
5210
- add(bankConnection) {
5211
- return this.http.post(`${this.environment.apiV2}/${this.url}`, bankConnection)
5212
- .pipe(map((bankConnectionBase) => {
5213
- const connection = plainToClass(BankConnection, bankConnectionBase);
5214
- // We use this endpoint for create and reconnect bank connections because of basiq logic.
5215
- // So we try to replace bank connection in cache for reconnection case.
5216
- if (this.cache) {
5217
- if (bankConnection.id) {
5218
- const tempCache = cloneDeep$1(this.cache);
5219
- replace(tempCache, connection);
5220
- this.cache = tempCache;
5221
- this.cacheSubject.next(this.cache);
5222
- }
5223
- else {
5224
- this.cache.push(connection);
5225
- this.cacheSubject.next(cloneDeep$1(this.cache));
5226
- }
5227
- }
5228
- this.eventDispatcherService.dispatch(new AppEvent(AppEventTypeEnum.BANK_CONNECTION_ADDED, connection));
5229
- return plainToClass(BankConnection, connection);
5230
- }), catchError((error) => {
5231
- // Show error when user provided wrong login data
5232
- if (error.status === 401) {
5233
- this.toastService.error('Invalid credentials');
5234
- }
5235
- // Show error when user provided another login (not login he used before)
5236
- if (error.status === 400) {
5237
- this.toastService.error('Please enter the login you used before');
5238
- }
5239
- return throwError$1(error);
5240
- }));
5233
+ get forecastedCashPosition() {
5234
+ var _a;
5235
+ return ((_a = this.currentYearForecast) === null || _a === void 0 ? void 0 : _a.cashPosition) || 0;
5241
5236
  }
5242
- listenToAddedBankAccounts() {
5243
- this.eventDispatcherService.on(AppEventTypeEnum.BANK_ACCOUNT_CREATED).subscribe(() => {
5244
- this.resetCache();
5245
- });
5237
+ get firstForecastYear() {
5238
+ return this.forecasts.reduce((min, forecast) => {
5239
+ return min > forecast.financialYear ? forecast.financialYear : min;
5240
+ }, new FinancialYear().year);
5241
+ }
5242
+ get marketValueGrowth() {
5243
+ return (this.marketValue - this.purchasePrice) / this.marketValue;
5244
+ }
5245
+ get myShare() {
5246
+ return this.shares.find((share) => share.user.id === +localStorage.getItem('userId'));
5247
+ }
5248
+ get actualValuation() {
5249
+ return this.valuations.reduce((maxDateValuation, valuation) => {
5250
+ return maxDateValuation.date > valuation.date ? maxDateValuation : valuation;
5251
+ }, this.valuations[0]);
5252
+ }
5253
+ get claimPercent() {
5254
+ return this.currentYearForecast.claimPercent;
5255
+ }
5256
+ get claimCoefficient() {
5257
+ return this.claimPercent / 100;
5258
+ }
5259
+ get sharePercent() {
5260
+ return this.myShare.percent;
5261
+ }
5262
+ get shareRatio() {
5263
+ return this.myShare.percent / 100;
5264
+ }
5265
+ get previousCategory() {
5266
+ let previousCategory;
5267
+ const movementsCount = this.categoryMovements.length;
5268
+ if (movementsCount > 1) {
5269
+ previousCategory = this.categoryMovements[movementsCount - 2].propertyCategory;
5270
+ }
5271
+ return previousCategory;
5272
+ }
5273
+ getCurrentSubscription() {
5274
+ // always return first element because subscriptions array contains only one element
5275
+ return this.subscriptions[0];
5276
+ }
5277
+ getForecastByYear(year) {
5278
+ return this.forecasts.find((forecast) => forecast.financialYear === year);
5279
+ }
5280
+ get isShared() {
5281
+ return this.shares.length > 1;
5246
5282
  }
5247
5283
  /**
5248
- * Update cache when basiq accounts were retrieved or login to basic was failed to get actual connections statuses
5284
+ * @TODO consider to move methods related with propertySale to separated class, since used just in one module yet
5285
+ * purchase costs - claimed costs, except `ppr to investment` exemption,
5286
+ * in that case it's equal to market value, when property became an investment property
5249
5287
  */
5250
- listenNotifications() {
5251
- // @TODO vik listen sse when backend updated
5252
- this.eventDispatcherService.on(AppEventTypeEnum.NOTIFICATION_ADDED).subscribe((notification) => {
5253
- // @Todo TT-2280 Alex refactor ServiceNotification isRead logic. We don't need to know here whether notification was read or not
5254
- if (!notification.isRead) {
5255
- return;
5256
- }
5257
- if (BankConnectionService.userEventTypes.includes(notification.eventType)) {
5258
- this.resetCache();
5259
- }
5260
- });
5288
+ calculateCostBase(sale) {
5289
+ const marketValue = new PropertySaleTaxExemptionMetadataCollection(sale.taxExemptionMetadata).getMarketValue();
5290
+ if (marketValue) {
5291
+ return marketValue;
5292
+ }
5293
+ return this.purchasePrice + this.capitalCostsTotalAmount + sale.holdingCosts + sale.structuralImprovementsWDV - sale.buildingAtCostClaimed;
5261
5294
  }
5262
5295
  /**
5263
- * Create/reconnect bank connection when user successfully logged in to basiq
5296
+ * gross capital gain tax: sale costs - cost base
5264
5297
  */
5265
- listenBasiqLogin() {
5266
- this.eventDispatcherService.on(AppEventTypeEnum.BASIQ_LOGIN_SUCCESS).subscribe((data) => {
5267
- this.add(plainToClass(BankConnection, { id: data.connectionId, basiqJob: { externalId: data.jobId } }))
5268
- .subscribe(() => { },
5269
- // When user already has some bank accounts in handling connection and trying to login with different credentials, backend can not save this connection.
5270
- // So we should handle this case as failed login
5271
- () => {
5272
- this.eventDispatcherService.dispatch(new AppEvent(AppEventTypeEnum.BASIQ_LOGIN_FAILED, null));
5273
- });
5274
- });
5275
- }
5276
- }
5277
- BankConnectionService.userEventTypes = [
5278
- UserEventTypeTypeEnum.BASIQ_NEW_ACCOUNTS,
5279
- UserEventTypeTypeEnum.BASIQ_AUTHORIZATION_FAIL
5280
- ];
5281
- BankConnectionService.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.2.15", ngImport: i0, type: BankConnectionService, deps: null, target: i0.ɵɵFactoryTarget.Injectable });
5282
- BankConnectionService.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "12.2.15", ngImport: i0, type: BankConnectionService, providedIn: 'root' });
5283
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.15", ngImport: i0, type: BankConnectionService, decorators: [{
5284
- type: Injectable,
5285
- args: [{
5286
- providedIn: 'root'
5287
- }]
5288
- }] });
5289
-
5290
- /**
5291
- * basiq is a middleman between bank and user
5292
- * service is responsible for fetching bank related information
5293
- */
5294
- class BasiqService extends RestService {
5295
- constructor(http, eventDispatcherService, environment, toastService,
5296
- // this inject required to init bank connection service and listen basiq login event
5297
- bankConnectionService) {
5298
- super(http, eventDispatcherService, environment, toastService);
5299
- this.http = http;
5300
- this.eventDispatcherService = eventDispatcherService;
5301
- this.environment = environment;
5302
- this.toastService = toastService;
5303
- this.bankConnectionService = bankConnectionService;
5304
- this.url = 'basiq/accounts';
5305
- this.modelClass = BankAccount;
5298
+ calculateCGT(sale) {
5299
+ return (sale.price - sale.saleCostsTotalAmount - this.calculateCostBase(sale)) * this.shareRatio - sale.capitalLoss;
5306
5300
  }
5307
5301
  /**
5308
- * Listen events from Event Dispatcher service
5302
+ * net capital gain tax (includes tax exemptions)
5309
5303
  */
5310
- listenEvents() {
5311
- this.listenNotifications();
5312
- this.listenJobCreated();
5304
+ calculateNetCGT(sale) {
5305
+ return this.getCGTExemptionRatio(sale) * sale.grossCGT;
5313
5306
  }
5314
5307
  /**
5315
- * Start basiq login process.
5316
- * Create a basiq job, which contain credentials verifying status.
5317
- * We can not see login result immediately, because it may take some time (average 10-20 sec)
5308
+ * guess tax exemption based on property details
5318
5309
  */
5319
- login(loginData, userId) {
5320
- this.http.post(`${BasiqService.basiqApiUrl}/users/${userId}/connections`, loginData)
5321
- .subscribe((response) => {
5322
- // we need jobId to check credentials verifying statis from Basiq API
5323
- // we need connectionId to know if we are creating a new connection or reconnecting existing invalid connection
5324
- const data = {
5325
- jobId: response.id,
5326
- connectionId: loginData.id
5327
- };
5328
- this.eventDispatcherService.dispatch(new AppEvent(AppEventTypeEnum.BASIQ_JOB_CREATED, data));
5329
- });
5310
+ getCGTExemption(sale) {
5311
+ if (sale.taxExemption) {
5312
+ return sale.taxExemption.id;
5313
+ }
5314
+ switch (true) {
5315
+ // exemption for main residence properties
5316
+ case this.category.id === PropertyCategoryListEnum.OWNER_OCCUPIED:
5317
+ return TaxExemptionEnum.PPR;
5318
+ // exemption for investment properties owned for at least one year
5319
+ case this.isOneYearExemptionApplicable(sale):
5320
+ return TaxExemptionEnum.ONE_YEAR_RULE;
5321
+ default:
5322
+ return null;
5323
+ }
5330
5324
  }
5331
- getByConnection(connection) {
5332
- return this.get().pipe(map((bankAccounts) => {
5333
- return new BankAccountCollection(bankAccounts).filterBy('bankConnection.id', connection.id);
5334
- }));
5325
+ /**
5326
+ * tax exemption can reduce cgt from 100% to less (up to zero)
5327
+ */
5328
+ getCGTExemptionRatio(sale) {
5329
+ var _a;
5330
+ const metadata = new PropertySaleTaxExemptionMetadataCollection(sale.taxExemptionMetadata);
5331
+ switch ((_a = sale.taxExemption) === null || _a === void 0 ? void 0 : _a.id) {
5332
+ // 50% exemption for investments owned for at least one year
5333
+ case TaxExemptionEnum.ONE_YEAR_RULE:
5334
+ return 0.5;
5335
+ // investment property become main residence (exemption for main residence ownership duration)
5336
+ case TaxExemptionEnum.INVESTMENT_TO_PPR:
5337
+ const ownershipDays = this.getOwnershipDuration(sale);
5338
+ return (ownershipDays - metadata.getPPRDays()) / ownershipDays;
5339
+ // main residence become investment (exemption for home office percent usage)
5340
+ case TaxExemptionEnum.PPR_TO_INVESTMENT:
5341
+ // 1 year CGT discount can still apply (on the income producing % if used for 12 months or more)
5342
+ const ratio = this.isOneYearExemptionApplicable(sale) ? 0.5 : 1;
5343
+ return metadata.getClaimPercent() / 100 * ratio;
5344
+ // full exemption
5345
+ case TaxExemptionEnum.PPR:
5346
+ case TaxExemptionEnum.SIX_YEARS_RULE:
5347
+ case TaxExemptionEnum.TRANSFER:
5348
+ case TaxExemptionEnum.OTHER:
5349
+ return 0;
5350
+ // no exemption
5351
+ default:
5352
+ return 1;
5353
+ }
5335
5354
  }
5336
- getNotImportedByConnection(savedAccounts, connection) {
5337
- return this.getByConnection(connection).pipe(map((bankAccounts) => {
5338
- return bankAccounts.removeBy('accountId', savedAccounts.mapBy('accountId'));
5339
- }));
5355
+ isOneYearExemptionApplicable(sale) {
5356
+ return sale.grossCGT > 0 && this.getOwnershipDuration(sale, 'years') > 0;
5340
5357
  }
5341
5358
  /**
5342
- * Get status of credentials verifying. Expected statuses: 'in-progress', 'failed' or 'success'
5343
- * We send this request by interval until basiq return success or failed.
5344
- *
5345
- * Because of Basiq login may take a long time (10-20sec) we have to check job status until it seccess or failed.
5346
- *
5347
- * @TODO Alex (TT-2431): check logic and try to remove subscribe, use pipes instead
5348
- * @TODO Alex (TT-2431): implement some limit and handle (message or something) if basiq stuck
5349
- * @TODO Alex (TT-2431): check logic and handle case when user cancelled loading
5350
- */
5351
- checkLoginStatus(data) {
5352
- this.http.get(`${BasiqService.basiqApiUrl}/jobs/${data.jobId}`)
5353
- .pipe(
5354
- // get verify-credentials step from basiq job
5355
- map((response) => plainToClass(BasiqJobResponse, response)),
5356
- // check credentials status again if not finished
5357
- filter((response) => {
5358
- if (!response.getVerifyCredentialsStep().isInProgress()) {
5359
- return true;
5360
- }
5361
- setTimeout(() => {
5362
- this.checkLoginStatus(data);
5363
- }, BasiqService.bankCredintialsCheckInterval);
5364
- return false;
5365
- }))
5366
- .subscribe((response) => {
5367
- if (response.getVerifyCredentialsStep().isSuccess()) {
5368
- this.eventDispatcherService.dispatch(new AppEvent(AppEventTypeEnum.BASIQ_LOGIN_SUCCESS, data));
5369
- }
5370
- else {
5371
- this.eventDispatcherService.dispatch(new AppEvent(AppEventTypeEnum.BASIQ_LOGIN_FAILED, null));
5372
- }
5373
- });
5359
+ * CGT is not applicable for properties acquired before 20.09.1985 (tax didn't exist before this date).
5360
+ * https://taxtank.atlassian.net/wiki/spaces/TAXTANK/pages/4644110466/Tax+Return+MyTax+-+Online+Form ("Capital gains or losses" section)
5361
+ */
5362
+ isCGTApplicable() {
5363
+ return this.contractDate >= Property.preCGTAssetDate;
5374
5364
  }
5375
5365
  /**
5376
- * listen to notifications to update basiq accounts list
5366
+ * ownership duration from purchase till sale
5377
5367
  */
5378
- listenNotifications() {
5379
- this.eventDispatcherService.on(AppEventTypeEnum.NOTIFICATION_ADDED).subscribe((notification) => {
5380
- if (!notification.isRead && notification.eventType === UserEventTypeTypeEnum.BASIQ_NEW_ACCOUNTS) {
5381
- this.resetCache();
5382
- }
5383
- });
5368
+ getOwnershipDuration(sale, unitOfTime = 'days') {
5369
+ return moment$1(sale.contractDate).diff(moment$1(this.contractDate), unitOfTime);
5384
5370
  }
5385
5371
  /**
5386
- * Start check job credential status when it created
5372
+ * Tax Position = Income - Expense - Interest - Depreciation
5373
+ * Where (Income - Expense - Interest) is cash position.
5374
+ * https://taxtank.atlassian.net/wiki/spaces/TAXTANK/pages/217415928/Dashboard+Property
5387
5375
  */
5388
- listenJobCreated() {
5389
- this.eventDispatcherService.on(AppEventTypeEnum.BASIQ_JOB_CREATED).subscribe((data) => {
5390
- this.checkLoginStatus(data);
5391
- });
5376
+ getTaxPosition(transactions, depreciations) {
5377
+ return transactions.grossClaimAmount - Math.abs(depreciations.claimAmount);
5392
5378
  }
5393
5379
  }
5394
- BasiqService.basiqApiUrl = 'https://au-api.basiq.io';
5395
5380
  /**
5396
- * Basiq does not provide a hook, so we have to check job status manually every x seconds
5381
+ * Property acquired before 20 September 1985 will generally be treated as pre-Capital Gains Tax (CGT) assets.
5382
+ * Any assets acquired before this day are CGT exempt (because the tax didn't exist before this date).
5397
5383
  */
5398
- BasiqService.bankCredintialsCheckInterval = 3000;
5399
- BasiqService.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.2.15", ngImport: i0, type: BasiqService, deps: [{ token: i1.HttpClient }, { token: EventDispatcherService }, { token: 'environment' }, { token: ToastService }, { token: BankConnectionService }], target: i0.ɵɵFactoryTarget.Injectable });
5400
- BasiqService.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "12.2.15", ngImport: i0, type: BasiqService, providedIn: 'root' });
5401
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.15", ngImport: i0, type: BasiqService, decorators: [{
5402
- type: Injectable,
5403
- args: [{
5404
- providedIn: 'root'
5405
- }]
5406
- }], ctorParameters: function () { return [{ type: i1.HttpClient }, { type: EventDispatcherService }, { type: undefined, decorators: [{
5407
- type: Inject,
5408
- args: ['environment']
5409
- }] }, { type: ToastService }, { type: BankConnectionService }]; } });
5384
+ Property.preCGTAssetDate = new Date(1985, 9, 20);
5385
+ Property.collectionClass = PropertyCollection;
5386
+ __decorate([
5387
+ Type(() => Date)
5388
+ ], Property.prototype, "contractDate", void 0);
5389
+ __decorate([
5390
+ Type(() => Date)
5391
+ ], Property.prototype, "settlementDate", void 0);
5392
+ __decorate([
5393
+ Type(() => Address)
5394
+ ], Property.prototype, "address", void 0);
5395
+ __decorate([
5396
+ Type(() => PropertyCategory)
5397
+ ], Property.prototype, "category", void 0);
5398
+ __decorate([
5399
+ Type(() => PropertyValuation)
5400
+ ], Property.prototype, "valuations", void 0);
5401
+ __decorate([
5402
+ Type(() => PropertyForecast)
5403
+ ], Property.prototype, "forecasts", void 0);
5404
+ __decorate([
5405
+ Type(() => PropertyCategoryMovement)
5406
+ ], Property.prototype, "categoryMovements", void 0);
5407
+ __decorate([
5408
+ Type(() => User)
5409
+ ], Property.prototype, "user", void 0);
5410
+ __decorate([
5411
+ Type(() => PropertySubscription)
5412
+ ], Property.prototype, "subscriptions", void 0);
5413
+ __decorate([
5414
+ Exclude()
5415
+ ], Property.prototype, "documentFile", void 0);
5410
5416
 
5411
- class BasiqTokenService {
5412
- constructor(http, environment) {
5413
- this.http = http;
5414
- this.environment = environment;
5415
- this.cacheSubject = new ReplaySubject(1);
5416
- }
5417
- /**
5418
- * Access token to use basiq flow
5419
- */
5420
- get() {
5421
- if (!this.cache || this.cache.isExpired()) {
5422
- this.http.get(`${this.environment.apiV2}/basiq/tokens`)
5423
- .pipe(map((response) => {
5424
- const now = new Date().getTime();
5425
- return new BasiqToken(response.access_token, new Date(now + response.expires_in * 1000));
5426
- }))
5427
- .subscribe((token) => {
5428
- this.cache = token;
5429
- this.cacheSubject.next(token);
5430
- });
5431
- }
5432
- return this.cacheSubject.asObservable();
5433
- }
5417
+ class BankAccountProperty extends BankAccountProperty$1 {
5434
5418
  }
5435
- BasiqTokenService.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.2.15", ngImport: i0, type: BasiqTokenService, deps: [{ token: i1.HttpClient }, { token: 'environment' }], target: i0.ɵɵFactoryTarget.Injectable });
5436
- BasiqTokenService.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "12.2.15", ngImport: i0, type: BasiqTokenService, providedIn: 'root' });
5437
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.15", ngImport: i0, type: BasiqTokenService, decorators: [{
5438
- type: Injectable,
5439
- args: [{
5440
- providedIn: 'root'
5441
- }]
5442
- }], ctorParameters: function () { return [{ type: i1.HttpClient }, { type: undefined, decorators: [{
5443
- type: Inject,
5444
- args: ['environment']
5445
- }] }]; } });
5419
+ __decorate([
5420
+ Type(() => Property)
5421
+ ], BankAccountProperty.prototype, "property", void 0);
5422
+ __decorate([
5423
+ Transform(({ value }) => value || 100),
5424
+ Expose()
5425
+ ], BankAccountProperty.prototype, "percent", void 0);
5446
5426
 
5447
- /**
5448
- * Interceptor which adds user's basiq token to any http request to basiq api
5449
- */
5450
- class BasiqTokenInterceptor {
5451
- constructor(basiqTokenService) {
5452
- this.basiqTokenService = basiqTokenService;
5453
- }
5454
- intercept(request, next) {
5455
- // skip non-basiq requests
5456
- if (!request.url.includes(BasiqService.basiqApiUrl)) {
5457
- return next.handle(request);
5458
- }
5459
- return this.basiqTokenService.get().pipe(mergeMap((token) => {
5460
- return next.handle(this.addToken(request, token));
5461
- }));
5462
- }
5463
- addToken(request, token) {
5464
- return request.clone({
5465
- setHeaders: {
5466
- Authorization: 'Bearer ' + token.value
5467
- }
5468
- });
5469
- }
5427
+ class BankConnection$1 extends AbstractModel {
5470
5428
  }
5471
- BasiqTokenInterceptor.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.2.15", ngImport: i0, type: BasiqTokenInterceptor, deps: [{ token: BasiqTokenService }], target: i0.ɵɵFactoryTarget.Injectable });
5472
- BasiqTokenInterceptor.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "12.2.15", ngImport: i0, type: BasiqTokenInterceptor });
5473
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.15", ngImport: i0, type: BasiqTokenInterceptor, decorators: [{
5474
- type: Injectable
5475
- }], ctorParameters: function () { return [{ type: BasiqTokenService }]; } });
5476
5429
 
5477
- /**
5478
- * server sent events service
5479
- * https://symfony.com/doc/current/mercure.html
5480
- */
5481
- class SseService {
5482
- constructor(zone, jwtService, environment) {
5483
- this.zone = zone;
5484
- this.jwtService = jwtService;
5485
- this.environment = environment;
5486
- }
5430
+ var BankConnectionStatusEnum;
5431
+ (function (BankConnectionStatusEnum) {
5432
+ BankConnectionStatusEnum[BankConnectionStatusEnum["PENDING"] = 1] = "PENDING";
5433
+ BankConnectionStatusEnum[BankConnectionStatusEnum["ACTIVE"] = 2] = "ACTIVE";
5434
+ BankConnectionStatusEnum[BankConnectionStatusEnum["INVALID"] = 3] = "INVALID";
5435
+ })(BankConnectionStatusEnum || (BankConnectionStatusEnum = {}));
5436
+
5437
+ class BankConnection extends BankConnection$1 {
5487
5438
  /**
5488
- * list to url for server events
5439
+ * Check if status of connection is inactive (invalid)
5489
5440
  */
5490
- on(topic) {
5491
- const url = new URL(this.environment.mercureUrl);
5492
- url.searchParams.append('topic', `${this.environment.apiV2}/users/${this.jwtService.decodeToken().username}/${topic}`);
5493
- // tslint:disable-next-line:typedef
5494
- return new Observable((observer) => {
5495
- const es = new EventSourcePolyfill(url, {
5496
- headers: {
5497
- Authorization: 'Bearer ' + this.jwtService.getToken(),
5498
- }
5499
- });
5500
- es.onmessage = (event) => {
5501
- this.zone.run(() => observer.next(event));
5502
- };
5503
- })
5504
- .pipe(map((messageEvent) => {
5505
- return JSON.parse(messageEvent.data);
5506
- }));
5507
- }
5508
- }
5509
- SseService.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.2.15", ngImport: i0, type: SseService, deps: [{ token: i0.NgZone }, { token: JwtService }, { token: 'environment' }], target: i0.ɵɵFactoryTarget.Injectable });
5510
- SseService.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "12.2.15", ngImport: i0, type: SseService, providedIn: 'root' });
5511
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.15", ngImport: i0, type: SseService, decorators: [{
5512
- type: Injectable,
5513
- args: [{
5514
- providedIn: 'root'
5515
- }]
5516
- }], ctorParameters: function () { return [{ type: i0.NgZone }, { type: JwtService }, { type: undefined, decorators: [{
5517
- type: Inject,
5518
- args: ['environment']
5519
- }] }]; } });
5520
-
5521
- /**
5522
- * Service to work with user
5523
- */
5524
- class UserService {
5525
- constructor(http, jwtService, eventDispatcherService, sseService, environment) {
5526
- this.http = http;
5527
- this.jwtService = jwtService;
5528
- this.eventDispatcherService = eventDispatcherService;
5529
- this.sseService = sseService;
5530
- this.environment = environment;
5531
- this.cacheSubject = new ReplaySubject(1);
5532
- this.listenEvents();
5533
- }
5534
- /**
5535
- * never return cache directly to prevent update
5536
- */
5537
- getCache() {
5538
- return clone(this.cache);
5539
- }
5540
- listenEvents() {
5541
- this.listenServiceSubscriptionUpdated();
5542
- }
5543
- get() {
5544
- if (!this.cache) {
5545
- this.fetch().subscribe(() => { }, (error) => {
5546
- // force logout user (clear localStorage) when get current user return error
5547
- if (error.status === 500) {
5548
- this.eventDispatcherService.dispatch(new AppEvent(AppEventTypeEnum.CURRENT_USER_GET_FAILED, null));
5549
- }
5550
- });
5551
- }
5552
- return this.cacheSubject.asObservable();
5553
- }
5554
- /**
5555
- * Get current user
5556
- */
5557
- fetch() {
5558
- return this.http.get(`${this.environment.apiV2}/users/current`)
5559
- .pipe(map((userBase) => {
5560
- const user = plainToClass(User, userBase);
5561
- localStorage.setItem('userId', user.id.toString());
5562
- // @TODO remove
5563
- localStorage.setItem('financialYear', user.financialYear.toString());
5564
- this.cache = user;
5565
- this.cacheSubject.next(this.cache);
5566
- return user;
5567
- }));
5568
- }
5569
- /**
5570
- * Register new user
5571
- */
5572
- register(data) {
5573
- return this.http.post(`${this.environment.apiV2}/users/registration`, data);
5574
- }
5575
- /**
5576
- * Update user
5577
- */
5578
- update(user) {
5579
- return this.http.put(`${this.environment.apiV2}/users/${user.id}`, user)
5580
- .pipe(map((userBase) => {
5581
- this.cache = plainToClass(User, userBase);
5582
- this.eventDispatcherService.dispatch(new AppEvent(AppEventTypeEnum.USER_UPDATED, null));
5583
- this.cacheSubject.next(this.cache);
5584
- }));
5585
- }
5586
- /**
5587
- * Change user password
5588
- */
5589
- changePassword(currentPassword, newPassword) {
5590
- return this.http.put(`${this.environment.apiV2}/users/password/change`, { currentPassword, newPassword });
5591
- }
5592
- /**
5593
- * Recovery user password
5594
- */
5595
- recoveryPassword(email) {
5596
- return this.http.put(`${this.environment.apiV2}/users/password/recovery`, { email });
5597
- }
5598
- /**
5599
- * Reset user password
5600
- */
5601
- resetPassword(newPassword, resetToken) {
5602
- return this.http.put(`${this.environment.apiV2}/users/password/reset`, { newPassword, resetToken });
5603
- }
5604
- resendConfirmationEmail(email) {
5605
- return this.http.post(`${this.environment.apiV2}/users/confirmation/resend`, { email });
5606
- }
5607
- /**
5608
- * Confirm registered user
5609
- */
5610
- confirm(verificationCode) {
5611
- return this.http.post(`${this.environment.apiV2}/users/confirmation`, { verificationCode });
5612
- }
5613
- /**
5614
- * Search existing user
5615
- */
5616
- search(email) {
5617
- return this.http.get(`${this.environment.apiV2}/users/search?email=${email}`)
5618
- .pipe(map((userBase) => {
5619
- return plainToClass(User, userBase);
5620
- }));
5621
- }
5622
- /**
5623
- * Finish onboarding process
5624
- */
5625
- finishOnboarding(user) {
5626
- return this.http.put(`${this.environment.apiV2}/users/status`, user)
5627
- .pipe(map(() => {
5628
- this.cache = user;
5629
- this.cacheSubject.next(this.cache);
5630
- }));
5631
- }
5632
- /**
5633
- * Update user photo
5634
- */
5635
- updatePhoto(photo) {
5636
- return this.http.post(`${this.environment.apiV2}/users/photo?_method=PUT`, photo)
5637
- .pipe(map((photoUrl) => {
5638
- this.cache = plainToClass(User, Object.assign(this.cache, { photo: photoUrl }));
5639
- this.cacheSubject.next(this.cache);
5640
- }));
5641
- }
5642
- switchFinancialYear(year) {
5643
- return this.http.get(`${this.environment.apiV2}/financial-year/switch`, { params: new HttpParams({ fromString: `financialYear=${year}` }) }).pipe(map(() => {
5644
- localStorage.setItem('financialYear', year.toString());
5645
- window.location.reload();
5646
- }));
5647
- }
5648
- /**
5649
- * clear service cache
5650
- */
5651
- resetCache() {
5652
- this.fetch().subscribe();
5653
- }
5654
- /**
5655
- * Create basiq (if not exist yet) to provide access to basiq api
5656
- */
5657
- createBasiq() {
5658
- var _a;
5659
- // no need to create basiqId if already exist
5660
- // @TODO Alex (TT-2431): move this check to component or separated method
5661
- if ((_a = this.cache) === null || _a === void 0 ? void 0 : _a.basiqId) {
5662
- return of(this.cache.basiqId);
5663
- }
5664
- return this.http.post(`${this.environment.apiV2}/basiq/user`, {})
5665
- .pipe(map((basiqId) => {
5666
- this.cache = plainToClass(User, Object.assign(this.cache, { basiqId }));
5667
- this.cacheSubject.next(this.cache);
5668
- return basiqId;
5669
- }));
5670
- }
5671
- /**
5672
- * Update cache when user's service subscription is updated
5673
- */
5674
- listenServiceSubscriptionUpdated() {
5675
- this.eventDispatcherService.on(AppEventTypeEnum.SERVICE_SUBSCRIPTION_UPDATED).subscribe(() => this.resetCache());
5676
- }
5677
- }
5678
- UserService.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.2.15", ngImport: i0, type: UserService, deps: [{ token: i1.HttpClient }, { token: JwtService }, { token: EventDispatcherService }, { token: SseService }, { token: 'environment' }], target: i0.ɵɵFactoryTarget.Injectable });
5679
- UserService.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "12.2.15", ngImport: i0, type: UserService, providedIn: 'root' });
5680
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.15", ngImport: i0, type: UserService, decorators: [{
5681
- type: Injectable,
5682
- args: [{
5683
- providedIn: 'root'
5684
- }]
5685
- }], ctorParameters: function () { return [{ type: i1.HttpClient }, { type: JwtService }, { type: EventDispatcherService }, { type: SseService }, { type: undefined, decorators: [{
5686
- type: Inject,
5687
- args: ['environment']
5688
- }] }]; } });
5689
-
5690
- /**
5691
- * Interceptor which check if client's basiq id exist and request it if not
5692
- */
5693
- class BasiqClientIdInterceptor {
5694
- constructor(userService) {
5695
- this.userService = userService;
5696
- }
5697
- intercept(request, next) {
5698
- // Check if 'client id' URL segment contains null instead of id
5699
- if (!request.url.startsWith(`${BasiqService.basiqApiUrl}/users/null`)) {
5700
- return next.handle(request);
5701
- }
5702
- return this.userService.createBasiq().pipe(mergeMap((basiqClientId) => next.handle(this.addId(request, basiqClientId))));
5703
- }
5704
- addId(request, basiqClientId) {
5705
- return request.clone({
5706
- url: request.url.replace('null', basiqClientId)
5707
- });
5708
- }
5709
- }
5710
- BasiqClientIdInterceptor.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.2.15", ngImport: i0, type: BasiqClientIdInterceptor, deps: [{ token: UserService }], target: i0.ɵɵFactoryTarget.Injectable });
5711
- BasiqClientIdInterceptor.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "12.2.15", ngImport: i0, type: BasiqClientIdInterceptor });
5712
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.15", ngImport: i0, type: BasiqClientIdInterceptor, decorators: [{
5713
- type: Injectable
5714
- }], ctorParameters: function () { return [{ type: UserService }]; } });
5715
-
5716
- class InterceptorsModule {
5717
- }
5718
- InterceptorsModule.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.2.15", ngImport: i0, type: InterceptorsModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule });
5719
- InterceptorsModule.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "12.0.0", version: "12.2.15", ngImport: i0, type: InterceptorsModule });
5720
- InterceptorsModule.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "12.2.15", ngImport: i0, type: InterceptorsModule, providers: [
5721
- {
5722
- provide: HTTP_INTERCEPTORS,
5723
- useClass: CorelogicInterceptor,
5724
- multi: true
5725
- },
5726
- // @TODO move to user module
5727
- {
5728
- provide: HTTP_INTERCEPTORS,
5729
- useClass: FinancialYearInterceptor,
5730
- multi: true
5731
- },
5732
- {
5733
- provide: HTTP_INTERCEPTORS,
5734
- useClass: JwtInterceptor,
5735
- multi: true
5736
- },
5737
- {
5738
- provide: HTTP_INTERCEPTORS,
5739
- useClass: UserSwitcherInterceptor,
5740
- multi: true
5741
- },
5742
- {
5743
- provide: HTTP_INTERCEPTORS,
5744
- useClass: PreloaderInterceptor,
5745
- multi: true
5746
- },
5747
- {
5748
- provide: HTTP_INTERCEPTORS,
5749
- useClass: BasiqTokenInterceptor,
5750
- multi: true
5751
- },
5752
- {
5753
- provide: HTTP_INTERCEPTORS,
5754
- useClass: BasiqClientIdInterceptor,
5755
- multi: true
5756
- }
5757
- ] });
5758
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.15", ngImport: i0, type: InterceptorsModule, decorators: [{
5759
- type: NgModule,
5760
- args: [{
5761
- providers: [
5762
- {
5763
- provide: HTTP_INTERCEPTORS,
5764
- useClass: CorelogicInterceptor,
5765
- multi: true
5766
- },
5767
- // @TODO move to user module
5768
- {
5769
- provide: HTTP_INTERCEPTORS,
5770
- useClass: FinancialYearInterceptor,
5771
- multi: true
5772
- },
5773
- {
5774
- provide: HTTP_INTERCEPTORS,
5775
- useClass: JwtInterceptor,
5776
- multi: true
5777
- },
5778
- {
5779
- provide: HTTP_INTERCEPTORS,
5780
- useClass: UserSwitcherInterceptor,
5781
- multi: true
5782
- },
5783
- {
5784
- provide: HTTP_INTERCEPTORS,
5785
- useClass: PreloaderInterceptor,
5786
- multi: true
5787
- },
5788
- {
5789
- provide: HTTP_INTERCEPTORS,
5790
- useClass: BasiqTokenInterceptor,
5791
- multi: true
5792
- },
5793
- {
5794
- provide: HTTP_INTERCEPTORS,
5795
- useClass: BasiqClientIdInterceptor,
5796
- multi: true
5797
- }
5798
- ]
5799
- }]
5800
- }] });
5801
-
5802
- class TtCoreModule {
5803
- static forRoot(environment) {
5804
- localStorage.setItem('api_uri', environment['api_uri']);
5805
- return {
5806
- ngModule: TtCoreModule,
5807
- providers: [
5808
- {
5809
- provide: 'environment',
5810
- useValue: environment
5811
- }
5812
- ]
5813
- };
5441
+ isInvalid() {
5442
+ return this.status === BankConnectionStatusEnum.INVALID;
5814
5443
  }
5815
- }
5816
- TtCoreModule.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.2.15", ngImport: i0, type: TtCoreModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule });
5817
- TtCoreModule.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "12.0.0", version: "12.2.15", ngImport: i0, type: TtCoreModule, imports: [CommonModule,
5818
- InterceptorsModule] });
5819
- TtCoreModule.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "12.2.15", ngImport: i0, type: TtCoreModule, imports: [[
5820
- CommonModule,
5821
- InterceptorsModule
5822
- ]] });
5823
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.15", ngImport: i0, type: TtCoreModule, decorators: [{
5824
- type: NgModule,
5825
- args: [{
5826
- declarations: [],
5827
- imports: [
5828
- CommonModule,
5829
- InterceptorsModule
5830
- ]
5831
- }]
5832
- }] });
5444
+ isPending() {
5445
+ return this.status === BankConnectionStatusEnum.PENDING;
5446
+ }
5447
+ isActive() {
5448
+ return this.status === BankConnectionStatusEnum.ACTIVE;
5449
+ }
5450
+ /**
5451
+ * login required for new or disconnected external connections
5452
+ */
5453
+ isLoginRequired() {
5454
+ return !!(!this.id && this.bank.externalId && !this.bank.isManual) || this.isInvalid();
5455
+ }
5456
+ setPending() {
5457
+ this.status = BankConnectionStatusEnum.PENDING;
5458
+ }
5459
+ }
5460
+ __decorate([
5461
+ Type(() => BasiqJob)
5462
+ ], BankConnection.prototype, "basiqJob", void 0);
5463
+ __decorate([
5464
+ Type(() => Bank)
5465
+ ], BankConnection.prototype, "bank", void 0);
5833
5466
 
5834
- class VehicleClaimCollection extends Collection {
5467
+ class BankAccount extends BankAccount$1 {
5468
+ get bank() {
5469
+ return this.bankConnection.bank;
5470
+ }
5471
+ get bsb() {
5472
+ return this.accountNumber.split(' ')[0];
5473
+ }
5474
+ get number() {
5475
+ return this.accountNumber.split(' ')[1];
5476
+ }
5835
5477
  /**
5836
- * Get remaining kilometers limit. Total limit ({@link VehicleClaim.totalKmsLimit}) - claimed kilometers from other vehicle claims
5478
+ * Get last digits of account number
5837
5479
  */
5838
- getKmsLimitForClaim(claim) {
5839
- let collection = this;
5840
- if (claim) {
5841
- collection = collection.removeBy('id', claim.id);
5842
- }
5843
- return VehicleClaim.totalKmsLimit - collection.sumBy('kilometers');
5480
+ get partialAccountNumber() {
5481
+ return `xxxx${this.accountNumber.slice(-4)}`;
5844
5482
  }
5845
5483
  /**
5846
- * Get remaining work usage limit. Total limit ({@link VehicleClaim.totalWorkUsagePercent}) - claimed percent from other vehicle claims
5484
+ * Get current opening balance amount
5847
5485
  */
5848
- getWorkUsageLimitForClaim(claim) {
5849
- let collection = this;
5850
- if (claim) {
5851
- collection = collection.removeBy('id', claim.id);
5852
- }
5853
- return VehicleClaim.totalWorkUsagePercent - collection.sumBy('workUsage');
5486
+ getOpeningBalance() {
5487
+ var _a;
5488
+ return ((_a = this.getCurrentYearBalance()) === null || _a === void 0 ? void 0 : _a.openingBalance) || 0;
5854
5489
  }
5855
- }
5856
-
5857
- class VehicleLogbookCollection extends Collection {
5858
5490
  /**
5859
- * Best period may be calculated only when user has logbooks minimum for VehicleLogbook.bestPeriodWeeks
5860
- * @TODO Vik: Best period: move this and related logic to backend
5491
+ * Get bank account balance for current financial year
5861
5492
  */
5862
- isBestPeriodExist() {
5863
- if (this.items.length < 2) {
5864
- return false;
5865
- }
5866
- return VehicleLogbook.bestPeriodDuration < (this.last.date.getTime() - this.first.date.getTime());
5493
+ getCurrentYearBalance() {
5494
+ const currentFinYear = new FinancialYear().year;
5495
+ return this.balances.find((balance) => balance.financialYear === currentFinYear);
5867
5496
  }
5868
5497
  /**
5869
- * Get collection of non-personal logbooks (work-related, sole-related).
5870
- * @TODO Vik: Best period: move this and related logic to backend
5498
+ * check if bank account type is one of savings accounts
5871
5499
  */
5872
- getClaimableLogbooks() {
5873
- return this.filterBy('isPersonal', false);
5500
+ isSavingsAccount() {
5501
+ return this.type === BankAccountTypeEnum.INVESTMENT ||
5502
+ this.type === BankAccountTypeEnum.TERM_DEPOSIT ||
5503
+ this.type === BankAccountTypeEnum.SAVINGS;
5874
5504
  }
5875
5505
  /**
5876
- * Get Logbook Period with the biggest work usage percent
5877
- * Best period duration is defined as VehicleLogbook.bestPeriodWeeks by the ATO
5878
- * @TODO Vik: Best period: move this and related logic to backend
5506
+ * check if bank account type is Loan
5879
5507
  */
5880
- getBestPeriod() {
5881
- if (!this.isBestPeriodExist()) {
5882
- return null;
5883
- }
5884
- let bestPeriod;
5885
- // get list of all logbooks available for best period calculation
5886
- const claimableLogbooks = this.getClaimableLogbooks().toArray();
5887
- for (let i = 0; i < claimableLogbooks.length; i++) {
5888
- // no sense to check next logbooks because we already get the end of the year
5889
- if (bestPeriod && bestPeriod.isEndOfYear()) {
5890
- break;
5891
- }
5892
- // get date range started from current handling logbook date
5893
- const dateRange = claimableLogbooks[i].getPeriod();
5894
- // get all logbooks included in current logbook period
5895
- const logbooksInRange = this.filterByRange('date', dateRange.start, dateRange.end);
5896
- const currentPeriod = plainToClass(LogbookPeriod, {
5897
- from: dateRange.start,
5898
- to: dateRange.end,
5899
- kilometers: logbooksInRange.getClaimableLogbooks().kilometers,
5900
- workUsage: logbooksInRange.getWorkUsage(),
5901
- logbooks: logbooksInRange
5902
- });
5903
- // compare with previous best period and overwrite if needs
5904
- if (!bestPeriod || currentPeriod.workUsage > bestPeriod.workUsage) {
5905
- bestPeriod = currentPeriod;
5906
- }
5907
- else if (currentPeriod.workUsage === bestPeriod.workUsage) {
5908
- // if work usage is the same then get period with the biggest work usage for work tank
5909
- const oldWorkUsage = bestPeriod.logbooks.filterBy('tankType', TankTypeEnum.WORK).getWorkUsage();
5910
- const currentWorkUsage = currentPeriod.logbooks.filterBy('tankType', TankTypeEnum.WORK).getWorkUsage();
5911
- if (oldWorkUsage < currentWorkUsage) {
5912
- bestPeriod = currentPeriod;
5913
- }
5914
- }
5915
- }
5916
- return bestPeriod;
5508
+ isLoan() {
5509
+ return this.type === BankAccountTypeEnum.LOAN;
5917
5510
  }
5918
5511
  /**
5919
- * Calculate total kilometers traveled
5512
+ * check if bank account type is Credit card
5920
5513
  */
5921
- get kilometers() {
5922
- return this.sumBy('kilometers');
5514
+ isCreditCard() {
5515
+ return this.type === BankAccountTypeEnum.CREDIT_CARD;
5923
5516
  }
5924
5517
  /**
5925
- * Calculate work usage (percent of business-related kilometers from total kilometers)
5926
- * @TODO Alex: TT-2089 replace with getter
5518
+ * check if bank account related to work tank
5927
5519
  */
5928
- getWorkUsage() {
5929
- const workKilometers = this.getClaimableLogbooks().kilometers;
5930
- return Math.round(workKilometers / this.kilometers * 100);
5520
+ isWorkTank() {
5521
+ return !this.isPropertyTank() && !this.isSoleTank();
5931
5522
  }
5932
5523
  /**
5933
- * Get list of logbooks related to passed vehicle claim
5524
+ * check if bank account related to work tank
5934
5525
  */
5935
- getByVehicleClaim(vehicleClaim) {
5936
- return vehicleClaim.isSoleTank()
5937
- // sole tank may have multiple vehicle claims, so we need to filter by business.id
5938
- ? this.filterBy('business.id', vehicleClaim.business.id)
5939
- // work tank may have only one vehicle claim, so we need to filter by tank type
5940
- : this.filterBy('tankType', TankTypeEnum.WORK);
5526
+ isPropertyTank() {
5527
+ return !!this.bankAccountProperties.length;
5941
5528
  }
5942
- }
5943
-
5944
- /**
5945
- * List of objects grouped by passed property
5946
- */
5947
- class Dictionary {
5948
- constructor(items, path = 'id') {
5949
- this.items = {};
5950
- if (!items.length) {
5951
- return;
5529
+ /**
5530
+ * check if bank account related to sole tank
5531
+ */
5532
+ isSoleTank() {
5533
+ return !!this.businessAllocations.length;
5534
+ }
5535
+ get tankType() {
5536
+ switch (true) {
5537
+ case this.isPropertyTank():
5538
+ return TankTypeEnum.PROPERTY;
5539
+ case this.isSoleTank():
5540
+ return TankTypeEnum.SOLE;
5541
+ default:
5542
+ return TankTypeEnum.WORK;
5952
5543
  }
5953
- // Do nothing if provided path was not found in the 1st item
5954
- if (!hasIn(items[0], path.split('.')[0])) {
5955
- return;
5544
+ }
5545
+ /**
5546
+ * Get Bank account property by id
5547
+ * @param id Id of property
5548
+ */
5549
+ getPropertyById(id) {
5550
+ return this.bankAccountProperties.find((bankAccountProperty) => bankAccountProperty.property.id === id);
5551
+ }
5552
+ /**
5553
+ * check if bank account is related with passed property by id
5554
+ * @param propertyId Property id for checking
5555
+ */
5556
+ hasProperty(propertyId) {
5557
+ return !!this.getPropertyById(propertyId);
5558
+ }
5559
+ /**
5560
+ * Get decimal percentage for property
5561
+ * @param propertyId Id of property
5562
+ */
5563
+ getPropertyPercentage(propertyId) {
5564
+ if (!this.hasProperty(propertyId)) {
5565
+ return 0;
5956
5566
  }
5957
- this.groupItems(items, path);
5567
+ return this.getPropertyById(propertyId).percent / 100;
5958
5568
  }
5959
- add(key, value) {
5960
- this.items[key] = value;
5569
+ /**
5570
+ * Get balance amount for property by id
5571
+ * @param propertyId Id of property
5572
+ */
5573
+ getPropertyBalanceAmount(propertyId) {
5574
+ return this.currentBalance * this.getPropertyPercentage(propertyId);
5961
5575
  }
5962
- get(key) {
5963
- return this.items[key] !== undefined ? this.items[key] : null;
5576
+ /**
5577
+ * Check if bank account is active (has 'active' status or hasn't been paid out/refinanced)
5578
+ */
5579
+ isActive() {
5580
+ return this.status === BankAccountStatusEnum.ACTIVE;
5964
5581
  }
5965
- groupItems(items, path) {
5966
- items.forEach((item) => {
5967
- let key = get(item, path);
5968
- // if object does not have property for grouping it will be grouped as 'other'
5969
- if (key === undefined) {
5970
- key = 'other';
5971
- }
5972
- this.items[key] = item;
5973
- });
5582
+ /**
5583
+ * first import (transactions) of basiq accounts
5584
+ */
5585
+ isFirstImport() {
5586
+ return !this.lastTransactionDate && !this.isManual;
5587
+ }
5588
+ /**
5589
+ * Check if passed user id is owner of bank account
5590
+ */
5591
+ isOwner(userId) {
5592
+ return this.bankConnection.user.id === userId;
5593
+ }
5594
+ /**
5595
+ * Loan is paid if it has no unallocated transactions and the bank balance is $0.
5596
+ */
5597
+ isLoanPaid(taxTankBalance) {
5598
+ const shouldPayoutLoanAccount = this.isActive() && this.isLoan() && taxTankBalance === 0;
5599
+ // we don't check current balance for basiq accounts, because basiq doesn't provide us last transactions (can't do for closed accounts),
5600
+ // that's why balance won't be 0 (updated by basiq)
5601
+ if (shouldPayoutLoanAccount && this.isManual) {
5602
+ return this.currentBalance === 0;
5603
+ }
5604
+ return shouldPayoutLoanAccount;
5974
5605
  }
5975
5606
  }
5607
+ __decorate([
5608
+ Type(() => BankAccountProperty)
5609
+ ], BankAccount.prototype, "bankAccountProperties", void 0);
5610
+ __decorate([
5611
+ Type(() => SoleBusinessAllocation)
5612
+ ], BankAccount.prototype, "businessAllocations", void 0);
5613
+ __decorate([
5614
+ Type(() => BankAccountBalance)
5615
+ ], BankAccount.prototype, "balances", void 0);
5616
+ __decorate([
5617
+ Type(() => Loan)
5618
+ ], BankAccount.prototype, "loan", void 0);
5619
+ __decorate([
5620
+ Type(() => BankConnection)
5621
+ ], BankAccount.prototype, "bankConnection", void 0);
5622
+ __decorate([
5623
+ Transform(({ value }) => value === 4 ? BankAccountTypeEnum.LOAN : value)
5624
+ ], BankAccount.prototype, "type", void 0);
5976
5625
 
5977
- class SoleBusinessLossesCollection extends Collection {
5626
+ /**
5627
+ * bank account collection UI class with frontend specific data
5628
+ */
5629
+ class BankAccountChartData {
5630
+ constructor(bankAccounts) {
5631
+ this.bankAccounts = bankAccounts;
5632
+ }
5978
5633
  /**
5979
- * Business loss applied in current year, includes previous year losses and current year losses for businesses matching offset rule
5634
+ * set value of pie chart data
5980
5635
  */
5981
- calculateBusinessLossApplied(transactions) {
5982
- // claim amounts for businesses that can be applied to be reduced by prior year business losses
5983
- const claimAmountsByBusinessId = this.getClaimAmountsByBusinessId(transactions);
5984
- return Object.keys(claimAmountsByBusinessId.items).reduce((sum, businessId) => {
5985
- const loss = this.findBy('business.id', +businessId);
5986
- const lossOpenBalance = (loss === null || loss === void 0 ? void 0 : loss.openBalance) || 0;
5987
- // business loss can be applied to business profit or other income types profit in case in offset rule met
5988
- return sum + (loss.offsetRule ? lossOpenBalance : Math.min(lossOpenBalance, claimAmountsByBusinessId.get(businessId)));
5989
- }, 0);
5636
+ getBalancePieChartData() {
5637
+ return this.bankAccounts.map((bankAccount) => {
5638
+ return {
5639
+ name: bankAccount.accountName,
5640
+ data: Math.abs(bankAccount.currentBalance)
5641
+ };
5642
+ });
5990
5643
  }
5991
5644
  /**
5992
- * Get business claim amounts that can be applied to be reduced by prior year business losses:
5993
- * businesses with income or businesses with a loss, but which met the non-commercial loss rules
5994
- * https://www.ato.gov.au/Business/Non-commercial-losses/
5645
+ * set value of bar chart data
5995
5646
  */
5996
- getClaimAmountsByBusinessId(transactions) {
5997
- const claimAmountsByBusinessId = new Dictionary([]);
5998
- const transactionsByBusinessId = new CollectionDictionary(transactions, 'business.id');
5999
- transactionsByBusinessId.keys.forEach((businessId) => {
6000
- var _a;
6001
- // business loss may not exist if, when creating a business, user didn't add losses for previous years
6002
- const lossOffsetRule = (_a = this.findBy('business.id', +businessId)) === null || _a === void 0 ? void 0 : _a.offsetRule;
6003
- const businessClaimAmount = transactionsByBusinessId
6004
- .get(businessId)
6005
- .getClaimAmountByBusinessId(+businessId);
6006
- // no way to apply loss for business without profit if offset rules not met
6007
- if (businessClaimAmount < 0 && !lossOffsetRule) {
6008
- return;
6009
- }
6010
- claimAmountsByBusinessId.add(businessId, businessClaimAmount);
6011
- });
6012
- return claimAmountsByBusinessId;
5647
+ getBalanceBarChartData() {
5648
+ return [{
5649
+ name: 'Balance',
5650
+ data: this.bankAccounts.map((bankAccount) => {
5651
+ return {
5652
+ label: bankAccount.accountName,
5653
+ value: bankAccount.currentBalance
5654
+ };
5655
+ })
5656
+ }];
6013
5657
  }
6014
5658
  }
6015
5659
 
6016
- class SoleInvoiceCollection extends Collection {
6017
- getOverdue() {
6018
- return this.filter((invoice) => invoice.isOverdue());
6019
- }
6020
- getUnpaid() {
6021
- return this.filter((invoice) => invoice.isUnpaid());
6022
- }
6023
- getPaid() {
6024
- return this.filter((invoice) => invoice.isPaid());
6025
- }
6026
- getPending() {
6027
- return this.filter((invoice) => invoice.isPending());
6028
- }
6029
- getTransactionsIds() {
6030
- return flatten(this.items.map((invoice) => invoice.getTransactionsIds()));
6031
- }
5660
+ /**
5661
+ * Const which contains array of bank account types
5662
+ */
5663
+ const BANK_ACCOUNT_TYPES = [
5664
+ { key: BankAccountTypeEnum.CREDIT_CARD, value: 'Credit Card Accounts' },
5665
+ { key: BankAccountTypeEnum.TERM_DEPOSIT, value: 'Deposit Accounts' },
5666
+ { key: BankAccountTypeEnum.INVESTMENT, value: 'Investment Accounts' },
5667
+ { key: BankAccountTypeEnum.LOAN, value: 'Loan Accounts' },
5668
+ { key: BankAccountTypeEnum.OFFSET, value: 'Offset' },
5669
+ { key: BankAccountTypeEnum.SAVINGS, value: 'Savings Accounts' },
5670
+ { key: BankAccountTypeEnum.TRANSACTION, value: 'Transaction Accounts' },
5671
+ ];
5672
+
5673
+ /**
5674
+ * Login data object for basiq banks
5675
+ */
5676
+ class BankLoginData {
6032
5677
  }
6033
5678
 
6034
- class PropertySaleCollection extends Collection {
6035
- get grossCGT() {
6036
- return this.create(this.items.filter((propertySale) => propertySale.grossCGT > 0)).sumBy('grossCGT');
5679
+ /**
5680
+ * enum with months indexes.
5681
+ * item value match with js Date month index from 0 to 11
5682
+ * Order of items match with financial year months order
5683
+ */
5684
+ var MonthNumberEnum;
5685
+ (function (MonthNumberEnum) {
5686
+ MonthNumberEnum[MonthNumberEnum["JULY"] = 6] = "JULY";
5687
+ MonthNumberEnum[MonthNumberEnum["AUGUST"] = 7] = "AUGUST";
5688
+ MonthNumberEnum[MonthNumberEnum["SEPTEMBER"] = 8] = "SEPTEMBER";
5689
+ MonthNumberEnum[MonthNumberEnum["OCTOBER"] = 9] = "OCTOBER";
5690
+ MonthNumberEnum[MonthNumberEnum["NOVEMBER"] = 10] = "NOVEMBER";
5691
+ MonthNumberEnum[MonthNumberEnum["DECEMBER"] = 11] = "DECEMBER";
5692
+ MonthNumberEnum[MonthNumberEnum["JANUARY"] = 0] = "JANUARY";
5693
+ MonthNumberEnum[MonthNumberEnum["FEBRUARY"] = 1] = "FEBRUARY";
5694
+ MonthNumberEnum[MonthNumberEnum["MARCH"] = 2] = "MARCH";
5695
+ MonthNumberEnum[MonthNumberEnum["APRIL"] = 3] = "APRIL";
5696
+ MonthNumberEnum[MonthNumberEnum["MAY"] = 4] = "MAY";
5697
+ MonthNumberEnum[MonthNumberEnum["JUNE"] = 5] = "JUNE";
5698
+ })(MonthNumberEnum || (MonthNumberEnum = {}));
5699
+
5700
+ /**
5701
+ * @TODO move to pipe/translation
5702
+ * enum with months short names.
5703
+ * Order of items match with financial year months order
5704
+ */
5705
+ var MonthNameShortEnum;
5706
+ (function (MonthNameShortEnum) {
5707
+ MonthNameShortEnum["JULY"] = "Jul";
5708
+ MonthNameShortEnum["AUGUST"] = "Aug";
5709
+ MonthNameShortEnum["SEPTEMBER"] = "Sep";
5710
+ MonthNameShortEnum["OCTOBER"] = "Oct";
5711
+ MonthNameShortEnum["NOVEMBER"] = "Nov";
5712
+ MonthNameShortEnum["DECEMBER"] = "Dec";
5713
+ MonthNameShortEnum["JANUARY"] = "Jan";
5714
+ MonthNameShortEnum["FEBRUARY"] = "Feb";
5715
+ MonthNameShortEnum["MARCH"] = "Mar";
5716
+ MonthNameShortEnum["APRIL"] = "Apr";
5717
+ MonthNameShortEnum["MAY"] = "May";
5718
+ MonthNameShortEnum["JUNE"] = "Jun";
5719
+ })(MonthNameShortEnum || (MonthNameShortEnum = {}));
5720
+
5721
+ /**
5722
+ * bank transactions collection UI class with frontend specific data
5723
+ */
5724
+ class BankTransactionChartData {
5725
+ constructor(bankTransactions) {
5726
+ this.bankTransactions = bankTransactions;
6037
5727
  }
6038
5728
  /**
6039
- * Property sales are CGT applicable unless it has "Principle place of residence" exemption type
5729
+ * get value of bar chart data
6040
5730
  */
6041
- getCGTApplicable() {
6042
- return this.create(this.items.filter((propertySale) => propertySale.isCGTApplicable()));
6043
- }
6044
- getByPropertyShareIds(ids) {
6045
- return this.filterBy('share.id', ids);
5731
+ getCashInOutBarChartData(months) {
5732
+ const chartData = this.calculateCashInOutBarChartData();
5733
+ if (!months) {
5734
+ return chartData;
5735
+ }
5736
+ return this.filterChartDataByMonths(months, chartData);
6046
5737
  }
6047
- }
6048
-
6049
- class PropertyCollection extends Collection {
6050
5738
  /**
6051
- * Get new property collection filtered by category id
6052
- * @param id id of category for filter
5739
+ * get value of line chart data
6053
5740
  */
6054
- getByCategoryId(id) {
6055
- return new PropertyCollection(this.items.filter((property) => property.category.id === id));
5741
+ getBalanceLineChartData(months) {
5742
+ const chartData = this.calculateBalanceLineChartData();
5743
+ if (!months) {
5744
+ return chartData;
5745
+ }
5746
+ return this.filterChartDataByMonths(months, chartData);
6056
5747
  }
6057
5748
  /**
6058
- * Get new property collection filtered by active status
5749
+ * set bar chart data
6059
5750
  */
6060
- getActiveProperties() {
6061
- return new PropertyCollection(this.items.filter((property) => property.isActive));
5751
+ calculateCashInOutBarChartData() {
5752
+ const chartData = [{
5753
+ name: 'Cash In',
5754
+ data: []
5755
+ }, {
5756
+ name: 'Cash Out',
5757
+ data: []
5758
+ }];
5759
+ for (const key in MonthNameShortEnum) {
5760
+ if (MonthNameShortEnum.hasOwnProperty(key)) {
5761
+ const bankTransactionsForMonth = this.bankTransactions.filter((bankTransaction) => {
5762
+ return +bankTransaction.date.getMonth() === +MonthNumberEnum[key];
5763
+ });
5764
+ const cashInForMonth = bankTransactionsForMonth
5765
+ .filter((bankTransaction) => bankTransaction.isCredit())
5766
+ .reduce((sum, bankTransaction) => sum += bankTransaction.allocatedAmount, 0);
5767
+ const cashOutForMonth = bankTransactionsForMonth
5768
+ .filter((bankTransaction) => bankTransaction.isDebit())
5769
+ .reduce((sum, bankTransaction) => sum += bankTransaction.allocatedAmount, 0);
5770
+ chartData[0].data.push({
5771
+ label: MonthNameShortEnum[key],
5772
+ value: cashInForMonth
5773
+ });
5774
+ chartData[1].data.push({
5775
+ label: MonthNameShortEnum[key],
5776
+ value: cashOutForMonth
5777
+ });
5778
+ }
5779
+ }
5780
+ return chartData;
6062
5781
  }
6063
- getCreatedProperties() {
6064
- return new PropertyCollection(this.items.filter((property) => property.isOwn()));
5782
+ /**
5783
+ * set line chart data
5784
+ */
5785
+ calculateBalanceLineChartData() {
5786
+ const chartData = [{
5787
+ name: 'Balance',
5788
+ data: []
5789
+ }];
5790
+ for (const key in MonthNameShortEnum) {
5791
+ if (MonthNameShortEnum.hasOwnProperty(key)) {
5792
+ const bankTransactionsForMonth = this.bankTransactions.filter((bankTransaction) => {
5793
+ return +bankTransaction.date.getMonth() === +MonthNumberEnum[key];
5794
+ });
5795
+ const balanceForMonth = bankTransactionsForMonth.reduce((sum, bankTransaction) => {
5796
+ if (bankTransaction.isCredit()) {
5797
+ return sum += bankTransaction.allocatedAmount;
5798
+ }
5799
+ else {
5800
+ return sum -= bankTransaction.allocatedAmount;
5801
+ }
5802
+ }, 0);
5803
+ chartData[0].data.push({
5804
+ label: MonthNameShortEnum[key],
5805
+ value: balanceForMonth
5806
+ });
5807
+ }
5808
+ }
5809
+ return chartData;
6065
5810
  }
6066
5811
  /**
6067
- * Get new property collection filtered by shared
5812
+ * filter chart data for passed months
6068
5813
  */
6069
- getSharedProperties() {
6070
- return new PropertyCollection(this.items.filter((property) => !property.isOwn()));
5814
+ filterChartDataByMonths(months, chartData) {
5815
+ const monthsNames = months.map((month) => MonthNumberEnum[month]).map((key) => MonthNameShortEnum[key]);
5816
+ const filteredChartData = cloneDeep$1(chartData);
5817
+ filteredChartData.forEach((chartDataItem) => {
5818
+ chartDataItem.data = chartDataItem.data.filter((serie) => monthsNames.includes(serie.label));
5819
+ });
5820
+ return filteredChartData;
5821
+ }
5822
+ }
5823
+
5824
+ var BankTransactionSummaryFieldsEnum;
5825
+ (function (BankTransactionSummaryFieldsEnum) {
5826
+ BankTransactionSummaryFieldsEnum["AMOUNT"] = "amount";
5827
+ BankTransactionSummaryFieldsEnum["ALLOCATED_AMOUNT"] = "allocatedAmount";
5828
+ })(BankTransactionSummaryFieldsEnum || (BankTransactionSummaryFieldsEnum = {}));
5829
+
5830
+ class Document$1 extends AbstractModel {
5831
+ }
5832
+
5833
+ /**
5834
+ * Enum with document types which used to API url prefix
5835
+ */
5836
+ var DocumentApiUrlPrefixEnum;
5837
+ (function (DocumentApiUrlPrefixEnum) {
5838
+ DocumentApiUrlPrefixEnum["FOLDERS"] = "folders";
5839
+ DocumentApiUrlPrefixEnum["PROPERTIES"] = "properties";
5840
+ })(DocumentApiUrlPrefixEnum || (DocumentApiUrlPrefixEnum = {}));
5841
+
5842
+ class Document extends Document$1 {
5843
+ constructor() {
5844
+ super(...arguments);
5845
+ this.type = AssetTypeEnum.DOCUMENT;
5846
+ this.entityType = AssetEntityTypeEnum.FOLDERS;
6071
5847
  }
6072
5848
  /**
6073
- * Properties that are taxed and will be included in reports (Tax summary, My tax report, e.t.c.)
5849
+ * Get folder as document parent entity
6074
5850
  */
6075
- getTaxInclusive() {
6076
- return this.create(this.items.filter((property) => property.category.isTaxInclusive));
6077
- }
6078
- getUnsold() {
6079
- return this.create(this.items.filter((property) => !property.isSold()));
5851
+ getEntity() {
5852
+ return this.folder;
6080
5853
  }
6081
5854
  /**
6082
- * Get total purchase price for all properties in the collection
5855
+ * Get API url prefix
6083
5856
  */
6084
- get purchasePrice() {
6085
- return this.sumBy('purchasePrice');
5857
+ getApiUrlPrefix() {
5858
+ return DocumentApiUrlPrefixEnum.FOLDERS;
6086
5859
  }
6087
- get growthPercent() {
6088
- return this.sumBy('growthPercent');
5860
+ }
5861
+
5862
+ class DocumentFolder$1 extends AbstractModel {
5863
+ }
5864
+
5865
+ class DocumentFolder extends DocumentFolder$1 {
5866
+ }
5867
+ __decorate([
5868
+ Type(() => Document)
5869
+ ], DocumentFolder.prototype, "documents", void 0);
5870
+
5871
+ /**
5872
+ * BankConnection means user account at specific bank (usually each user has only one at the same bank)
5873
+ * service handles BankConnection management
5874
+ */
5875
+ class BankConnectionService extends RestService$1 {
5876
+ constructor() {
5877
+ super(...arguments);
5878
+ this.modelClass = BankConnection;
5879
+ this.url = 'bank-connections';
6089
5880
  }
6090
- get marketValue() {
6091
- return this.sumBy('marketValue');
5881
+ listenEvents() {
5882
+ this.listenToAddedBankAccounts();
5883
+ this.listenNotifications();
5884
+ this.listenBasiqLogin();
6092
5885
  }
6093
- get firstForecastYear() {
6094
- return this.items.reduce((min, property) => {
6095
- const current = property.firstForecastYear;
6096
- return min > current ? current : min;
6097
- }, new FinancialYear().year);
5886
+ add(bankConnection) {
5887
+ return this.http.post(`${this.environment.apiV2}/${this.url}`, bankConnection)
5888
+ .pipe(map((bankConnectionBase) => {
5889
+ const connection = plainToClass(BankConnection, bankConnectionBase);
5890
+ // We use this endpoint for create and reconnect bank connections because of basiq logic.
5891
+ // So we try to replace bank connection in cache for reconnection case.
5892
+ if (this.cache) {
5893
+ if (bankConnection.id) {
5894
+ const tempCache = cloneDeep$1(this.cache);
5895
+ replace(tempCache, connection);
5896
+ this.cache = tempCache;
5897
+ this.cacheSubject.next(this.cache);
5898
+ }
5899
+ else {
5900
+ this.cache.push(connection);
5901
+ this.cacheSubject.next(cloneDeep$1(this.cache));
5902
+ }
5903
+ }
5904
+ this.eventDispatcherService.dispatch(new AppEvent(AppEventTypeEnum.BANK_CONNECTION_ADDED, connection));
5905
+ return plainToClass(BankConnection, connection);
5906
+ }), catchError((error) => {
5907
+ // Show error when user provided wrong login data
5908
+ if (error.status === 401) {
5909
+ this.toastService.error('Invalid credentials');
5910
+ }
5911
+ // Show error when user provided another login (not login he used before)
5912
+ if (error.status === 400) {
5913
+ this.toastService.error('Please enter the login you used before');
5914
+ }
5915
+ return throwError$1(error);
5916
+ }));
6098
5917
  }
6099
- get marketValueGrowth() {
6100
- return (this.marketValue - this.purchasePrice) / this.purchasePrice;
5918
+ listenToAddedBankAccounts() {
5919
+ this.eventDispatcherService.on(AppEventTypeEnum.BANK_ACCOUNT_CREATED).subscribe(() => {
5920
+ this.resetCache();
5921
+ });
6101
5922
  }
6102
5923
  /**
6103
- * list of properties
5924
+ * Update cache when basiq accounts were retrieved or login to basic was failed to get actual connections statuses
6104
5925
  */
6105
- getCGTApplicable() {
6106
- return this.create(this.items.filter((property) => property.isCGTApplicable()));
6107
- }
6108
- getOwnerOccupiedProperties() {
6109
- return new PropertyCollection(this.items.filter((property) => property.category.isOwnerOccupied()));
6110
- }
6111
- get earliestContractDate() {
6112
- return this.items.reduce((min, property) => {
6113
- return min < property.contractDate ? min : property.contractDate;
6114
- }, new FinancialYear(new Date()).startDate);
5926
+ listenNotifications() {
5927
+ // @TODO vik listen sse when backend updated
5928
+ this.eventDispatcherService.on(AppEventTypeEnum.NOTIFICATION_ADDED).subscribe((notification) => {
5929
+ // @Todo TT-2280 Alex refactor ServiceNotification isRead logic. We don't need to know here whether notification was read or not
5930
+ if (!notification.isRead) {
5931
+ return;
5932
+ }
5933
+ if (BankConnectionService.userEventTypes.includes(notification.eventType)) {
5934
+ this.resetCache();
5935
+ }
5936
+ });
6115
5937
  }
6116
5938
  /**
6117
- * Get list of unique property categories from collection
5939
+ * Create/reconnect bank connection when user successfully logged in to basiq
6118
5940
  */
6119
- getCategories() {
6120
- return uniqBy(this.items.map((property) => property.category), 'id');
5941
+ listenBasiqLogin() {
5942
+ this.eventDispatcherService.on(AppEventTypeEnum.BASIQ_LOGIN_SUCCESS).subscribe((data) => {
5943
+ this.add(plainToClass(BankConnection, { id: data.connectionId, basiqJob: { externalId: data.jobId } }))
5944
+ .subscribe(() => { },
5945
+ // When user already has some bank accounts in handling connection and trying to login with different credentials, backend can not save this connection.
5946
+ // So we should handle this case as failed login
5947
+ () => {
5948
+ this.eventDispatcherService.dispatch(new AppEvent(AppEventTypeEnum.BASIQ_LOGIN_FAILED, null));
5949
+ });
5950
+ });
5951
+ }
5952
+ }
5953
+ BankConnectionService.userEventTypes = [
5954
+ UserEventTypeTypeEnum.BASIQ_NEW_ACCOUNTS,
5955
+ UserEventTypeTypeEnum.BASIQ_AUTHORIZATION_FAIL
5956
+ ];
5957
+ BankConnectionService.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.2.15", ngImport: i0, type: BankConnectionService, deps: null, target: i0.ɵɵFactoryTarget.Injectable });
5958
+ BankConnectionService.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "12.2.15", ngImport: i0, type: BankConnectionService, providedIn: 'root' });
5959
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.15", ngImport: i0, type: BankConnectionService, decorators: [{
5960
+ type: Injectable,
5961
+ args: [{
5962
+ providedIn: 'root'
5963
+ }]
5964
+ }] });
5965
+
5966
+ /**
5967
+ * basiq is a middleman between bank and user
5968
+ * service is responsible for fetching bank related information
5969
+ */
5970
+ class BasiqService extends RestService$1 {
5971
+ constructor(http, eventDispatcherService, environment, toastService,
5972
+ // this inject required to init bank connection service and listen basiq login event
5973
+ bankConnectionService) {
5974
+ super(http, eventDispatcherService, environment, toastService);
5975
+ this.http = http;
5976
+ this.eventDispatcherService = eventDispatcherService;
5977
+ this.environment = environment;
5978
+ this.toastService = toastService;
5979
+ this.bankConnectionService = bankConnectionService;
5980
+ this.url = 'basiq/accounts';
5981
+ this.modelClass = BankAccount;
6121
5982
  }
6122
5983
  /**
6123
- * Get property with the highest growth percent
5984
+ * Listen events from Event Dispatcher service
6124
5985
  */
6125
- getBestPerformanceGrowthProperty() {
6126
- return this.items.reduce((max, current) => {
6127
- return max.growthPercent < current.growthPercent ? current : max;
6128
- }, this.first);
5986
+ listenEvents() {
5987
+ this.listenNotifications();
5988
+ this.listenJobCreated();
6129
5989
  }
6130
5990
  /**
6131
- * Get property with the lowest tax position
5991
+ * Start basiq login process.
5992
+ * Create a basiq job, which contain credentials verifying status.
5993
+ * We can not see login result immediately, because it may take some time (average 10-20 sec)
6132
5994
  */
6133
- getBestPerformanceTaxProperty(transactions, depreciations) {
6134
- const transactionsByProperty = transactions.groupBy('property.id');
6135
- const depreciationsByProperty = depreciations.groupBy('property.id');
6136
- return this.items.reduce((min, current) => {
6137
- const minTaxPosition = min.getTaxPosition(transactionsByProperty.get(min.id), depreciationsByProperty.get(min.id));
6138
- const currentTaxPosition = current.getTaxPosition(transactionsByProperty.get(current.id), depreciationsByProperty.get(current.id));
6139
- return minTaxPosition > currentTaxPosition ? current : min;
6140
- }, this.first);
5995
+ login(loginData, userId) {
5996
+ this.http.post(`${BasiqService.basiqApiUrl}/users/${userId}/connections`, loginData)
5997
+ .subscribe((response) => {
5998
+ // we need jobId to check credentials verifying statis from Basiq API
5999
+ // we need connectionId to know if we are creating a new connection or reconnecting existing invalid connection
6000
+ const data = {
6001
+ jobId: response.id,
6002
+ connectionId: loginData.id
6003
+ };
6004
+ this.eventDispatcherService.dispatch(new AppEvent(AppEventTypeEnum.BASIQ_JOB_CREATED, data));
6005
+ });
6006
+ }
6007
+ getByConnection(connection) {
6008
+ return this.get().pipe(map((bankAccounts) => {
6009
+ return new BankAccountCollection(bankAccounts).filterBy('bankConnection.id', connection.id);
6010
+ }));
6011
+ }
6012
+ getNotImportedByConnection(savedAccounts, connection) {
6013
+ return this.getByConnection(connection).pipe(map((bankAccounts) => {
6014
+ return bankAccounts.removeBy('accountId', savedAccounts.mapBy('accountId'));
6015
+ }));
6141
6016
  }
6142
6017
  /**
6143
- * Show best performance properties first
6144
- * https://taxtank.atlassian.net/wiki/spaces/TAXTANK/pages/217677997/Property+Tank+Dashboard
6145
- */
6146
- sortByBestPerformance(transactions, depreciations) {
6147
- const activeProperties = this.getActiveProperties();
6148
- // nothing to sort when no active properties
6149
- if (!activeProperties.length) {
6150
- return this;
6151
- }
6152
- const bestProperties = uniqBy(this.create([
6153
- activeProperties.getBestPerformanceGrowthProperty(),
6154
- activeProperties.getBestPerformanceTaxProperty(transactions, depreciations)
6155
- ]).toArray(), 'id');
6156
- const newItems = this.remove(bestProperties).toArray();
6157
- newItems.unshift(...bestProperties);
6158
- return this.create(newItems);
6018
+ * Get status of credentials verifying. Expected statuses: 'in-progress', 'failed' or 'success'
6019
+ * We send this request by interval until basiq return success or failed.
6020
+ *
6021
+ * Because of Basiq login may take a long time (10-20sec) we have to check job status until it seccess or failed.
6022
+ *
6023
+ * @TODO Alex (TT-2431): check logic and try to remove subscribe, use pipes instead
6024
+ * @TODO Alex (TT-2431): implement some limit and handle (message or something) if basiq stuck
6025
+ * @TODO Alex (TT-2431): check logic and handle case when user cancelled loading
6026
+ */
6027
+ checkLoginStatus(data) {
6028
+ this.http.get(`${BasiqService.basiqApiUrl}/jobs/${data.jobId}`)
6029
+ .pipe(
6030
+ // get verify-credentials step from basiq job
6031
+ map((response) => plainToClass(BasiqJobResponse, response)),
6032
+ // check credentials status again if not finished
6033
+ filter((response) => {
6034
+ if (!response.getVerifyCredentialsStep().isInProgress()) {
6035
+ return true;
6036
+ }
6037
+ setTimeout(() => {
6038
+ this.checkLoginStatus(data);
6039
+ }, BasiqService.bankCredintialsCheckInterval);
6040
+ return false;
6041
+ }))
6042
+ .subscribe((response) => {
6043
+ if (response.getVerifyCredentialsStep().isSuccess()) {
6044
+ this.eventDispatcherService.dispatch(new AppEvent(AppEventTypeEnum.BASIQ_LOGIN_SUCCESS, data));
6045
+ }
6046
+ else {
6047
+ this.eventDispatcherService.dispatch(new AppEvent(AppEventTypeEnum.BASIQ_LOGIN_FAILED, null));
6048
+ }
6049
+ });
6159
6050
  }
6160
- }
6161
-
6162
- class PropertyCategoryMovementCollection extends Collection {
6163
6051
  /**
6164
- * @TODO TT-2355 Alex refactor propertyForecast, use separated api (then I can remove property from param)
6052
+ * listen to notifications to update basiq accounts list
6165
6053
  */
6166
- getByForecast(property, forecast) {
6167
- const financialYear = new FinancialYear(forecast.financialYear);
6168
- return this.filterBy('property.id', property.id).filter((movement) => {
6169
- return movement.fromDate <= financialYear.endDate && !movement.toDate || movement.toDate >= financialYear.startDate;
6054
+ listenNotifications() {
6055
+ this.eventDispatcherService.on(AppEventTypeEnum.NOTIFICATION_ADDED).subscribe((notification) => {
6056
+ if (!notification.isRead && notification.eventType === UserEventTypeTypeEnum.BASIQ_NEW_ACCOUNTS) {
6057
+ this.resetCache();
6058
+ }
6170
6059
  });
6171
6060
  }
6172
- hasCategory(categoryId) {
6173
- return !!this.findBy('propertyCategory.id', categoryId);
6061
+ /**
6062
+ * Start check job credential status when it created
6063
+ */
6064
+ listenJobCreated() {
6065
+ this.eventDispatcherService.on(AppEventTypeEnum.BASIQ_JOB_CREATED).subscribe((data) => {
6066
+ this.checkLoginStatus(data);
6067
+ });
6174
6068
  }
6175
6069
  }
6176
-
6070
+ BasiqService.basiqApiUrl = 'https://au-api.basiq.io';
6177
6071
  /**
6178
- * Chart serie class: chart data item
6179
- * @TODO consider rename to ChartSerieData
6072
+ * Basiq does not provide a hook, so we have to check job status manually every x seconds
6180
6073
  */
6181
- class ChartSerie {
6074
+ BasiqService.bankCredintialsCheckInterval = 3000;
6075
+ BasiqService.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.2.15", ngImport: i0, type: BasiqService, deps: [{ token: i1.HttpClient }, { token: EventDispatcherService }, { token: 'environment' }, { token: ToastService }, { token: BankConnectionService }], target: i0.ɵɵFactoryTarget.Injectable });
6076
+ BasiqService.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "12.2.15", ngImport: i0, type: BasiqService, providedIn: 'root' });
6077
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.15", ngImport: i0, type: BasiqService, decorators: [{
6078
+ type: Injectable,
6079
+ args: [{
6080
+ providedIn: 'root'
6081
+ }]
6082
+ }], ctorParameters: function () { return [{ type: i1.HttpClient }, { type: EventDispatcherService }, { type: undefined, decorators: [{
6083
+ type: Inject,
6084
+ args: ['environment']
6085
+ }] }, { type: ToastService }, { type: BankConnectionService }]; } });
6086
+
6087
+ class BasiqTokenService {
6088
+ constructor(http, environment) {
6089
+ this.http = http;
6090
+ this.environment = environment;
6091
+ this.cacheSubject = new ReplaySubject(1);
6092
+ }
6093
+ /**
6094
+ * Access token to use basiq flow
6095
+ */
6096
+ get() {
6097
+ if (!this.cache || this.cache.isExpired()) {
6098
+ this.http.get(`${this.environment.apiV2}/basiq/tokens`)
6099
+ .pipe(map((response) => {
6100
+ const now = new Date().getTime();
6101
+ return new BasiqToken(response.access_token, new Date(now + response.expires_in * 1000));
6102
+ }))
6103
+ .subscribe((token) => {
6104
+ this.cache = token;
6105
+ this.cacheSubject.next(token);
6106
+ });
6107
+ }
6108
+ return this.cacheSubject.asObservable();
6109
+ }
6182
6110
  }
6111
+ BasiqTokenService.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.2.15", ngImport: i0, type: BasiqTokenService, deps: [{ token: i1.HttpClient }, { token: 'environment' }], target: i0.ɵɵFactoryTarget.Injectable });
6112
+ BasiqTokenService.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "12.2.15", ngImport: i0, type: BasiqTokenService, providedIn: 'root' });
6113
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.15", ngImport: i0, type: BasiqTokenService, decorators: [{
6114
+ type: Injectable,
6115
+ args: [{
6116
+ providedIn: 'root'
6117
+ }]
6118
+ }], ctorParameters: function () { return [{ type: i1.HttpClient }, { type: undefined, decorators: [{
6119
+ type: Inject,
6120
+ args: ['environment']
6121
+ }] }]; } });
6183
6122
 
6184
6123
  /**
6185
- * Chart data class
6186
- * @TODO consider rename to ChartSerie
6124
+ * Interceptor which adds user's basiq token to any http request to basiq api
6187
6125
  */
6188
- class ChartData {
6126
+ class BasiqTokenInterceptor {
6127
+ constructor(basiqTokenService) {
6128
+ this.basiqTokenService = basiqTokenService;
6129
+ }
6130
+ intercept(request, next) {
6131
+ // skip non-basiq requests
6132
+ if (!request.url.includes(BasiqService.basiqApiUrl)) {
6133
+ return next.handle(request);
6134
+ }
6135
+ return this.basiqTokenService.get().pipe(mergeMap((token) => {
6136
+ return next.handle(this.addToken(request, token));
6137
+ }));
6138
+ }
6139
+ addToken(request, token) {
6140
+ return request.clone({
6141
+ setHeaders: {
6142
+ Authorization: 'Bearer ' + token.value
6143
+ }
6144
+ });
6145
+ }
6189
6146
  }
6190
- __decorate([
6191
- Type(() => ChartSerie)
6192
- ], ChartData.prototype, "data", void 0);
6193
-
6194
- const MONTHS = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec', 'Jan'];
6147
+ BasiqTokenInterceptor.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.2.15", ngImport: i0, type: BasiqTokenInterceptor, deps: [{ token: BasiqTokenService }], target: i0.ɵɵFactoryTarget.Injectable });
6148
+ BasiqTokenInterceptor.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "12.2.15", ngImport: i0, type: BasiqTokenInterceptor });
6149
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.15", ngImport: i0, type: BasiqTokenInterceptor, decorators: [{
6150
+ type: Injectable
6151
+ }], ctorParameters: function () { return [{ type: BasiqTokenService }]; } });
6195
6152
 
6196
6153
  /**
6197
- * @TODO extend from TransactionBaseCollection
6198
- * Collection of transactions
6154
+ * server sent events service
6155
+ * https://symfony.com/doc/current/mercure.html
6199
6156
  */
6200
- class TransactionCollection extends ExportableCollection {
6201
- /**
6202
- * @TODO use TransactionBaseCollection instead
6203
- * we use depreciations as expense transactions a lot
6204
- */
6205
- constructor(transactions = [], depreciations = []) {
6206
- super([...transactions, ...depreciations.map((depreciation) => depreciation.toTransaction())]);
6207
- }
6208
- getSoleTransactions() {
6209
- return this.filter((transaction) => transaction.isSoleTank());
6210
- }
6211
- get amount() {
6212
- return this.sumBy('amount');
6157
+ class SseService {
6158
+ constructor(zone, jwtService, environment) {
6159
+ this.zone = zone;
6160
+ this.jwtService = jwtService;
6161
+ this.environment = environment;
6213
6162
  }
6214
6163
  /**
6215
- * Difference between allocated amount and total amount
6164
+ * list to url for server events
6216
6165
  */
6217
- getUnallocatedAmount(allocations) {
6218
- return this.items.reduce((sum, transaction) => {
6219
- return sum + transaction.getUnallocatedAmount(allocations.filterBy('transaction.id', transaction.id));
6220
- }, 0);
6166
+ on(topic) {
6167
+ const url = new URL(this.environment.mercureUrl);
6168
+ url.searchParams.append('topic', `${this.environment.apiV2}/users/${this.jwtService.decodeToken().username}/${topic}`);
6169
+ // tslint:disable-next-line:typedef
6170
+ return new Observable((observer) => {
6171
+ const es = new EventSourcePolyfill(url, {
6172
+ headers: {
6173
+ Authorization: 'Bearer ' + this.jwtService.getToken(),
6174
+ }
6175
+ });
6176
+ es.onmessage = (event) => {
6177
+ this.zone.run(() => observer.next(event));
6178
+ };
6179
+ })
6180
+ .pipe(map((messageEvent) => {
6181
+ return JSON.parse(messageEvent.data);
6182
+ }));
6183
+ }
6184
+ }
6185
+ SseService.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.2.15", ngImport: i0, type: SseService, deps: [{ token: i0.NgZone }, { token: JwtService }, { token: 'environment' }], target: i0.ɵɵFactoryTarget.Injectable });
6186
+ SseService.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "12.2.15", ngImport: i0, type: SseService, providedIn: 'root' });
6187
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.15", ngImport: i0, type: SseService, decorators: [{
6188
+ type: Injectable,
6189
+ args: [{
6190
+ providedIn: 'root'
6191
+ }]
6192
+ }], ctorParameters: function () { return [{ type: i0.NgZone }, { type: JwtService }, { type: undefined, decorators: [{
6193
+ type: Inject,
6194
+ args: ['environment']
6195
+ }] }]; } });
6196
+
6197
+ /**
6198
+ * Service to work with user
6199
+ */
6200
+ class UserService {
6201
+ constructor(http, jwtService, eventDispatcherService, sseService, environment) {
6202
+ this.http = http;
6203
+ this.jwtService = jwtService;
6204
+ this.eventDispatcherService = eventDispatcherService;
6205
+ this.sseService = sseService;
6206
+ this.environment = environment;
6207
+ this.cacheSubject = new ReplaySubject(1);
6208
+ this.listenEvents();
6221
6209
  }
6222
6210
  /**
6223
- * get date of the last transaction
6211
+ * never return cache directly to prevent update
6224
6212
  */
6225
- getLastTransactionDate() {
6226
- return new Date(Math.max.apply(Math, this.items.map((transaction) => transaction.date)));
6227
- }
6228
- get claimAmount() {
6229
- return this.items.reduce((sum, transaction) => sum + transaction.claimAmount, 0);
6230
- }
6231
- get grossClaimAmount() {
6232
- return this.items.reduce((sum, transaction) => sum + transaction.grossClaimAmount, 0);
6213
+ getCache() {
6214
+ return clone(this.cache);
6233
6215
  }
6234
- get grossAmount() {
6235
- return this.items.reduce((sum, transaction) => sum + transaction.grossAmount, 0);
6216
+ listenEvents() {
6217
+ this.listenServiceSubscriptionUpdated();
6236
6218
  }
6237
- getByChartAccountsCategories(categories) {
6238
- return new TransactionCollection(this.items.filter((transaction) => categories.includes(transaction.chartAccounts.category)));
6219
+ get() {
6220
+ if (!this.cache) {
6221
+ this.fetch().subscribe(() => { }, (error) => {
6222
+ // force logout user (clear localStorage) when get current user return error
6223
+ if (error.status === 500) {
6224
+ this.eventDispatcherService.dispatch(new AppEvent(AppEventTypeEnum.CURRENT_USER_GET_FAILED, null));
6225
+ }
6226
+ });
6227
+ }
6228
+ return this.cacheSubject.asObservable();
6239
6229
  }
6240
6230
  /**
6241
- * Get transactions by month
6242
- * @param monthIndex by which desired month should be taken
6231
+ * Get current user
6243
6232
  */
6244
- getByMonth(monthIndex) {
6245
- return new TransactionCollection(this.items.filter((transaction) => transaction.date.getMonth() === monthIndex));
6233
+ fetch() {
6234
+ return this.http.get(`${this.environment.apiV2}/users/current`)
6235
+ .pipe(map((userBase) => {
6236
+ const user = plainToClass(User, userBase);
6237
+ localStorage.setItem('userId', user.id.toString());
6238
+ // @TODO remove
6239
+ localStorage.setItem('financialYear', user.financialYear.toString());
6240
+ this.cache = user;
6241
+ this.cacheSubject.next(this.cache);
6242
+ return user;
6243
+ }));
6246
6244
  }
6247
6245
  /**
6248
- * Get collection of transactions metadata
6246
+ * Register new user
6249
6247
  */
6250
- getTransactionsMetadata() {
6251
- const metadataArray = [];
6252
- this.items.forEach((transaction) => {
6253
- metadataArray.push(...transaction.metadata);
6254
- });
6255
- return new Collection(metadataArray);
6256
- }
6257
- getIncomeTransactions() {
6258
- return new TransactionCollection(this.items.filter((transaction) => transaction.isIncome()));
6259
- }
6260
- getExpenseTransactions() {
6261
- return new TransactionCollection(this.items.filter((transaction) => transaction.isExpense() && !transaction.isInterest()));
6262
- }
6263
- get claimIncome() {
6264
- return this.getIncomeTransactions().claimAmount;
6265
- }
6266
- get claimExpense() {
6267
- return this.getExpenseTransactions().claimAmount;
6268
- }
6269
- getInterestTransactions() {
6270
- return new TransactionCollection(this.items.filter((transaction) => transaction.isInterest()));
6271
- }
6272
- get claimInterest() {
6273
- return this.getInterestTransactions().claimAmount;
6248
+ register(data) {
6249
+ return this.http.post(`${this.environment.apiV2}/users/registration`, data);
6274
6250
  }
6275
6251
  /**
6276
- * Get collection of transactions and properties filtered by properties ids
6277
- * @param ids Ids of properties for filter
6252
+ * Update user
6278
6253
  */
6279
- getByPropertiesIds(ids) {
6280
- return new TransactionCollection(this.items.filter((transaction) => {
6281
- var _a;
6282
- return ids.includes((_a = transaction.property) === null || _a === void 0 ? void 0 : _a.id);
6254
+ update(user) {
6255
+ return this.http.put(`${this.environment.apiV2}/users/${user.id}`, user)
6256
+ .pipe(map((userBase) => {
6257
+ this.cache = plainToClass(User, userBase);
6258
+ this.eventDispatcherService.dispatch(new AppEvent(AppEventTypeEnum.USER_UPDATED, null));
6259
+ this.cacheSubject.next(this.cache);
6283
6260
  }));
6284
6261
  }
6285
6262
  /**
6286
- * Get new collection filtered by income source id
6287
- * @param id id of income source for filter
6263
+ * Change user password
6288
6264
  */
6289
- getByIncomeSourceId(id) {
6290
- return new TransactionCollection(this.items.filter((transaction) => { var _a; return ((_a = transaction.incomeSource) === null || _a === void 0 ? void 0 : _a.id) === id; }));
6265
+ changePassword(currentPassword, newPassword) {
6266
+ return this.http.put(`${this.environment.apiV2}/users/password/change`, { currentPassword, newPassword });
6291
6267
  }
6292
6268
  /**
6293
- * Get new collection filtered by chart accounts category
6294
- * @param category Chart accounts category value
6269
+ * Recovery user password
6295
6270
  */
6296
- getByChartAccountsCategory(category) {
6297
- return new TransactionCollection(this.items.filter((transaction) => transaction.chartAccounts.category === category));
6271
+ recoveryPassword(email) {
6272
+ return this.http.put(`${this.environment.apiV2}/users/password/recovery`, { email });
6298
6273
  }
6299
6274
  /**
6300
- * Get new collection of property transactions
6275
+ * Reset user password
6301
6276
  */
6302
- getPropertyTransactions() {
6303
- return new TransactionCollection(this.items.filter((transaction) => transaction.isPropertyTank()));
6304
- }
6305
- getDebitTransactions() {
6306
- return new TransactionCollection(this.items.filter((transaction) => transaction.isDebit()));
6277
+ resetPassword(newPassword, resetToken) {
6278
+ return this.http.put(`${this.environment.apiV2}/users/password/reset`, { newPassword, resetToken });
6307
6279
  }
6308
- getCreditTransactions() {
6309
- return new TransactionCollection(this.items.filter((transaction) => transaction.isCredit()));
6280
+ resendConfirmationEmail(email) {
6281
+ return this.http.post(`${this.environment.apiV2}/users/confirmation/resend`, { email });
6310
6282
  }
6311
- getByAllocations(allocations) {
6312
- return new TransactionCollection(this.items.filter((transaction) => allocations.hasTransaction(transaction)));
6283
+ /**
6284
+ * Confirm registered user
6285
+ */
6286
+ confirm(verificationCode) {
6287
+ return this.http.post(`${this.environment.apiV2}/users/confirmation`, { verificationCode });
6313
6288
  }
6314
6289
  /**
6315
- * Get transactions related to Vehicle category
6290
+ * Search existing user
6316
6291
  */
6317
- getVehicleTransactions() {
6318
- return this.create(this.items.filter((transaction) => {
6319
- return transaction.isVehicleTransaction();
6292
+ search(email) {
6293
+ return this.http.get(`${this.environment.apiV2}/users/search?email=${email}`)
6294
+ .pipe(map((userBase) => {
6295
+ return plainToClass(User, userBase);
6320
6296
  }));
6321
6297
  }
6322
6298
  /**
6323
- * Get new transaction collection filtered by tank type
6299
+ * Finish onboarding process
6324
6300
  */
6325
- getByTankType(tankType) {
6326
- return this.create(this.items.filter((transaction) => {
6327
- switch (tankType) {
6328
- case TankTypeEnum.PROPERTY:
6329
- return transaction.isPropertyTank();
6330
- case TankTypeEnum.WORK:
6331
- return transaction.isWorkTank();
6332
- case TankTypeEnum.SOLE:
6333
- return transaction.isSoleTank();
6334
- // Transaction may be not related to any tank type (personal)
6335
- default:
6336
- return false;
6337
- }
6301
+ finishOnboarding(user) {
6302
+ return this.http.put(`${this.environment.apiV2}/users/status`, user)
6303
+ .pipe(map(() => {
6304
+ this.cache = user;
6305
+ this.cacheSubject.next(this.cache);
6338
6306
  }));
6339
6307
  }
6340
- getExportHeader() {
6341
- return ['Date', 'Description', 'Debit', 'Credit'];
6342
- }
6343
- getExportFooter() {
6344
- return [
6345
- plainToClass(ExportCell, { value: 'Total', type: ExportCellTypeEnum.STRING }),
6346
- plainToClass(ExportCell, { value: '', type: ExportCellTypeEnum.STRING }),
6347
- plainToClass(ExportCell, { value: this.sumBy('debit'), type: ExportCellTypeEnum.CURRENCY }),
6348
- plainToClass(ExportCell, { value: this.sumBy('credit'), type: ExportCellTypeEnum.CURRENCY })
6349
- ];
6350
- }
6351
- getExportBody() {
6352
- return this.items.map((transaction) => {
6353
- return [
6354
- plainToClass(ExportCell, { value: transaction.date, type: ExportCellTypeEnum.DATE }),
6355
- plainToClass(ExportCell, { value: transaction.description, type: ExportCellTypeEnum.STRING }),
6356
- plainToClass(ExportCell, { value: transaction.debit, type: ExportCellTypeEnum.CURRENCY }),
6357
- plainToClass(ExportCell, { value: transaction.credit, type: ExportCellTypeEnum.CURRENCY })
6358
- ];
6359
- });
6360
- }
6361
6308
  /**
6362
- * Get list of vehicle transactions filtered by vehicle claim
6309
+ * Update user photo
6363
6310
  */
6364
- getByVehicleClaim(vehicleClaim) {
6365
- if (!vehicleClaim) {
6366
- return this.create([]);
6367
- }
6368
- return vehicleClaim.isSoleTank()
6369
- // sole tank may have multiple vehicle claims, so we need to filter by business.id
6370
- ? this.getVehicleTransactions().filterBy('business.id', vehicleClaim.business.id)
6371
- // work tank may have only one vehicle claim, so we need to filter by tank type
6372
- : this.getVehicleTransactions().filterBy('tankType', TankTypeEnum.WORK);
6311
+ updatePhoto(photo) {
6312
+ return this.http.post(`${this.environment.apiV2}/users/photo?_method=PUT`, photo)
6313
+ .pipe(map((photoUrl) => {
6314
+ this.cache = plainToClass(User, Object.assign(this.cache, { photo: photoUrl }));
6315
+ this.cacheSubject.next(this.cache);
6316
+ }));
6317
+ }
6318
+ switchFinancialYear(year) {
6319
+ return this.http.get(`${this.environment.apiV2}/financial-year/switch`, { params: new HttpParams({ fromString: `financialYear=${year}` }) }).pipe(map(() => {
6320
+ localStorage.setItem('financialYear', year.toString());
6321
+ window.location.reload();
6322
+ }));
6373
6323
  }
6374
6324
  /**
6375
- * Get list of vehicle transactions except KMS transactions
6325
+ * clear service cache
6376
6326
  */
6377
- getLogbookTransactions() {
6378
- return this
6379
- .getVehicleTransactions()
6380
- .removeBy('chartAccounts.id', [ChartAccountsListEnum.KLMS_TRAVELLED_FOR_WORK, ChartAccountsListEnum.KLMS_TRAVELLED]);
6327
+ resetCache() {
6328
+ this.fetch().subscribe();
6381
6329
  }
6382
6330
  /**
6383
- * Build chart data with transactions cash position.
6384
- * Cash position = Income - Expenses (include depreciations)
6385
- * Chart data for each month from fin year start till current month
6331
+ * Create basiq (if not exist yet) to provide access to basiq api
6386
6332
  */
6387
- getCashPositionChartData() {
6388
- const chartData = [
6389
- plainToClass(ChartData, { name: 'Income', data: [] }),
6390
- plainToClass(ChartData, { name: 'Expense', data: [] })
6391
- ];
6392
- new FinancialYear().getPastMonths().forEach((month) => {
6393
- chartData[0].data.push({
6394
- label: MONTHS[month],
6395
- value: this.getIncomeTransactions().getByMonth(month).claimAmount
6396
- });
6397
- chartData[1].data.push({
6398
- label: MONTHS[month],
6399
- value: Math.abs(this.getExpenseTransactions().getByMonth(month).claimAmount)
6400
- });
6401
- });
6402
- return chartData;
6333
+ createBasiq() {
6334
+ var _a;
6335
+ // no need to create basiqId if already exist
6336
+ // @TODO Alex (TT-2431): move this check to component or separated method
6337
+ if ((_a = this.cache) === null || _a === void 0 ? void 0 : _a.basiqId) {
6338
+ return of(this.cache.basiqId);
6339
+ }
6340
+ return this.http.post(`${this.environment.apiV2}/basiq/user`, {})
6341
+ .pipe(map((basiqId) => {
6342
+ this.cache = plainToClass(User, Object.assign(this.cache, { basiqId }));
6343
+ this.cacheSubject.next(this.cache);
6344
+ return basiqId;
6345
+ }));
6403
6346
  }
6404
6347
  /**
6405
- * user pays GST only from allocated part (or paid) of income
6348
+ * Update cache when user's service subscription is updated
6406
6349
  */
6407
- calculateAllocatedClaimAmount(allocations) {
6408
- let allocatedClaimAmount = 0;
6409
- this.filterBy('isGST', true).toArray().forEach((transaction) => {
6410
- allocatedClaimAmount += transaction.getAllocatedClaimAmount(allocations);
6411
- });
6412
- return allocatedClaimAmount;
6413
- }
6414
- calculateAllocatedGST(allocations) {
6415
- return this.calculateAllocatedClaimAmount(allocations) * ChartAccounts.GSTRatio;
6416
- }
6417
- getAllocatedAmount(allocations) {
6418
- return allocations.getByTransactionsIds(this.getIds()).sumBy('amount');
6350
+ listenServiceSubscriptionUpdated() {
6351
+ this.eventDispatcherService.on(AppEventTypeEnum.SERVICE_SUBSCRIPTION_UPDATED).subscribe(() => this.resetCache());
6419
6352
  }
6420
6353
  }
6354
+ UserService.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.2.15", ngImport: i0, type: UserService, deps: [{ token: i1.HttpClient }, { token: JwtService }, { token: EventDispatcherService }, { token: SseService }, { token: 'environment' }], target: i0.ɵɵFactoryTarget.Injectable });
6355
+ UserService.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "12.2.15", ngImport: i0, type: UserService, providedIn: 'root' });
6356
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.15", ngImport: i0, type: UserService, decorators: [{
6357
+ type: Injectable,
6358
+ args: [{
6359
+ providedIn: 'root'
6360
+ }]
6361
+ }], ctorParameters: function () { return [{ type: i1.HttpClient }, { type: JwtService }, { type: EventDispatcherService }, { type: SseService }, { type: undefined, decorators: [{
6362
+ type: Inject,
6363
+ args: ['environment']
6364
+ }] }]; } });
6421
6365
 
6422
- class TransactionAllocationCollection extends Collection {
6423
- get amount() {
6424
- return this.sumBy('amount');
6425
- }
6426
- getByTransactionsIds(ids) {
6427
- return new TransactionAllocationCollection(this.items.filter((allocation) => ids.includes(allocation.transaction.id)));
6366
+ /**
6367
+ * Interceptor which check if client's basiq id exist and request it if not
6368
+ */
6369
+ class BasiqClientIdInterceptor {
6370
+ constructor(userService) {
6371
+ this.userService = userService;
6428
6372
  }
6429
- getByBankTransactionsIds(ids) {
6430
- return new TransactionAllocationCollection(this.items.filter((allocation) => ids.includes(allocation.bankTransaction.id)));
6373
+ intercept(request, next) {
6374
+ // Check if 'client id' URL segment contains null instead of id
6375
+ if (!request.url.startsWith(`${BasiqService.basiqApiUrl}/users/null`)) {
6376
+ return next.handle(request);
6377
+ }
6378
+ return this.userService.createBasiq().pipe(mergeMap((basiqClientId) => next.handle(this.addId(request, basiqClientId))));
6431
6379
  }
6432
- /**
6433
- * Group allocations by bank account via bank transactions collection
6434
- */
6435
- groupByBankAccount(bankTransactions) {
6436
- // Group bank transactions by bank account id
6437
- const bankTransactionsByBankAccount = new CollectionDictionary(bankTransactions, 'bankAccount.id');
6438
- // Create empty dictionary of transaction allocations
6439
- const allocationsByBankAccount = new CollectionDictionary(new TransactionAllocationCollection([]));
6440
- // Fill allocations dictionary with bank transactions dictionary keys and allocations related with each bank transaction collection
6441
- bankTransactionsByBankAccount.keys.forEach((key) => {
6442
- allocationsByBankAccount.add(key, this.getByBankTransactionsIds(bankTransactionsByBankAccount.get(key).getIds()));
6380
+ addId(request, basiqClientId) {
6381
+ return request.clone({
6382
+ url: request.url.replace('null', basiqClientId)
6443
6383
  });
6444
- return allocationsByBankAccount;
6445
- }
6446
- /**
6447
- * check if collection includes allocation of passed transaction
6448
- */
6449
- hasTransaction(transaction) {
6450
- return !!this.items.find((allocation) => allocation.transaction.id === transaction.id);
6451
- }
6452
- /**
6453
- * Check if bank transaction is related with current allocations
6454
- */
6455
- hasBankTransaction(bankTransaction) {
6456
- return !!this.items.find((allocation) => allocation.bankTransaction.id === bankTransaction.id);
6457
6384
  }
6458
6385
  }
6386
+ BasiqClientIdInterceptor.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.2.15", ngImport: i0, type: BasiqClientIdInterceptor, deps: [{ token: UserService }], target: i0.ɵɵFactoryTarget.Injectable });
6387
+ BasiqClientIdInterceptor.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "12.2.15", ngImport: i0, type: BasiqClientIdInterceptor });
6388
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.15", ngImport: i0, type: BasiqClientIdInterceptor, decorators: [{
6389
+ type: Injectable
6390
+ }], ctorParameters: function () { return [{ type: UserService }]; } });
6391
+
6392
+ class InterceptorsModule {
6393
+ }
6394
+ InterceptorsModule.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.2.15", ngImport: i0, type: InterceptorsModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule });
6395
+ InterceptorsModule.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "12.0.0", version: "12.2.15", ngImport: i0, type: InterceptorsModule });
6396
+ InterceptorsModule.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "12.2.15", ngImport: i0, type: InterceptorsModule, providers: [
6397
+ {
6398
+ provide: HTTP_INTERCEPTORS,
6399
+ useClass: CorelogicInterceptor,
6400
+ multi: true
6401
+ },
6402
+ // @TODO move to user module
6403
+ {
6404
+ provide: HTTP_INTERCEPTORS,
6405
+ useClass: FinancialYearInterceptor,
6406
+ multi: true
6407
+ },
6408
+ {
6409
+ provide: HTTP_INTERCEPTORS,
6410
+ useClass: JwtInterceptor,
6411
+ multi: true
6412
+ },
6413
+ {
6414
+ provide: HTTP_INTERCEPTORS,
6415
+ useClass: UserSwitcherInterceptor,
6416
+ multi: true
6417
+ },
6418
+ {
6419
+ provide: HTTP_INTERCEPTORS,
6420
+ useClass: PreloaderInterceptor,
6421
+ multi: true
6422
+ },
6423
+ {
6424
+ provide: HTTP_INTERCEPTORS,
6425
+ useClass: BasiqTokenInterceptor,
6426
+ multi: true
6427
+ },
6428
+ {
6429
+ provide: HTTP_INTERCEPTORS,
6430
+ useClass: BasiqClientIdInterceptor,
6431
+ multi: true
6432
+ }
6433
+ ] });
6434
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.15", ngImport: i0, type: InterceptorsModule, decorators: [{
6435
+ type: NgModule,
6436
+ args: [{
6437
+ providers: [
6438
+ {
6439
+ provide: HTTP_INTERCEPTORS,
6440
+ useClass: CorelogicInterceptor,
6441
+ multi: true
6442
+ },
6443
+ // @TODO move to user module
6444
+ {
6445
+ provide: HTTP_INTERCEPTORS,
6446
+ useClass: FinancialYearInterceptor,
6447
+ multi: true
6448
+ },
6449
+ {
6450
+ provide: HTTP_INTERCEPTORS,
6451
+ useClass: JwtInterceptor,
6452
+ multi: true
6453
+ },
6454
+ {
6455
+ provide: HTTP_INTERCEPTORS,
6456
+ useClass: UserSwitcherInterceptor,
6457
+ multi: true
6458
+ },
6459
+ {
6460
+ provide: HTTP_INTERCEPTORS,
6461
+ useClass: PreloaderInterceptor,
6462
+ multi: true
6463
+ },
6464
+ {
6465
+ provide: HTTP_INTERCEPTORS,
6466
+ useClass: BasiqTokenInterceptor,
6467
+ multi: true
6468
+ },
6469
+ {
6470
+ provide: HTTP_INTERCEPTORS,
6471
+ useClass: BasiqClientIdInterceptor,
6472
+ multi: true
6473
+ }
6474
+ ]
6475
+ }]
6476
+ }] });
6459
6477
 
6460
- /**
6461
- * used to combine transactions/depreciations
6462
- */
6463
- class TransactionBaseCollection extends Collection {
6464
- getClaimAmountByBusinessId(businessId) {
6465
- return +this.filterBy('business.id', businessId).items.map((transaction) => transaction instanceof Depreciation ? -transaction.claimAmount : transaction['claimAmount']).reduce((sum, claimAmount) => sum + claimAmount, 0).toFixed(2);
6466
- }
6467
- getSoleTransactions() {
6468
- return this.filter((transaction) => transaction.isSoleTank());
6478
+ class TtCoreModule {
6479
+ static forRoot(environment) {
6480
+ localStorage.setItem('api_uri', environment['api_uri']);
6481
+ return {
6482
+ ngModule: TtCoreModule,
6483
+ providers: [
6484
+ {
6485
+ provide: 'environment',
6486
+ useValue: environment
6487
+ }
6488
+ ]
6489
+ };
6469
6490
  }
6470
6491
  }
6471
-
6472
- // @TODO Alex move here all collections
6492
+ TtCoreModule.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.2.15", ngImport: i0, type: TtCoreModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule });
6493
+ TtCoreModule.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "12.0.0", version: "12.2.15", ngImport: i0, type: TtCoreModule, imports: [CommonModule,
6494
+ InterceptorsModule] });
6495
+ TtCoreModule.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "12.2.15", ngImport: i0, type: TtCoreModule, imports: [[
6496
+ CommonModule,
6497
+ InterceptorsModule
6498
+ ]] });
6499
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.15", ngImport: i0, type: TtCoreModule, decorators: [{
6500
+ type: NgModule,
6501
+ args: [{
6502
+ declarations: [],
6503
+ imports: [
6504
+ CommonModule,
6505
+ InterceptorsModule
6506
+ ]
6507
+ }]
6508
+ }] });
6473
6509
 
6474
6510
  class AccountSetupItemCollection extends Collection {
6475
6511
  constructor(items) {
@@ -9786,7 +9822,8 @@ class SoleBusinessLossReport extends AbstractModel {
9786
9822
  super();
9787
9823
  this.openBalance = loss.openBalance;
9788
9824
  this.netIncome = transactions.sumBy('claimAmount') - depreciations.sumBy('claimAmount');
9789
- this.closeBalance = this.netIncome - this.openBalance;
9825
+ this.closeBalance = new SoleBusinessLossesCollection([loss])
9826
+ .calculateBusinessLossApplied(new TransactionBaseCollection([...transactions, ...depreciations]));
9790
9827
  }
9791
9828
  }
9792
9829
 
@@ -10211,7 +10248,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.15", ngImpo
10211
10248
  /**
10212
10249
  * Service that handling user's bank accounts logic
10213
10250
  */
10214
- class BankAccountService extends RestService {
10251
+ class BankAccountService extends RestService$1 {
10215
10252
  constructor() {
10216
10253
  super(...arguments);
10217
10254
  // api url parameter for bank accounts
@@ -10314,7 +10351,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.15", ngImpo
10314
10351
  /**
10315
10352
  * Service for bank transactions business logic
10316
10353
  */
10317
- class BankTransactionService extends RestService {
10354
+ class BankTransactionService extends RestService$1 {
10318
10355
  constructor() {
10319
10356
  super(...arguments);
10320
10357
  // url part for BankTransaction API
@@ -10395,7 +10432,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.15", ngImpo
10395
10432
  /**
10396
10433
  * Service that handling banks logic
10397
10434
  */
10398
- class BankService extends RestService {
10435
+ class BankService extends RestService$1 {
10399
10436
  constructor() {
10400
10437
  super(...arguments);
10401
10438
  this.modelClass = Bank;
@@ -10421,7 +10458,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.15", ngImpo
10421
10458
  /**
10422
10459
  * Service to work with depreciation chart accounts
10423
10460
  */
10424
- class ChartAccountsDepreciationService extends RestService {
10461
+ class ChartAccountsDepreciationService extends RestService$1 {
10425
10462
  constructor() {
10426
10463
  super(...arguments);
10427
10464
  this.url = 'chart-accounts-depreciations';
@@ -10540,7 +10577,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.15", ngImpo
10540
10577
  /**
10541
10578
  * Service for work with messages
10542
10579
  */
10543
- class MessageService extends RestService {
10580
+ class MessageService extends RestService$1 {
10544
10581
  constructor(http, eventDispatcherService, environment, toastService, sseService) {
10545
10582
  super(http, eventDispatcherService, environment, toastService);
10546
10583
  this.http = http;
@@ -10696,7 +10733,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.15", ngImpo
10696
10733
  /**
10697
10734
  * Service for work with chats
10698
10735
  */
10699
- class ChatService extends RestService {
10736
+ class ChatService extends RestService$1 {
10700
10737
  constructor(http, eventDispatcherService, environment, toastService, sseService) {
10701
10738
  super(http, eventDispatcherService, environment, toastService);
10702
10739
  this.http = http;
@@ -10868,7 +10905,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.15", ngImpo
10868
10905
  args: ['environment']
10869
10906
  }] }, { type: ToastService }]; } });
10870
10907
 
10871
- class DepreciationService extends RestService {
10908
+ class DepreciationService extends RestService$1 {
10872
10909
  constructor(http, eventDispatcherService, environment, toastService, depreciationReceiptService) {
10873
10910
  super(http, eventDispatcherService, environment, toastService);
10874
10911
  this.http = http;
@@ -11075,7 +11112,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.15", ngImpo
11075
11112
  args: ['environment']
11076
11113
  }] }]; } });
11077
11114
 
11078
- class DocumentService extends RestService {
11115
+ class DocumentService extends RestService$1 {
11079
11116
  constructor() {
11080
11117
  super(...arguments);
11081
11118
  this.url = 'documents';
@@ -11094,7 +11131,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.15", ngImpo
11094
11131
  /**
11095
11132
  * Service to handle document-folders and depending documents logic
11096
11133
  */
11097
- class DocumentFolderService extends RestService {
11134
+ class DocumentFolderService extends RestService$1 {
11098
11135
  constructor() {
11099
11136
  super(...arguments);
11100
11137
  this.url = 'folders';
@@ -11286,7 +11323,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.15", ngImpo
11286
11323
  args: ['environment']
11287
11324
  }] }]; } });
11288
11325
 
11289
- class ClientInviteService extends RestService {
11326
+ class ClientInviteService extends RestService$1 {
11290
11327
  constructor() {
11291
11328
  super(...arguments);
11292
11329
  this.url = 'clients/invites';
@@ -11403,7 +11440,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.15", ngImpo
11403
11440
  }]
11404
11441
  }] });
11405
11442
 
11406
- class ClientMovementService extends RestService {
11443
+ class ClientMovementService extends RestService$1 {
11407
11444
  constructor() {
11408
11445
  super(...arguments);
11409
11446
  this.modelClass = ClientMovement;
@@ -11484,7 +11521,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.15", ngImpo
11484
11521
  }]
11485
11522
  }] });
11486
11523
 
11487
- class EmployeeService extends RestService {
11524
+ class EmployeeService extends RestService$1 {
11488
11525
  constructor() {
11489
11526
  super(...arguments);
11490
11527
  this.url = 'employees';
@@ -11515,7 +11552,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.15", ngImpo
11515
11552
  }]
11516
11553
  }] });
11517
11554
 
11518
- class EmployeeInviteService extends RestService {
11555
+ class EmployeeInviteService extends RestService$1 {
11519
11556
  constructor() {
11520
11557
  super(...arguments);
11521
11558
  this.url = 'employees/invites';
@@ -11665,7 +11702,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.15", ngImpo
11665
11702
  /**
11666
11703
  * Service to work with Other Income Forecasts
11667
11704
  */
11668
- class IncomeSourceForecastService extends RestService {
11705
+ class IncomeSourceForecastService extends RestService$1 {
11669
11706
  constructor() {
11670
11707
  super(...arguments);
11671
11708
  this.modelClass = IncomeSourceForecast;
@@ -11737,7 +11774,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.15", ngImpo
11737
11774
  /**
11738
11775
  * Service to work with Salary Forecasts
11739
11776
  */
11740
- class SalaryForecastService extends RestService {
11777
+ class SalaryForecastService extends RestService$1 {
11741
11778
  constructor() {
11742
11779
  super(...arguments);
11743
11780
  this.modelClass = SalaryForecast;
@@ -11806,7 +11843,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.15", ngImpo
11806
11843
  }]
11807
11844
  }] });
11808
11845
 
11809
- class SoleForecastService extends RestService {
11846
+ class SoleForecastService extends RestService$1 {
11810
11847
  constructor() {
11811
11848
  super(...arguments);
11812
11849
  this.modelClass = SoleForecast;
@@ -11887,7 +11924,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.15", ngImpo
11887
11924
  /**
11888
11925
  * Service to work with income sources
11889
11926
  */
11890
- class IncomeSourceService extends RestService {
11927
+ class IncomeSourceService extends RestService$1 {
11891
11928
  constructor() {
11892
11929
  super(...arguments);
11893
11930
  this.url = 'income-sources';
@@ -12053,7 +12090,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.15", ngImpo
12053
12090
  /**
12054
12091
  * Service that handling loans logic
12055
12092
  */
12056
- class LoanService extends RestService {
12093
+ class LoanService extends RestService$1 {
12057
12094
  constructor() {
12058
12095
  super(...arguments);
12059
12096
  this.url = 'bank-accounts/loans';
@@ -12179,7 +12216,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.15", ngImpo
12179
12216
  /**
12180
12217
  * Service for work with Property Categories
12181
12218
  */
12182
- class PropertyCategoryService extends RestService {
12219
+ class PropertyCategoryService extends RestService$1 {
12183
12220
  constructor() {
12184
12221
  super(...arguments);
12185
12222
  this.modelClass = PropertyCategory;
@@ -12195,7 +12232,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.15", ngImpo
12195
12232
  }]
12196
12233
  }] });
12197
12234
 
12198
- class PropertyCategoryMovementService extends RestService {
12235
+ class PropertyCategoryMovementService extends RestService$1 {
12199
12236
  constructor() {
12200
12237
  super(...arguments);
12201
12238
  this.modelClass = PropertyCategoryMovement;
@@ -12238,7 +12275,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.15", ngImpo
12238
12275
  /**
12239
12276
  * Class for work with Property Documents
12240
12277
  */
12241
- class PropertyDocumentService extends RestService {
12278
+ class PropertyDocumentService extends RestService$1 {
12242
12279
  constructor() {
12243
12280
  super(...arguments);
12244
12281
  this.modelClass = PropertyDocument;
@@ -12289,7 +12326,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.15", ngImpo
12289
12326
  }]
12290
12327
  }] });
12291
12328
 
12292
- class TaxExemptionService extends RestService {
12329
+ class TaxExemptionService extends RestService$1 {
12293
12330
  constructor() {
12294
12331
  super(...arguments);
12295
12332
  this.modelClass = TaxExemption;
@@ -12306,7 +12343,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.15", ngImpo
12306
12343
  }]
12307
12344
  }] });
12308
12345
 
12309
- class PropertySaleService extends RestService {
12346
+ class PropertySaleService extends RestService$1 {
12310
12347
  constructor() {
12311
12348
  super(...arguments);
12312
12349
  this.modelClass = PropertySale;
@@ -12340,7 +12377,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.15", ngImpo
12340
12377
  }] });
12341
12378
 
12342
12379
  // @TODO check and improve logic during refactoring
12343
- class PropertyShareService extends RestService {
12380
+ class PropertyShareService extends RestService$1 {
12344
12381
  constructor() {
12345
12382
  super(...arguments);
12346
12383
  // api url parameter for properties shares
@@ -12457,17 +12494,249 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.15", ngImpo
12457
12494
  }]
12458
12495
  }] });
12459
12496
 
12497
+ /**
12498
+ * Abstract base service that implements common services functionality
12499
+ * and describe abstract methods/properties that have to be implemented in child services
12500
+ * Model - entity service is working with
12501
+ * BaseModel - base entity model that extends by Model
12502
+ * CollectionModel - entity collection class
12503
+ */
12504
+ class RestService {
12505
+ constructor(http, eventDispatcherService, environment) {
12506
+ this.http = http;
12507
+ this.eventDispatcherService = eventDispatcherService;
12508
+ this.environment = environment;
12509
+ /**
12510
+ * Subject for service cache
12511
+ */
12512
+ this.cacheSubject = new ReplaySubject(1);
12513
+ /**
12514
+ * List of methods unavailable for current API
12515
+ */
12516
+ this.disabledMethods = [];
12517
+ this.listenEvents();
12518
+ }
12519
+ get apiUrl() {
12520
+ return `${this.environment.apiV2}/${this.entityUrl}`;
12521
+ }
12522
+ get() {
12523
+ this.handleAccessError('get');
12524
+ // Set cache as empty collection to avoid multiple requests before cache filled
12525
+ if (!this.cache) {
12526
+ this.cache = this.createCollectionInstance(this.collectionClass, []);
12527
+ this.resetCache();
12528
+ }
12529
+ return this.cacheSubject.asObservable();
12530
+ }
12531
+ ;
12532
+ getSingle() {
12533
+ this.handleAccessError('get');
12534
+ return this.get().pipe(map((collection) => collection.first));
12535
+ }
12536
+ /**
12537
+ * Create a new Model instance in database
12538
+ */
12539
+ post(model) {
12540
+ this.handleAccessError('post');
12541
+ return this.http.post(this.apiUrl, model)
12542
+ .pipe(map((response) => {
12543
+ const result = this.createModelInstance(this.modelClass, response);
12544
+ this.handleResponse([result], 'post');
12545
+ return result;
12546
+ }));
12547
+ }
12548
+ /**
12549
+ * Create multiple new Model instances in database
12550
+ */
12551
+ postBatch(models) {
12552
+ this.handleAccessError('postBatch');
12553
+ return this.http.post(this.apiUrl, models)
12554
+ .pipe(map((response) => {
12555
+ const result = response.map((item) => this.createModelInstance(this.modelClass, item));
12556
+ this.handleResponse(result, 'post');
12557
+ return result;
12558
+ }));
12559
+ }
12560
+ /**
12561
+ * Change an existing Model instance in database
12562
+ */
12563
+ put(model) {
12564
+ this.handleAccessError('put');
12565
+ return this.http.put(`${this.apiUrl}/${model.id}`, model)
12566
+ .pipe(map((response) => {
12567
+ const result = this.createModelInstance(this.modelClass, response);
12568
+ this.handleResponse([result], 'put');
12569
+ return result;
12570
+ }));
12571
+ }
12572
+ /**
12573
+ * Change multiple existing Model instances in database
12574
+ */
12575
+ putBatch(models) {
12576
+ this.handleAccessError('putBatch');
12577
+ return this.http.put(this.apiUrl, models)
12578
+ .pipe(map((response) => {
12579
+ const result = response.map((item) => this.createModelInstance(this.modelClass, item));
12580
+ debugger;
12581
+ this.handleResponse(result, 'put');
12582
+ return result;
12583
+ }));
12584
+ }
12585
+ /**
12586
+ * Remove a Model instance from database
12587
+ */
12588
+ delete(model) {
12589
+ this.handleAccessError('delete');
12590
+ return this.http.delete(`${this.apiUrl}/${model.id}`)
12591
+ .pipe(map(() => {
12592
+ this.handleResponse([model], 'delete');
12593
+ }));
12594
+ }
12595
+ /**
12596
+ * Remove multiple Model instances from database
12597
+ */
12598
+ deleteBatch(models) {
12599
+ this.handleAccessError('deleteBatch');
12600
+ return this.http.post(`${this.apiUrl}/delete`, models)
12601
+ .pipe(map(() => {
12602
+ this.handleResponse(models, 'delete');
12603
+ }));
12604
+ }
12605
+ /**
12606
+ * Refresh cache with actual backend data
12607
+ */
12608
+ resetCache() {
12609
+ this.fetch()
12610
+ .pipe(first$1())
12611
+ .subscribe();
12612
+ }
12613
+ /**
12614
+ * Get data from backend and fill the cache
12615
+ */
12616
+ fetch() {
12617
+ return this.http.get(this.apiUrl)
12618
+ .pipe(map((response) => this.isApiPlatform ? response['hydra:member'] : toArray(response)), map((response) => {
12619
+ const items = response.map((item) => this.createModelInstance(this.modelClass, item));
12620
+ this.cache = this.createCollectionInstance(this.collectionClass, items);
12621
+ this.cacheSubject.next(this.cache);
12622
+ return this.cache;
12623
+ }));
12624
+ }
12625
+ ;
12626
+ /**
12627
+ * Handle response data - update cache and dispatch event if it is needed
12628
+ */
12629
+ handleResponse(response, method) {
12630
+ this.updateCache(response, method);
12631
+ // dispatch event for interested services
12632
+ if (response[0] instanceof ObservableModel) {
12633
+ this.dispatchEvent(method, response);
12634
+ }
12635
+ }
12636
+ /**
12637
+ * Update cache with passed items. Add/Update detects automatically, Delete via optional flag
12638
+ */
12639
+ updateCache(items, method) {
12640
+ switch (method) {
12641
+ case 'post':
12642
+ this.cache = this.cache.push(...items);
12643
+ break;
12644
+ case 'put':
12645
+ items.forEach((item) => {
12646
+ this.cache = this.cache.replaceBy('id', item.id, item);
12647
+ });
12648
+ break;
12649
+ case 'delete':
12650
+ this.cache = this.cache.removeBy('id', items.map((item) => item.id));
12651
+ }
12652
+ this.cacheSubject.next(this.cache);
12653
+ }
12654
+ /**
12655
+ * Generate and dispatch rest event
12656
+ */
12657
+ dispatchEvent(method, items) {
12658
+ const eventName = this.modelClass.getEventName(method);
12659
+ this.eventDispatcherService.dispatch2(new AppEvent2(eventName, items));
12660
+ }
12661
+ /**
12662
+ * Create new instance of class
12663
+ * @param model The class whose instance to be created
12664
+ * @param plain Single object or array from which will be created model instance(s)
12665
+ */
12666
+ createModelInstance(model, plain) {
12667
+ // excludePrefixes - class-transformer option is using to ignore hydra fields
12668
+ return plainToClass(model, plain, { excludePrefixes: ['@'] });
12669
+ }
12670
+ createCollectionInstance(collectionClass, items) {
12671
+ return new collectionClass(items);
12672
+ }
12673
+ /**
12674
+ * Check if method is not disabled. Throw exception otherwise.
12675
+ * Some entities does not have endpoints for all methods.
12676
+ */
12677
+ handleAccessError(method) {
12678
+ if (!this.disabledMethods.includes(method)) {
12679
+ return;
12680
+ }
12681
+ throw new Error(`Method ${method}() is not allowed for ${this.constructor.name}`);
12682
+ }
12683
+ /**
12684
+ * Subscribe to http events and run callback
12685
+ * @param type The class whose changes should be listened for
12686
+ * @param methods The list of http methods should be listened for
12687
+ * @param callback The function to be called when event triggered
12688
+ */
12689
+ listenCSE(modelClass, methods, callback) {
12690
+ methods.forEach((method) => {
12691
+ this.eventDispatcherService.on2(modelClass.getEventName(method)).subscribe((data) => {
12692
+ callback(data);
12693
+ });
12694
+ });
12695
+ }
12696
+ /**
12697
+ * Method that call all listeners. Empty by default. Should be redefined by child services if required
12698
+ */
12699
+ listenEvents() { }
12700
+ }
12701
+ RestService.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.2.15", ngImport: i0, type: RestService, deps: [{ token: i1.HttpClient }, { token: EventDispatcherService }, { token: 'environment' }], target: i0.ɵɵFactoryTarget.Injectable });
12702
+ RestService.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "12.2.15", ngImport: i0, type: RestService, providedIn: 'root' });
12703
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.15", ngImport: i0, type: RestService, decorators: [{
12704
+ type: Injectable,
12705
+ args: [{
12706
+ providedIn: 'root'
12707
+ }]
12708
+ }], ctorParameters: function () { return [{ type: i1.HttpClient }, { type: EventDispatcherService }, { type: undefined, decorators: [{
12709
+ type: Inject,
12710
+ args: ['environment']
12711
+ }] }]; } });
12712
+
12460
12713
  /**
12461
12714
  * @Todo Alex remove functionality related to PropertyShare
12715
+ * @TODO Alex (TT-1777): replace all event listeners with the new this.listen()
12462
12716
  * Service for work with Property
12463
12717
  */
12464
12718
  class PropertyService extends RestService {
12465
12719
  constructor() {
12466
12720
  super(...arguments);
12467
12721
  this.modelClass = Property;
12468
- this.url = 'properties';
12722
+ this.collectionClass = PropertyCollection;
12723
+ this.entityUrl = 'properties';
12724
+ }
12725
+ post(property) {
12726
+ return super.post(property)
12727
+ // @TODO Alex (TT-1777): handle this events and refactor
12728
+ .pipe(map((updatedProperty) => {
12729
+ if (property.documentFile) {
12730
+ this.eventDispatcherService.dispatch(new AppEvent(AppEventTypeEnum.PROPERTY_UPDATED_WITH_DOCUMENT, property));
12731
+ }
12732
+ else {
12733
+ this.eventDispatcherService.dispatch(new AppEvent(AppEventTypeEnum.PROPERTY_UPDATED, property));
12734
+ }
12735
+ return updatedProperty;
12736
+ }));
12469
12737
  }
12470
12738
  listenEvents() {
12739
+ this.cache;
12471
12740
  this.listenShareInviteAccepted();
12472
12741
  // @TODO Alex: consider to refactor property movements logic similar to client-movements
12473
12742
  this.listenMovementsChanged();
@@ -12496,39 +12765,21 @@ class PropertyService extends RestService {
12496
12765
  this.eventDispatcherService.on(AppEventTypeEnum.PROPERTY_SALE_ADDED).subscribe((propertySale) => {
12497
12766
  const propertyToReplace = this.cache.find((property) => property.myShare.id === propertySale.share.id);
12498
12767
  propertyToReplace.myShare.sale = plainToClass(PropertySale, { id: propertySale.id });
12499
- replace(this.cache, propertyToReplace);
12500
- this.updateCache();
12768
+ this.updateCache([propertyToReplace], 'put');
12501
12769
  });
12502
12770
  }
12503
12771
  listenSalesDeleted() {
12504
12772
  this.eventDispatcherService.on(AppEventTypeEnum.PROPERTY_SALE_DELETED).subscribe((propertySale) => {
12505
12773
  const propertyToReplace = this.cache.find((property) => property.myShare.id === propertySale.share.id);
12506
12774
  propertyToReplace.myShare.sale = null;
12507
- replace(this.cache, propertyToReplace);
12508
- this.updateCache();
12775
+ this.updateCache([propertyToReplace], 'put');
12509
12776
  });
12510
12777
  }
12511
- update(property) {
12512
- return super.update(property).pipe(map((updatedProperty) => {
12513
- if (property.documentFile) {
12514
- this.eventDispatcherService.dispatch(new AppEvent(AppEventTypeEnum.PROPERTY_UPDATED_WITH_DOCUMENT, property));
12515
- }
12516
- else {
12517
- this.eventDispatcherService.dispatch(new AppEvent(AppEventTypeEnum.PROPERTY_UPDATED, property));
12518
- }
12519
- return updatedProperty;
12520
- }));
12521
- }
12522
12778
  updateDepreciationCalculation(property) {
12523
12779
  const propertyToUpdate = plainToClass(Property, { id: property.id, depreciationCalculation: property.depreciationCalculation });
12524
- return this.update(propertyToUpdate).pipe(map((updatedProperty) => {
12780
+ return this.post(propertyToUpdate)
12781
+ .pipe(map((updatedProperty) => {
12525
12782
  this.eventDispatcherService.dispatch(new AppEvent(AppEventTypeEnum.PROPERTY_DEPRECIATION_CALCULATION_UPDATED, updatedProperty));
12526
- return updatedProperty;
12527
- }));
12528
- }
12529
- getByCategoryId(id) {
12530
- return this.get().pipe(map((properties) => {
12531
- return properties.filter((property) => property.category.id === id);
12532
12783
  }));
12533
12784
  }
12534
12785
  /**
@@ -12539,8 +12790,7 @@ class PropertyService extends RestService {
12539
12790
  .pipe(map((propertySubscriptionBase) => {
12540
12791
  const newPropertySubscription = plainToClass(PropertySubscription, propertySubscriptionBase);
12541
12792
  const activatedProperty = plainToClass(Property, Object.assign({}, property, { subscriptions: [newPropertySubscription] }));
12542
- replace(this.cache, activatedProperty);
12543
- this.updateCache();
12793
+ this.updateCache([activatedProperty], 'put');
12544
12794
  }));
12545
12795
  }
12546
12796
  /**
@@ -12550,8 +12800,7 @@ class PropertyService extends RestService {
12550
12800
  return this.http.delete(`${this.environment.apiV2}/property-subscriptions/${property.getCurrentSubscription().id}`)
12551
12801
  .pipe(map(() => {
12552
12802
  const deactivatedProperty = plainToClass(Property, Object.assign({}, property, { subscriptions: [] }));
12553
- replace(this.cache, deactivatedProperty);
12554
- this.updateCache();
12803
+ this.updateCache([deactivatedProperty], 'put');
12555
12804
  }));
12556
12805
  }
12557
12806
  /**
@@ -12562,23 +12811,9 @@ class PropertyService extends RestService {
12562
12811
  updatePhoto(property, photoFormData) {
12563
12812
  return this.http.post(`${this.environment.apiV2}/properties/${property.id}/photo?_method=PUT`, photoFormData)
12564
12813
  .pipe(map((photoLink) => {
12565
- property.photo = photoLink;
12566
- // update properties cache
12567
- replace(this.cache, property);
12568
- this.updateCache();
12569
- }));
12570
- }
12571
- getByShareId(id) {
12572
- return this.get().pipe(map((properties) => {
12573
- return properties.filter((property) => property.user.id === id);
12814
+ this.updateCache([plainToClass(Property, merge(property, { photo: photoLink }))], 'put');
12574
12815
  }));
12575
12816
  }
12576
- /**
12577
- * Get list of active user's properties
12578
- */
12579
- getActive() {
12580
- return this.get().pipe(map((properties) => properties.filter((property) => property.isActive)));
12581
- }
12582
12817
  }
12583
12818
  PropertyService.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.2.15", ngImport: i0, type: PropertyService, deps: null, target: i0.ɵɵFactoryTarget.Injectable });
12584
12819
  PropertyService.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "12.2.15", ngImport: i0, type: PropertyService, providedIn: 'root' });
@@ -12592,7 +12827,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.15", ngImpo
12592
12827
  /**
12593
12828
  * Service to handle service notifications logic
12594
12829
  */
12595
- class ServiceNotificationService extends RestService {
12830
+ class ServiceNotificationService extends RestService$1 {
12596
12831
  constructor(http, eventDispatcherService, environment, toastService, sseService) {
12597
12832
  super(http, eventDispatcherService, environment, toastService);
12598
12833
  this.http = http;
@@ -12645,7 +12880,7 @@ var MessagesEnum$1;
12645
12880
  MessagesEnum["LOGO_ERROR_SIZE"] = "The file is too big. Maximum size is 2mb";
12646
12881
  })(MessagesEnum$1 || (MessagesEnum$1 = {}));
12647
12882
 
12648
- class SoleBusinessService extends RestService {
12883
+ class SoleBusinessService extends RestService$1 {
12649
12884
  constructor() {
12650
12885
  super(...arguments);
12651
12886
  this.modelClass = SoleBusiness;
@@ -12686,7 +12921,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.15", ngImpo
12686
12921
  }]
12687
12922
  }] });
12688
12923
 
12689
- class SoleBusinessActivityService extends RestService {
12924
+ class SoleBusinessActivityService extends RestService$1 {
12690
12925
  constructor() {
12691
12926
  super(...arguments);
12692
12927
  this.modelClass = SoleBusinessActivity;
@@ -12703,7 +12938,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.15", ngImpo
12703
12938
  }]
12704
12939
  }] });
12705
12940
 
12706
- class SoleBusinessLossService extends RestService {
12941
+ class SoleBusinessLossService extends RestService$1 {
12707
12942
  constructor() {
12708
12943
  super(...arguments);
12709
12944
  this.modelClass = SoleBusinessLoss;
@@ -12734,7 +12969,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.15", ngImpo
12734
12969
  /**
12735
12970
  * @TODO vik replace with json when the final list is confirmed
12736
12971
  */
12737
- class SoleBusinessLossOffsetRuleService extends RestService {
12972
+ class SoleBusinessLossOffsetRuleService extends RestService$1 {
12738
12973
  constructor() {
12739
12974
  super(...arguments);
12740
12975
  this.modelClass = SoleBusinessLossOffsetRule;
@@ -12751,7 +12986,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.15", ngImpo
12751
12986
  }]
12752
12987
  }] });
12753
12988
 
12754
- class SoleContactService extends RestService {
12989
+ class SoleContactService extends RestService$1 {
12755
12990
  constructor() {
12756
12991
  super(...arguments);
12757
12992
  this.modelClass = SoleContact;
@@ -12884,7 +13119,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.15", ngImpo
12884
13119
  args: ['environment']
12885
13120
  }] }, { type: EventDispatcherService }]; } });
12886
13121
 
12887
- class SoleInvoiceService extends RestService {
13122
+ class SoleInvoiceService extends RestService$1 {
12888
13123
  constructor() {
12889
13124
  super(...arguments);
12890
13125
  this.modelClass = SoleInvoice;
@@ -12957,7 +13192,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.15", ngImpo
12957
13192
  }]
12958
13193
  }] });
12959
13194
 
12960
- class SoleInvoiceTemplateService extends RestService {
13195
+ class SoleInvoiceTemplateService extends RestService$1 {
12961
13196
  constructor() {
12962
13197
  super(...arguments);
12963
13198
  this.modelClass = SoleInvoiceTemplate;
@@ -12974,7 +13209,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.15", ngImpo
12974
13209
  }]
12975
13210
  }] });
12976
13211
 
12977
- class BasReportService extends RestService {
13212
+ class BasReportService extends RestService$1 {
12978
13213
  constructor() {
12979
13214
  super(...arguments);
12980
13215
  this.modelClass = BasReport;
@@ -12994,7 +13229,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.15", ngImpo
12994
13229
  /**
12995
13230
  * Service that handling banks logic
12996
13231
  */
12997
- class ServicePriceService extends RestService {
13232
+ class ServicePriceService extends RestService$1 {
12998
13233
  constructor() {
12999
13234
  super(...arguments);
13000
13235
  this.modelClass = ServicePrice;
@@ -13124,7 +13359,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.15", ngImpo
13124
13359
  /**
13125
13360
  * Service to work with tax review history
13126
13361
  */
13127
- class TaxReviewHistoryService extends RestService {
13362
+ class TaxReviewHistoryService extends RestService$1 {
13128
13363
  constructor() {
13129
13364
  super(...arguments);
13130
13365
  this.url = 'tax-reviews/history';
@@ -13158,7 +13393,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.15", ngImpo
13158
13393
  /**
13159
13394
  * Service to work with tax review
13160
13395
  */
13161
- class TaxReviewService extends RestService {
13396
+ class TaxReviewService extends RestService$1 {
13162
13397
  constructor() {
13163
13398
  super(...arguments);
13164
13399
  this.url = 'tax-reviews';
@@ -13313,7 +13548,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.15", ngImpo
13313
13548
  * Service for transaction allocations business logic
13314
13549
  * @TODO alex refactor
13315
13550
  */
13316
- class TransactionAllocationService extends RestService {
13551
+ class TransactionAllocationService extends RestService$1 {
13317
13552
  constructor() {
13318
13553
  super(...arguments);
13319
13554
  // API URL param for transaction allocations
@@ -13450,7 +13685,7 @@ function enumToList(data) {
13450
13685
  /**
13451
13686
  * Service for transactions business logic
13452
13687
  */
13453
- class TransactionService extends RestService {
13688
+ class TransactionService extends RestService$1 {
13454
13689
  constructor(http, eventDispatcherService, environment, toastService, transactionReceiptService) {
13455
13690
  super(http, eventDispatcherService, environment, toastService);
13456
13691
  this.http = http;
@@ -13828,7 +14063,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.15", ngImpo
13828
14063
  /**
13829
14064
  * Service that allows to work with WorkTank operations
13830
14065
  */
13831
- class VehicleService extends RestService {
14066
+ class VehicleService extends RestService$1 {
13832
14067
  constructor() {
13833
14068
  super(...arguments);
13834
14069
  this.url = 'vehicles';
@@ -13844,7 +14079,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.15", ngImpo
13844
14079
  }]
13845
14080
  }] });
13846
14081
 
13847
- class VehicleClaimService extends RestService {
14082
+ class VehicleClaimService extends RestService$1 {
13848
14083
  constructor() {
13849
14084
  super(...arguments);
13850
14085
  this.modelClass = VehicleClaim;
@@ -14003,7 +14238,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.15", ngImpo
14003
14238
  /**
14004
14239
  * Vehicle logbook service. Allows user to add, update or delete vehicle trips
14005
14240
  */
14006
- class VehicleLogbookService extends RestService {
14241
+ class VehicleLogbookService extends RestService$1 {
14007
14242
  constructor() {
14008
14243
  super(...arguments);
14009
14244
  this.url = 'vehicles/logbooks';
@@ -14057,7 +14292,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.15", ngImpo
14057
14292
  args: ['environment']
14058
14293
  }] }]; } });
14059
14294
 
14060
- class UserEventSettingService extends RestService {
14295
+ class UserEventSettingService extends RestService$1 {
14061
14296
  constructor() {
14062
14297
  super(...arguments);
14063
14298
  this.modelClass = UserEventSetting;
@@ -14100,7 +14335,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.15", ngImpo
14100
14335
  }]
14101
14336
  }] });
14102
14337
 
14103
- class UserEventTypeService extends RestService {
14338
+ class UserEventTypeService extends RestService$1 {
14104
14339
  constructor() {
14105
14340
  super(...arguments);
14106
14341
  this.modelClass = UserEventType;
@@ -14120,7 +14355,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.15", ngImpo
14120
14355
  /**
14121
14356
  * Service to work with invitations for unregistered users
14122
14357
  */
14123
- class UsersInviteService extends RestService {
14358
+ class UsersInviteService extends RestService$1 {
14124
14359
  constructor() {
14125
14360
  super(...arguments);
14126
14361
  this.modelClass = RegistrationInvite;
@@ -14280,7 +14515,8 @@ class AccountSetupService {
14280
14515
  }
14281
14516
  // Rental income item is completed when user added at least one property
14282
14517
  if (incomeTypes.property) {
14283
- batch.push(this.create(AccountSetupItemsEnum.PROPERTY, this.propertyService.get()));
14518
+ // @TODO Alex (TT-1777): remove pipe when all services refactored
14519
+ batch.push(this.create(AccountSetupItemsEnum.PROPERTY, this.propertyService.get().pipe(map(properties => properties.toArray()))));
14284
14520
  }
14285
14521
  // Sole business item is completed when user added at least one business
14286
14522
  if (incomeTypes.sole) {
@@ -15030,7 +15266,7 @@ class PropertyTransactionReportService {
15030
15266
  this.getDepreciations(),
15031
15267
  this.chartAccountsService.getChartAccounts()
15032
15268
  ]).pipe(map(([properties, transactions, depreciations, chartAccounts]) => {
15033
- return new CollectionDictionary(this.create(transactions, depreciations, new PropertyCollection(properties), new Collection(chartAccounts)), 'propertyId');
15269
+ return new CollectionDictionary(this.create(transactions, depreciations, properties, new Collection(chartAccounts)), 'propertyId');
15034
15270
  }));
15035
15271
  }
15036
15272
  create(transactions, depreciations, properties, chartAccounts) {
@@ -17427,5 +17663,5 @@ VehicleLogbookForm.maxDescriptionLength = 60;
17427
17663
  * Generated bundle index. Do not edit.
17428
17664
  */
17429
17665
 
17430
- export { AbstractForm, AbstractModel, AccountSetupItem, AccountSetupItemCollection, AccountSetupService, Address, AddressForm, AddressService, AddressTypeEnum, AlphabetColorsEnum, AnnualFrequencyEnum, AppEvent, AppEventTypeEnum, AssetEntityTypeEnum, AssetTypeEnum, AssetsService, AuthService, BANK_ACCOUNT_TYPES, Badge, BadgeColorEnum, Bank, BankAccount, BankAccountAddManualForm, BankAccountAllocationForm, BankAccountCalculationService, BankAccountChartData, BankAccountCollection, BankAccountImportForm, BankAccountPropertiesForm, BankAccountProperty, BankAccountService, BankAccountStatusEnum, BankAccountTypeEnum, BankAccountsImportForm, BankConnection, BankConnectionService, BankConnectionStatusEnum, BankExternalStats, BankLoginData, BankLoginForm, BankService, BankTransaction, BankTransactionCalculationService, BankTransactionChartData, BankTransactionCollection, BankTransactionService, BankTransactionSummaryFieldsEnum, BankTransactionTypeEnum, BasReport, BasReportForm, BasReportService, BasiqConfig, BasiqJob, BasiqJobResponse, BasiqJobStep, BasiqService, BasiqToken, BasiqTokenService, BorrowingExpense, BorrowingExpenseLoan, BorrowingExpenseService, BusinessTypeEnum, CAPITAL_COSTS_ITEMS, CHART_ACCOUNTS_CATEGORIES, CalculationFormItem, CalculationFormTypeEnum, CgtExemptionAndRolloverCodeEnum, ChartAccounts, ChartAccountsCategoryECollection, ChartAccountsCategoryEnum, ChartAccountsCollection, ChartAccountsDepreciation, ChartAccountsDepreciationService, ChartAccountsEtpEnum, ChartAccountsHeading, ChartAccountsHeadingListEnum, ChartAccountsHeadingTaxDeductibleEnum, ChartAccountsHeadingTaxableEnum, ChartAccountsHeadingVehicleListEnum, ChartAccountsListEnum, ChartAccountsMetadata, ChartAccountsMetadataListEnum, ChartAccountsMetadataTypeEnum, ChartAccountsService, ChartAccountsTaxLabelsEnum, ChartAccountsTypeEnum, ChartAccountsValue, ChartData, ChartSerie, Chat, ChatCollection, ChatService, ChatStatusEnum, ChatViewTypeEnum, ClientCollection, ClientDetails, ClientDetailsMedicareExemptionEnum, ClientDetailsWorkDepreciationCalculationEnum, ClientDetailsWorkingHolidayMakerEnum, ClientIncomeTypes, ClientIncomeTypesForm, ClientIncomeTypesService, ClientInvite, ClientInviteCollection, ClientInviteService, ClientInviteStatusEnum, ClientInviteTypeEnum, ClientMovement, ClientMovementCollection, ClientMovementService, ClientPortfolioChartData, ClientPortfolioReport, ClientPortfolioReportCollection, ClientPortfolioReportService, Collection, CollectionDictionary, CorelogicService, CorelogicSuggestion, Country, DEDUCTION_CATEGORIES, DEPRECIATION_GROUPS, DOCUMENT_FILE_TYPES, DeductionClothingTypeEnum, DeductionSelfEducationTypeEnum, Depreciation, DepreciationCalculationEnum, DepreciationCalculationPercentEnum, DepreciationCapitalProject, DepreciationCapitalProjectService, DepreciationCollection, DepreciationForecast, DepreciationForecastCollection, DepreciationGroup, DepreciationGroupEnum, DepreciationGroupItem, DepreciationLvpAssetTypeEnum, DepreciationLvpReportItem, DepreciationLvpReportItemCollection, DepreciationReceipt, DepreciationReceiptService, DepreciationReportItem, DepreciationReportItemCollection, DepreciationService, DepreciationTypeEnum, DepreciationWriteOffAmountEnum, Dictionary, Document, DocumentApiUrlPrefixEnum, DocumentFolder, DocumentFolderService, DocumentService, DocumentTypeEnum, ENDPOINTS, EmployeeCollection, EmployeeDetails, EmployeeInvite, EmployeeInviteService, EmployeeService, Endpoint, EquityPositionChartService, EventDispatcherService, ExportDataTable, ExportFormatEnum, ExportFormatterService, ExportableCollection, FacebookService, FinancialYear, Firm, FirmService, FirmTypeEnum, HeaderTitleService, IconsFileEnum, IncomeAmountTypeEnum, IncomePosition, IncomeSource, IncomeSourceChartData, IncomeSourceCollection, IncomeSourceForecast, IncomeSourceForecastService, IncomeSourceForecastTrustTypeEnum, IncomeSourceService, IncomeSourceType, IncomeSourceTypeEnum, IncomeSourceTypeListOtherEnum, IncomeSourceTypeListSoleEnum, IncomeSourceTypeListWorkEnum, InterceptorsModule, IntercomService, InviteStatusEnum, JwtService, Loan, LoanBankTypeEnum, LoanCollection, LoanForm, LoanFrequencyEnum, LoanInterestTypeEnum, LoanMaxNumberOfPaymentsEnum, LoanPayment, LoanPaymentCollection, LoanPayout, LoanPayoutTypeEnum, LoanRepaymentFrequencyEnum, LoanRepaymentTypeEnum, LoanService, LoanTypeEnum, LoanVehicleTypeEnum, LogbookBestPeriodService, LogbookPeriod, LoginForm, LossTypeEnum, MODULE_URL_LIST, MONTHS, Message, MessageCollection, MessageDocument, MessageDocumentCollection, MessageDocumentService, MessageService, MonthNameShortEnum, MonthNumberEnum, MyAccountHistory, MyAccountHistoryInitiatedByEnum, MyAccountHistoryStatusEnum, MyAccountHistoryTypeEnum, MyTaxBusinessDetails, MyTaxBusinessDetailsForm, MyTaxBusinessIncome, MyTaxBusinessIncomeForm, MyTaxBusinessIncomeOrLossesForm, MyTaxBusinessLosses, MyTaxBusinessLossesForm, MyTaxCgt, MyTaxCgtForm, MyTaxDeductions, MyTaxDeductionsForm, MyTaxDividends, MyTaxDividendsForm, MyTaxEmployeeShareSchemes, MyTaxEmployeeShareSchemesForm, MyTaxEstimate, MyTaxIncomeStatements, MyTaxIncomeStatementsForm, MyTaxIncomeTests, MyTaxIncomeTestsForm, MyTaxInterest, MyTaxInterestForm, MyTaxLosses, MyTaxLossesForm, MyTaxMedicareForm, MyTaxOffsets, MyTaxOffsetsForm, MyTaxOtherIncome, MyTaxOtherIncomeForm, MyTaxPartnershipsAndTrusts, MyTaxPartnershipsAndTrustsForm, MyTaxRent, MyTaxRentForm, Notification, Occupation, OccupationService, PASSWORD_REGEXPS, PasswordForm, PdfFromDataTableService, PdfFromDomElementService, PdfFromHtmlTableService, PdfFromTableService, PdfOrientationEnum, PdfSettings, Phone, PhoneForm, PhoneTypeEnum, PreloaderService, Property, PropertyCalculationService, PropertyCategory, PropertyCategoryListEnum, PropertyCategoryMovement, PropertyCategoryMovementCollection, PropertyCategoryMovementService, PropertyCategoryService, PropertyCollection, PropertyDepreciationCalculationEnum, PropertyDocument, PropertyDocumentService, PropertyEquityChartData, PropertyEquityChartItem, PropertyForecast, PropertyReportItem, PropertyReportItemCollection, PropertyReportItemDepreciation, PropertyReportItemDepreciationCollection, PropertyReportItemTransaction, PropertyReportItemTransactionCollection, PropertySale, PropertySaleCollection, PropertySaleCostBase, PropertySaleCostBaseForm, PropertySaleCostSaleForm, PropertySaleExemptionsForm, PropertySaleService, PropertySaleTaxExemptionMetadata, PropertySaleTaxExemptionMetadataCollection, PropertyService, PropertyShare, PropertyShareAccessEnum, PropertyShareService, PropertyShareStatusEnum, PropertySubscription, PropertyTransactionReportService, PropertyValuation, ReceiptService, RegisterClientForm, RegisterFirmForm, RegistrationInvite, RegistrationInviteStatusEnum, ReportItem, ReportItemCollection, ReportItemDetails, ResetPasswordForm, RestService, RewardfulService, SalaryForecast, SalaryForecastFrequencyEnum, SalaryForecastService, ServiceNotificationService, ServiceNotificationStatusEnum, ServiceNotificationTypeEnum, ServicePayment, ServicePaymentStatusEnum, ServicePrice, ServicePriceRecurringIntervalEnum, ServicePriceService, ServicePriceTypeEnum, ServiceProduct, ServiceProductIdEnum, ServiceProductStatusEnum, ServiceSubscription, ServiceSubscriptionCollection, ServiceSubscriptionItem, ServiceSubscriptionStatusEnum, ShareFilterOptionsEnum, SoleBusiness, SoleBusinessActivity, SoleBusinessActivityService, SoleBusinessAllocation, SoleBusinessAllocationsForm, SoleBusinessForm, SoleBusinessLoss, SoleBusinessLossForm, SoleBusinessLossOffsetRule, SoleBusinessLossOffsetRuleService, SoleBusinessLossReport, SoleBusinessLossService, SoleBusinessLossesCollection, SoleBusinessService, SoleContact, SoleContactForm, SoleContactService, SoleDepreciationMethod, SoleDepreciationMethodEnum, SoleDepreciationMethodForm, SoleDepreciationMethodService, SoleDetails, SoleDetailsForm, SoleDetailsService, SoleForecast, SoleForecastService, SoleInvoice, SoleInvoiceCollection, SoleInvoiceForm, SoleInvoiceItem, SoleInvoiceItemForm, SoleInvoiceService, SoleInvoiceStatusesEnum, SoleInvoiceTaxTypeEnum, SoleInvoiceTemplate, SoleInvoiceTemplateForm, SoleInvoiceTemplateService, SoleInvoiceTemplateTaxTypeEnum, SpareDocumentSpareTypeEnum, SseService, StatesEnum, SubscriptionService, TAX_RETURN_CATEGORIES, TYPE_LOAN, TankTypeEnum, TaxCalculationMedicareExemptionEnum, TaxCalculationTypeEnum, TaxExemption, TaxExemptionEnum, TaxExemptionMetadata, TaxExemptionMetadataEnum, TaxExemptionService, TaxReturnCategoryListEnum, TaxReturnCategorySectionEnum, TaxReview, TaxReviewCollection, TaxReviewHistoryService, TaxReviewService, TaxReviewStatusEnum, TaxSummary, TaxSummaryListEnum, TaxSummarySection, TaxSummarySectionEnum, TaxSummaryService, TaxSummaryTaxSummaryEnum, TaxSummaryTypeEnum, TicketFeedbackEnum, TicketStatusEnum, TicketTypesEnum, Toast, ToastService, ToastTypeEnum, Transaction, TransactionAllocation, TransactionAllocationCollection, TransactionAllocationService, TransactionBase, TransactionBaseCollection, TransactionCalculationService, TransactionCategoryEnum, TransactionCollection, TransactionMetadata, TransactionOperationEnum, TransactionReceipt, TransactionReceiptService, TransactionService, TransactionSourceEnum, TransactionTypeEnum, TtCoreModule, TutorialVideoService, USER_ROLES, USER_WORK_POSITION, User, UserEventSetting, UserEventSettingCollection, UserEventSettingFieldEnum, UserEventSettingService, UserEventStatusEnum, UserEventType, UserEventTypeCategory, UserEventTypeClientTypeEnum, UserEventTypeEmployeeTypeEnum, UserEventTypeFrequencyEnum, UserEventTypeService, UserEventTypeUserTypeEnum, UserInviteForm, UserMedicareExemptionEnum, UserRolesEnum, UserService, UserStatusEnum, UserSwitcherService, UserTitleEnum, UserToRegister, UserWorkDepreciationCalculationEnum, UserWorkingHolidayMakerEnum, UsersInviteService, Vehicle, VehicleClaim, VehicleClaimCollection, VehicleClaimDetails, VehicleClaimDetailsForm, VehicleClaimDetailsMethodEnum, VehicleClaimDetailsService, VehicleClaimForm, VehicleClaimService, VehicleExpense, VehicleExpenseCollection, VehicleForm, VehicleLogbook, VehicleLogbookCollection, VehicleLogbookForm, VehicleLogbookPurposeEnum, VehicleLogbookService, VehicleService, XlsxService, atLeastOneCheckedValidator, atoLinks, autocompleteValidator, cloneDeep, compare, compareMatOptions, conditionalValidator, createDate, displayMatOptions, enumToList, fieldsSumValidator, getDocIcon, minDateValidator, passwordMatchValidator, passwordValidator, replace, roundTo, sort, sortDeep, taxReviewFilterPredicate };
17666
+ export { AbstractForm, AbstractModel, AccountSetupItem, AccountSetupItemCollection, AccountSetupService, Address, AddressForm, AddressService, AddressTypeEnum, AlphabetColorsEnum, AnnualFrequencyEnum, AppEvent, AppEvent2, AppEventTypeEnum, AssetEntityTypeEnum, AssetTypeEnum, AssetsService, AuthService, BANK_ACCOUNT_TYPES, Badge, BadgeColorEnum, Bank, BankAccount, BankAccountAddManualForm, BankAccountAllocationForm, BankAccountCalculationService, BankAccountChartData, BankAccountCollection, BankAccountImportForm, BankAccountPropertiesForm, BankAccountProperty, BankAccountService, BankAccountStatusEnum, BankAccountTypeEnum, BankAccountsImportForm, BankConnection, BankConnectionService, BankConnectionStatusEnum, BankExternalStats, BankLoginData, BankLoginForm, BankService, BankTransaction, BankTransactionCalculationService, BankTransactionChartData, BankTransactionCollection, BankTransactionService, BankTransactionSummaryFieldsEnum, BankTransactionTypeEnum, BasReport, BasReportForm, BasReportService, BasiqConfig, BasiqJob, BasiqJobResponse, BasiqJobStep, BasiqService, BasiqToken, BasiqTokenService, BorrowingExpense, BorrowingExpenseLoan, BorrowingExpenseService, BusinessTypeEnum, CAPITAL_COSTS_ITEMS, CHART_ACCOUNTS_CATEGORIES, CalculationFormItem, CalculationFormTypeEnum, CgtExemptionAndRolloverCodeEnum, ChartAccounts, ChartAccountsCategoryECollection, ChartAccountsCategoryEnum, ChartAccountsCollection, ChartAccountsDepreciation, ChartAccountsDepreciationService, ChartAccountsEtpEnum, ChartAccountsHeading, ChartAccountsHeadingListEnum, ChartAccountsHeadingTaxDeductibleEnum, ChartAccountsHeadingTaxableEnum, ChartAccountsHeadingVehicleListEnum, ChartAccountsListEnum, ChartAccountsMetadata, ChartAccountsMetadataListEnum, ChartAccountsMetadataTypeEnum, ChartAccountsService, ChartAccountsTaxLabelsEnum, ChartAccountsTypeEnum, ChartAccountsValue, ChartData, ChartSerie, Chat, ChatCollection, ChatService, ChatStatusEnum, ChatViewTypeEnum, ClientCollection, ClientDetails, ClientDetailsMedicareExemptionEnum, ClientDetailsWorkDepreciationCalculationEnum, ClientDetailsWorkingHolidayMakerEnum, ClientIncomeTypes, ClientIncomeTypesForm, ClientIncomeTypesService, ClientInvite, ClientInviteCollection, ClientInviteService, ClientInviteStatusEnum, ClientInviteTypeEnum, ClientMovement, ClientMovementCollection, ClientMovementService, ClientPortfolioChartData, ClientPortfolioReport, ClientPortfolioReportCollection, ClientPortfolioReportService, Collection, CollectionDictionary, CorelogicService, CorelogicSuggestion, Country, DEDUCTION_CATEGORIES, DEPRECIATION_GROUPS, DOCUMENT_FILE_TYPES, DeductionClothingTypeEnum, DeductionSelfEducationTypeEnum, Depreciation, DepreciationCalculationEnum, DepreciationCalculationPercentEnum, DepreciationCapitalProject, DepreciationCapitalProjectService, DepreciationCollection, DepreciationForecast, DepreciationForecastCollection, DepreciationGroup, DepreciationGroupEnum, DepreciationGroupItem, DepreciationLvpAssetTypeEnum, DepreciationLvpReportItem, DepreciationLvpReportItemCollection, DepreciationReceipt, DepreciationReceiptService, DepreciationReportItem, DepreciationReportItemCollection, DepreciationService, DepreciationTypeEnum, DepreciationWriteOffAmountEnum, Dictionary, Document, DocumentApiUrlPrefixEnum, DocumentFolder, DocumentFolderService, DocumentService, DocumentTypeEnum, ENDPOINTS, EmployeeCollection, EmployeeDetails, EmployeeInvite, EmployeeInviteService, EmployeeService, Endpoint, EquityPositionChartService, EventDispatcherService, ExportDataTable, ExportFormatEnum, ExportFormatterService, ExportableCollection, FacebookService, FinancialYear, Firm, FirmService, FirmTypeEnum, HeaderTitleService, IconsFileEnum, IncomeAmountTypeEnum, IncomePosition, IncomeSource, IncomeSourceChartData, IncomeSourceCollection, IncomeSourceForecast, IncomeSourceForecastService, IncomeSourceForecastTrustTypeEnum, IncomeSourceService, IncomeSourceType, IncomeSourceTypeEnum, IncomeSourceTypeListOtherEnum, IncomeSourceTypeListSoleEnum, IncomeSourceTypeListWorkEnum, InterceptorsModule, IntercomService, InviteStatusEnum, JwtService, Loan, LoanBankTypeEnum, LoanCollection, LoanForm, LoanFrequencyEnum, LoanInterestTypeEnum, LoanMaxNumberOfPaymentsEnum, LoanPayment, LoanPaymentCollection, LoanPayout, LoanPayoutTypeEnum, LoanRepaymentFrequencyEnum, LoanRepaymentTypeEnum, LoanService, LoanTypeEnum, LoanVehicleTypeEnum, LogbookBestPeriodService, LogbookPeriod, LoginForm, LossTypeEnum, MODULE_URL_LIST, MONTHS, Message, MessageCollection, MessageDocument, MessageDocumentCollection, MessageDocumentService, MessageService, MonthNameShortEnum, MonthNumberEnum, MyAccountHistory, MyAccountHistoryInitiatedByEnum, MyAccountHistoryStatusEnum, MyAccountHistoryTypeEnum, MyTaxBusinessDetails, MyTaxBusinessDetailsForm, MyTaxBusinessIncome, MyTaxBusinessIncomeForm, MyTaxBusinessIncomeOrLossesForm, MyTaxBusinessLosses, MyTaxBusinessLossesForm, MyTaxCgt, MyTaxCgtForm, MyTaxDeductions, MyTaxDeductionsForm, MyTaxDividends, MyTaxDividendsForm, MyTaxEmployeeShareSchemes, MyTaxEmployeeShareSchemesForm, MyTaxEstimate, MyTaxIncomeStatements, MyTaxIncomeStatementsForm, MyTaxIncomeTests, MyTaxIncomeTestsForm, MyTaxInterest, MyTaxInterestForm, MyTaxLosses, MyTaxLossesForm, MyTaxMedicareForm, MyTaxOffsets, MyTaxOffsetsForm, MyTaxOtherIncome, MyTaxOtherIncomeForm, MyTaxPartnershipsAndTrusts, MyTaxPartnershipsAndTrustsForm, MyTaxRent, MyTaxRentForm, Notification, Occupation, OccupationService, PASSWORD_REGEXPS, PasswordForm, PdfFromDataTableService, PdfFromDomElementService, PdfFromHtmlTableService, PdfFromTableService, PdfOrientationEnum, PdfSettings, Phone, PhoneForm, PhoneTypeEnum, PreloaderService, Property, PropertyCalculationService, PropertyCategory, PropertyCategoryListEnum, PropertyCategoryMovement, PropertyCategoryMovementCollection, PropertyCategoryMovementService, PropertyCategoryService, PropertyCollection, PropertyDepreciationCalculationEnum, PropertyDocument, PropertyDocumentService, PropertyEquityChartData, PropertyEquityChartItem, PropertyForecast, PropertyReportItem, PropertyReportItemCollection, PropertyReportItemDepreciation, PropertyReportItemDepreciationCollection, PropertyReportItemTransaction, PropertyReportItemTransactionCollection, PropertySale, PropertySaleCollection, PropertySaleCostBase, PropertySaleCostBaseForm, PropertySaleCostSaleForm, PropertySaleExemptionsForm, PropertySaleService, PropertySaleTaxExemptionMetadata, PropertySaleTaxExemptionMetadataCollection, PropertyService, PropertyShare, PropertyShareAccessEnum, PropertyShareService, PropertyShareStatusEnum, PropertySubscription, PropertyTransactionReportService, PropertyValuation, ReceiptService, RegisterClientForm, RegisterFirmForm, RegistrationInvite, RegistrationInviteStatusEnum, ReportItem, ReportItemCollection, ReportItemDetails, ResetPasswordForm, RestService, RewardfulService, SalaryForecast, SalaryForecastFrequencyEnum, SalaryForecastService, ServiceNotificationService, ServiceNotificationStatusEnum, ServiceNotificationTypeEnum, ServicePayment, ServicePaymentStatusEnum, ServicePrice, ServicePriceRecurringIntervalEnum, ServicePriceService, ServicePriceTypeEnum, ServiceProduct, ServiceProductIdEnum, ServiceProductStatusEnum, ServiceSubscription, ServiceSubscriptionCollection, ServiceSubscriptionItem, ServiceSubscriptionStatusEnum, ShareFilterOptionsEnum, SoleBusiness, SoleBusinessActivity, SoleBusinessActivityService, SoleBusinessAllocation, SoleBusinessAllocationsForm, SoleBusinessForm, SoleBusinessLoss, SoleBusinessLossForm, SoleBusinessLossOffsetRule, SoleBusinessLossOffsetRuleService, SoleBusinessLossReport, SoleBusinessLossService, SoleBusinessLossesCollection, SoleBusinessService, SoleContact, SoleContactForm, SoleContactService, SoleDepreciationMethod, SoleDepreciationMethodEnum, SoleDepreciationMethodForm, SoleDepreciationMethodService, SoleDetails, SoleDetailsForm, SoleDetailsService, SoleForecast, SoleForecastService, SoleInvoice, SoleInvoiceCollection, SoleInvoiceForm, SoleInvoiceItem, SoleInvoiceItemForm, SoleInvoiceService, SoleInvoiceStatusesEnum, SoleInvoiceTaxTypeEnum, SoleInvoiceTemplate, SoleInvoiceTemplateForm, SoleInvoiceTemplateService, SoleInvoiceTemplateTaxTypeEnum, SpareDocumentSpareTypeEnum, SseService, StatesEnum, SubscriptionService, TAX_RETURN_CATEGORIES, TYPE_LOAN, TankTypeEnum, TaxCalculationMedicareExemptionEnum, TaxCalculationTypeEnum, TaxExemption, TaxExemptionEnum, TaxExemptionMetadata, TaxExemptionMetadataEnum, TaxExemptionService, TaxReturnCategoryListEnum, TaxReturnCategorySectionEnum, TaxReview, TaxReviewCollection, TaxReviewHistoryService, TaxReviewService, TaxReviewStatusEnum, TaxSummary, TaxSummaryListEnum, TaxSummarySection, TaxSummarySectionEnum, TaxSummaryService, TaxSummaryTaxSummaryEnum, TaxSummaryTypeEnum, TicketFeedbackEnum, TicketStatusEnum, TicketTypesEnum, Toast, ToastService, ToastTypeEnum, Transaction, TransactionAllocation, TransactionAllocationCollection, TransactionAllocationService, TransactionBase, TransactionBaseCollection, TransactionCalculationService, TransactionCategoryEnum, TransactionCollection, TransactionMetadata, TransactionOperationEnum, TransactionReceipt, TransactionReceiptService, TransactionService, TransactionSourceEnum, TransactionTypeEnum, TtCoreModule, TutorialVideoService, USER_ROLES, USER_WORK_POSITION, User, UserEventSetting, UserEventSettingCollection, UserEventSettingFieldEnum, UserEventSettingService, UserEventStatusEnum, UserEventType, UserEventTypeCategory, UserEventTypeClientTypeEnum, UserEventTypeEmployeeTypeEnum, UserEventTypeFrequencyEnum, UserEventTypeService, UserEventTypeUserTypeEnum, UserInviteForm, UserMedicareExemptionEnum, UserRolesEnum, UserService, UserStatusEnum, UserSwitcherService, UserTitleEnum, UserToRegister, UserWorkDepreciationCalculationEnum, UserWorkingHolidayMakerEnum, UsersInviteService, Vehicle, VehicleClaim, VehicleClaimCollection, VehicleClaimDetails, VehicleClaimDetailsForm, VehicleClaimDetailsMethodEnum, VehicleClaimDetailsService, VehicleClaimForm, VehicleClaimService, VehicleExpense, VehicleExpenseCollection, VehicleForm, VehicleLogbook, VehicleLogbookCollection, VehicleLogbookForm, VehicleLogbookPurposeEnum, VehicleLogbookService, VehicleService, XlsxService, atLeastOneCheckedValidator, atoLinks, autocompleteValidator, cloneDeep, compare, compareMatOptions, conditionalValidator, createDate, displayMatOptions, enumToList, fieldsSumValidator, getDocIcon, minDateValidator, passwordMatchValidator, passwordValidator, replace, roundTo, sort, sortDeep, taxReviewFilterPredicate, toArray };
17431
17667
  //# sourceMappingURL=taxtank-core.js.map