taxtank-core 0.28.1 → 0.28.2

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 (30) hide show
  1. package/bundles/taxtank-core.umd.js +337 -244
  2. package/bundles/taxtank-core.umd.js.map +1 -1
  3. package/esm2015/lib/collections/vehicle/vehicle-logbook.collection.js +2 -2
  4. package/esm2015/lib/db/Models/sole/sole-business-loss.js +1 -1
  5. package/esm2015/lib/forms/sole/sole-business.form.js +11 -2
  6. package/esm2015/lib/forms/sole/sole-details.form.js +3 -2
  7. package/esm2015/lib/interceptors/basiq-client-id.interceptor.js +31 -0
  8. package/esm2015/lib/interceptors/basiq-token.interceptor.js +35 -0
  9. package/esm2015/lib/interceptors/interceptors.module.js +15 -4
  10. package/esm2015/lib/models/endpoint/endpoints.const.js +2 -1
  11. package/esm2015/lib/models/event/app-event-type.enum.js +21 -19
  12. package/esm2015/lib/models/vehicle/vehicle-logbook.js +4 -4
  13. package/esm2015/lib/services/http/sole/sole-depreciation-method/sole-depreciation-method.service.js +12 -1
  14. package/esm2015/lib/services/http/sole/sole-details/sole-details.service.js +10 -4
  15. package/esm2015/lib/services/http/user/user.service.js +12 -1
  16. package/esm2015/lib/validators/required-length.validator.js +12 -0
  17. package/fesm2015/taxtank-core.js +310 -225
  18. package/fesm2015/taxtank-core.js.map +1 -1
  19. package/lib/db/Models/sole/sole-business-loss.d.ts +2 -3
  20. package/lib/forms/sole/sole-business.form.d.ts +1 -0
  21. package/lib/interceptors/basiq-client-id.interceptor.d.ts +15 -0
  22. package/lib/interceptors/{basiq.interceptor.d.ts → basiq-token.interceptor.d.ts} +3 -3
  23. package/lib/models/event/app-event-type.enum.d.ts +20 -18
  24. package/lib/models/vehicle/vehicle-logbook.d.ts +2 -2
  25. package/lib/services/http/sole/sole-depreciation-method/sole-depreciation-method.service.d.ts +4 -1
  26. package/lib/services/http/sole/sole-details/sole-details.service.d.ts +3 -1
  27. package/lib/services/http/user/user.service.d.ts +4 -0
  28. package/lib/validators/required-length.validator.d.ts +5 -0
  29. package/package.json +1 -1
  30. package/esm2015/lib/interceptors/basiq.interceptor.js +0 -35
@@ -4,7 +4,7 @@ import * as i1$1 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 { ReplaySubject, Subject, BehaviorSubject, throwError, combineLatest, forkJoin, Observable, of, from } from 'rxjs';
7
+ import { ReplaySubject, Subject, BehaviorSubject, throwError, Observable, combineLatest, forkJoin, of, from } from 'rxjs';
8
8
  import { map, filter, catchError, take, switchMap, finalize, mergeMap, skip, distinctUntilChanged } from 'rxjs/operators';
9
9
  import { plainToClass, classToPlain, Type, Exclude, Transform, Expose } from 'class-transformer';
10
10
  import { JwtHelperService } from '@auth0/angular-jwt';
@@ -20,12 +20,12 @@ import uniqBy from 'lodash/uniqBy';
20
20
  import concat from 'lodash/concat';
21
21
  import { throwError as throwError$1 } from 'rxjs/internal/observable/throwError';
22
22
  import cloneDeep$1 from 'lodash/cloneDeep';
23
+ import { EventSourcePolyfill } from 'event-source-polyfill/src/eventsource.min.js';
23
24
  import compact from 'lodash/compact';
24
25
  import { Validators, FormGroup, FormControl, FormArray } from '@angular/forms';
25
26
  import isEqual from 'lodash/isEqual';
26
27
  import fromPairs from 'lodash/fromPairs';
27
28
  import _ from 'lodash';
28
- import { EventSourcePolyfill } from 'event-source-polyfill/src/eventsource.min.js';
29
29
  import * as i1$2 from '@angular/router';
30
30
  import { NavigationEnd } from '@angular/router';
31
31
  import clone from 'lodash/clone';
@@ -240,24 +240,26 @@ var AppEventTypeEnum;
240
240
  AppEventTypeEnum[AppEventTypeEnum["SERVICE_SUBSCRIPTION_UPDATED"] = 40] = "SERVICE_SUBSCRIPTION_UPDATED";
241
241
  AppEventTypeEnum[AppEventTypeEnum["SOLE_BUSINESS_CREATED"] = 41] = "SOLE_BUSINESS_CREATED";
242
242
  AppEventTypeEnum[AppEventTypeEnum["SOLE_DEPRECIATION_METHOD_UPDATED"] = 42] = "SOLE_DEPRECIATION_METHOD_UPDATED";
243
- AppEventTypeEnum[AppEventTypeEnum["TAX_REVIEW_UPDATED"] = 43] = "TAX_REVIEW_UPDATED";
244
- AppEventTypeEnum[AppEventTypeEnum["TRANSACTION_CREATED"] = 44] = "TRANSACTION_CREATED";
245
- AppEventTypeEnum[AppEventTypeEnum["TRANSACTION_DELETED"] = 45] = "TRANSACTION_DELETED";
246
- AppEventTypeEnum[AppEventTypeEnum["TRANSACTION_UPDATED"] = 46] = "TRANSACTION_UPDATED";
247
- AppEventTypeEnum[AppEventTypeEnum["TRANSACTION_UPDATED_WITH_RECEIPT"] = 47] = "TRANSACTION_UPDATED_WITH_RECEIPT";
248
- AppEventTypeEnum[AppEventTypeEnum["TRANSACTION_UPDATED_WITH_DELETED_RECEIPT"] = 48] = "TRANSACTION_UPDATED_WITH_DELETED_RECEIPT";
249
- AppEventTypeEnum[AppEventTypeEnum["TRANSACTION_RECEIPT_CREATED"] = 49] = "TRANSACTION_RECEIPT_CREATED";
250
- AppEventTypeEnum[AppEventTypeEnum["TRANSACTION_RECEIPT_DELETED"] = 50] = "TRANSACTION_RECEIPT_DELETED";
251
- AppEventTypeEnum[AppEventTypeEnum["TRANSACTIONS_CREATED"] = 51] = "TRANSACTIONS_CREATED";
252
- AppEventTypeEnum[AppEventTypeEnum["USER_UPDATED"] = 52] = "USER_UPDATED";
253
- AppEventTypeEnum[AppEventTypeEnum["VEHICLE_CLAIM_UPDATED"] = 53] = "VEHICLE_CLAIM_UPDATED";
254
- AppEventTypeEnum[AppEventTypeEnum["VEHICLE_CLAIM_CREATED"] = 54] = "VEHICLE_CLAIM_CREATED";
255
- AppEventTypeEnum[AppEventTypeEnum["VEHICLE_CLAIM_DETAILS_UPDATED"] = 55] = "VEHICLE_CLAIM_DETAILS_UPDATED";
256
- AppEventTypeEnum[AppEventTypeEnum["VEHICLE_CLAIM_DETAILS_CREATED"] = 56] = "VEHICLE_CLAIM_DETAILS_CREATED";
257
- AppEventTypeEnum[AppEventTypeEnum["VEHICLE_LOGBOOK_CREATED"] = 57] = "VEHICLE_LOGBOOK_CREATED";
258
- AppEventTypeEnum[AppEventTypeEnum["VEHICLE_LOGBOOK_UPDATED"] = 58] = "VEHICLE_LOGBOOK_UPDATED";
259
- AppEventTypeEnum[AppEventTypeEnum["VEHICLE_LOGBOOK_DELETED"] = 59] = "VEHICLE_LOGBOOK_DELETED";
260
- AppEventTypeEnum[AppEventTypeEnum["VEHICLE_LOGBOOK_BEST_PERIOD_UPDATED"] = 60] = "VEHICLE_LOGBOOK_BEST_PERIOD_UPDATED";
243
+ AppEventTypeEnum[AppEventTypeEnum["SOLE_DETAILS_CREATED"] = 43] = "SOLE_DETAILS_CREATED";
244
+ AppEventTypeEnum[AppEventTypeEnum["SOLE_DETAILS_UPDATED"] = 44] = "SOLE_DETAILS_UPDATED";
245
+ AppEventTypeEnum[AppEventTypeEnum["TAX_REVIEW_UPDATED"] = 45] = "TAX_REVIEW_UPDATED";
246
+ AppEventTypeEnum[AppEventTypeEnum["TRANSACTION_CREATED"] = 46] = "TRANSACTION_CREATED";
247
+ AppEventTypeEnum[AppEventTypeEnum["TRANSACTION_DELETED"] = 47] = "TRANSACTION_DELETED";
248
+ AppEventTypeEnum[AppEventTypeEnum["TRANSACTION_UPDATED"] = 48] = "TRANSACTION_UPDATED";
249
+ AppEventTypeEnum[AppEventTypeEnum["TRANSACTION_UPDATED_WITH_RECEIPT"] = 49] = "TRANSACTION_UPDATED_WITH_RECEIPT";
250
+ AppEventTypeEnum[AppEventTypeEnum["TRANSACTION_UPDATED_WITH_DELETED_RECEIPT"] = 50] = "TRANSACTION_UPDATED_WITH_DELETED_RECEIPT";
251
+ AppEventTypeEnum[AppEventTypeEnum["TRANSACTION_RECEIPT_CREATED"] = 51] = "TRANSACTION_RECEIPT_CREATED";
252
+ AppEventTypeEnum[AppEventTypeEnum["TRANSACTION_RECEIPT_DELETED"] = 52] = "TRANSACTION_RECEIPT_DELETED";
253
+ AppEventTypeEnum[AppEventTypeEnum["TRANSACTIONS_CREATED"] = 53] = "TRANSACTIONS_CREATED";
254
+ AppEventTypeEnum[AppEventTypeEnum["USER_UPDATED"] = 54] = "USER_UPDATED";
255
+ AppEventTypeEnum[AppEventTypeEnum["VEHICLE_CLAIM_UPDATED"] = 55] = "VEHICLE_CLAIM_UPDATED";
256
+ AppEventTypeEnum[AppEventTypeEnum["VEHICLE_CLAIM_CREATED"] = 56] = "VEHICLE_CLAIM_CREATED";
257
+ AppEventTypeEnum[AppEventTypeEnum["VEHICLE_CLAIM_DETAILS_UPDATED"] = 57] = "VEHICLE_CLAIM_DETAILS_UPDATED";
258
+ AppEventTypeEnum[AppEventTypeEnum["VEHICLE_CLAIM_DETAILS_CREATED"] = 58] = "VEHICLE_CLAIM_DETAILS_CREATED";
259
+ AppEventTypeEnum[AppEventTypeEnum["VEHICLE_LOGBOOK_CREATED"] = 59] = "VEHICLE_LOGBOOK_CREATED";
260
+ AppEventTypeEnum[AppEventTypeEnum["VEHICLE_LOGBOOK_UPDATED"] = 60] = "VEHICLE_LOGBOOK_UPDATED";
261
+ AppEventTypeEnum[AppEventTypeEnum["VEHICLE_LOGBOOK_DELETED"] = 61] = "VEHICLE_LOGBOOK_DELETED";
262
+ AppEventTypeEnum[AppEventTypeEnum["VEHICLE_LOGBOOK_BEST_PERIOD_UPDATED"] = 62] = "VEHICLE_LOGBOOK_BEST_PERIOD_UPDATED";
261
263
  })(AppEventTypeEnum || (AppEventTypeEnum = {}));
262
264
 
263
265
  class EventDispatcherService {
@@ -684,6 +686,7 @@ const ENDPOINTS = {
684
686
  SOLE_BUSINESSES_GET: new Endpoint('GET', '\\/sole-businesses'),
685
687
  SOLE_BUSINESSES_POST: new Endpoint('POST', '\\/sole-businesses'),
686
688
  SOLE_BUSINESSES_PUT: new Endpoint('PUT', '\\/sole-businesses\\/\\d+'),
689
+ BUSINESS_ACTIVITIES_GET: new Endpoint('GET', '\\/sole-business-activities'),
687
690
  SOLE_DEPRECIATION_METHODS_GET: new Endpoint('GET', '\\/sole-depreciation-methods'),
688
691
  SOLE_DEPRECIATION_METHODS_PUT: new Endpoint('PUT', '\\/sole-depreciation-methods\\/\\d+'),
689
692
  SOLE_INVOICES_GET: new Endpoint('GET', '\\/sole-invoices'),
@@ -2607,14 +2610,14 @@ class VehicleLogbook extends VehicleLogbook$1 {
2607
2610
  * Get logbook period date range from logbook date and weeksInPeriod duration
2608
2611
  */
2609
2612
  getPeriod() {
2610
- return moment.rangeFromInterval('weeks', VehicleLogbook.bestPeriodWeeks, this.date);
2613
+ return moment.rangeFromInterval('milliseconds', VehicleLogbook.bestPeriodDuration, this.date);
2611
2614
  }
2612
2615
  }
2613
2616
  /**
2614
- * Logbook period duration in weeks.
2617
+ * Logbook period duration in milliseconds.
2615
2618
  * https://taxtank.atlassian.net/wiki/spaces/TAXTANK/pages/211517441/Logbook+Vehicle
2616
2619
  */
2617
- VehicleLogbook.bestPeriodWeeks = 12;
2620
+ VehicleLogbook.bestPeriodDuration = 12 * 7 * 24 * 3600 * 1000;
2618
2621
  __decorate([
2619
2622
  Type(() => Date)
2620
2623
  ], VehicleLogbook.prototype, "date", void 0);
@@ -4732,7 +4735,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.15", ngImpo
4732
4735
  /**
4733
4736
  * Interceptor which adds user's basiq token to any http request to basiq api
4734
4737
  */
4735
- class BasiqInterceptor {
4738
+ class BasiqTokenInterceptor {
4736
4739
  constructor(basiqTokenService) {
4737
4740
  this.basiqTokenService = basiqTokenService;
4738
4741
  }
@@ -4753,12 +4756,239 @@ class BasiqInterceptor {
4753
4756
  });
4754
4757
  }
4755
4758
  }
4756
- BasiqInterceptor.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.2.15", ngImport: i0, type: BasiqInterceptor, deps: [{ token: BasiqTokenService }], target: i0.ɵɵFactoryTarget.Injectable });
4757
- BasiqInterceptor.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "12.2.15", ngImport: i0, type: BasiqInterceptor });
4758
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.15", ngImport: i0, type: BasiqInterceptor, decorators: [{
4759
+ BasiqTokenInterceptor.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.2.15", ngImport: i0, type: BasiqTokenInterceptor, deps: [{ token: BasiqTokenService }], target: i0.ɵɵFactoryTarget.Injectable });
4760
+ BasiqTokenInterceptor.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "12.2.15", ngImport: i0, type: BasiqTokenInterceptor });
4761
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.15", ngImport: i0, type: BasiqTokenInterceptor, decorators: [{
4759
4762
  type: Injectable
4760
4763
  }], ctorParameters: function () { return [{ type: BasiqTokenService }]; } });
4761
4764
 
4765
+ /**
4766
+ * server sent events service
4767
+ * https://symfony.com/doc/current/mercure.html
4768
+ */
4769
+ class SseService {
4770
+ constructor(zone, jwtService, environment) {
4771
+ this.zone = zone;
4772
+ this.jwtService = jwtService;
4773
+ this.environment = environment;
4774
+ }
4775
+ /**
4776
+ * list to url for server events
4777
+ */
4778
+ on(topic) {
4779
+ const url = new URL(this.environment.mercureUrl);
4780
+ url.searchParams.append('topic', `${this.environment.apiV2}/users/${this.jwtService.decodeToken().username}/${topic}`);
4781
+ // tslint:disable-next-line:typedef
4782
+ return new Observable((observer) => {
4783
+ const es = new EventSourcePolyfill(url, {
4784
+ headers: {
4785
+ Authorization: 'Bearer ' + this.jwtService.getToken(),
4786
+ }
4787
+ });
4788
+ es.onmessage = (event) => {
4789
+ this.zone.run(() => observer.next(event));
4790
+ };
4791
+ })
4792
+ .pipe(map((messageEvent) => {
4793
+ return JSON.parse(messageEvent.data);
4794
+ }));
4795
+ }
4796
+ }
4797
+ 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 });
4798
+ SseService.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "12.2.15", ngImport: i0, type: SseService, providedIn: 'root' });
4799
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.15", ngImport: i0, type: SseService, decorators: [{
4800
+ type: Injectable,
4801
+ args: [{
4802
+ providedIn: 'root'
4803
+ }]
4804
+ }], ctorParameters: function () { return [{ type: i0.NgZone }, { type: JwtService }, { type: undefined, decorators: [{
4805
+ type: Inject,
4806
+ args: ['environment']
4807
+ }] }]; } });
4808
+
4809
+ /**
4810
+ * Service to work with user
4811
+ */
4812
+ class UserService {
4813
+ constructor(http, jwtService, eventDispatcherService, sseService, environment) {
4814
+ this.http = http;
4815
+ this.jwtService = jwtService;
4816
+ this.eventDispatcherService = eventDispatcherService;
4817
+ this.sseService = sseService;
4818
+ this.environment = environment;
4819
+ this.cacheSubject = new ReplaySubject(1);
4820
+ this.listenEvents();
4821
+ }
4822
+ listenEvents() {
4823
+ this.listenServiceSubscriptionUpdated();
4824
+ }
4825
+ get() {
4826
+ if (!this.cache) {
4827
+ this.fetch().subscribe(() => { }, (error) => {
4828
+ // force logout user (clear localStorage) when get current user return error
4829
+ if (error.status === 500) {
4830
+ this.eventDispatcherService.dispatch(new AppEvent(AppEventTypeEnum.CURRENT_USER_GET_FAILED, null));
4831
+ }
4832
+ });
4833
+ }
4834
+ return this.cacheSubject.asObservable();
4835
+ }
4836
+ /**
4837
+ * Get current user
4838
+ */
4839
+ fetch() {
4840
+ return this.http.get(`${this.environment.apiV2}/users/current`)
4841
+ .pipe(map((userBase) => {
4842
+ const user = plainToClass(User, userBase);
4843
+ localStorage.setItem('userId', user.id.toString());
4844
+ // @TODO remove
4845
+ localStorage.setItem('financialYear', user.financialYear.toString());
4846
+ this.cache = user;
4847
+ this.cacheSubject.next(this.cache);
4848
+ return user;
4849
+ }));
4850
+ }
4851
+ /**
4852
+ * Register new user
4853
+ */
4854
+ register(data) {
4855
+ return this.http.post(`${this.environment.apiV2}/users/registration`, data);
4856
+ }
4857
+ /**
4858
+ * Update user
4859
+ */
4860
+ update(user) {
4861
+ return this.http.put(`${this.environment.apiV2}/users/${user.id}`, user)
4862
+ .pipe(map((userBase) => {
4863
+ this.cache = plainToClass(User, userBase);
4864
+ this.eventDispatcherService.dispatch(new AppEvent(AppEventTypeEnum.USER_UPDATED, null));
4865
+ this.cacheSubject.next(this.cache);
4866
+ }));
4867
+ }
4868
+ /**
4869
+ * Change user password
4870
+ */
4871
+ changePassword(currentPassword, newPassword) {
4872
+ return this.http.put(`${this.environment.apiV2}/users/password/change`, { currentPassword, newPassword });
4873
+ }
4874
+ /**
4875
+ * Recovery user password
4876
+ */
4877
+ recoveryPassword(email) {
4878
+ return this.http.put(`${this.environment.apiV2}/users/password/recovery`, { email });
4879
+ }
4880
+ /**
4881
+ * Reset user password
4882
+ */
4883
+ resetPassword(newPassword, resetToken) {
4884
+ return this.http.put(`${this.environment.apiV2}/users/password/reset`, { newPassword, resetToken });
4885
+ }
4886
+ resendConfirmationEmail(email) {
4887
+ return this.http.post(`${this.environment.apiV2}/users/confirmation/resend`, { email });
4888
+ }
4889
+ /**
4890
+ * Confirm registered user
4891
+ */
4892
+ confirm(verificationCode) {
4893
+ return this.http.post(`${this.environment.apiV2}/users/confirmation`, { verificationCode });
4894
+ }
4895
+ /**
4896
+ * Search existing user
4897
+ */
4898
+ search(email) {
4899
+ return this.http.get(`${this.environment.apiV2}/users/search?email=${email}`)
4900
+ .pipe(map((userBase) => {
4901
+ return plainToClass(User, userBase);
4902
+ }));
4903
+ }
4904
+ /**
4905
+ * Finish onboarding process
4906
+ */
4907
+ finishOnboarding(user) {
4908
+ return this.http.put(`${this.environment.apiV2}/users/status`, user)
4909
+ .pipe(map(() => {
4910
+ this.cache = user;
4911
+ this.cacheSubject.next(this.cache);
4912
+ }));
4913
+ }
4914
+ /**
4915
+ * Update user photo
4916
+ */
4917
+ updatePhoto(photo) {
4918
+ return this.http.post(`${this.environment.apiV2}/users/photo?_method=PUT`, photo)
4919
+ .pipe(map((photoUrl) => {
4920
+ this.cache = plainToClass(User, Object.assign(this.cache, { photo: photoUrl }));
4921
+ this.cacheSubject.next(this.cache);
4922
+ }));
4923
+ }
4924
+ switchFinancialYear(year) {
4925
+ return this.http.get(`${this.environment.apiV2}/financial-year/switch`, { params: new HttpParams({ fromString: `financialYear=${year}` }) }).pipe(map(() => {
4926
+ localStorage.setItem('financialYear', year.toString());
4927
+ window.location.reload();
4928
+ }));
4929
+ }
4930
+ /**
4931
+ * clear service cache
4932
+ */
4933
+ resetCache() {
4934
+ this.fetch().subscribe();
4935
+ }
4936
+ /**
4937
+ * Create basiq (if not exist yet) to provide access to basiq api
4938
+ */
4939
+ createBasiq() {
4940
+ return this.http.post(`${this.environment.apiV2}/basiq/user`, {})
4941
+ .pipe(map((basiqId) => {
4942
+ this.cache = plainToClass(User, Object.assign(this.cache, { basiqId }));
4943
+ this.cacheSubject.next(this.cache);
4944
+ return basiqId;
4945
+ }));
4946
+ }
4947
+ /**
4948
+ * Update cache when user's service subscription is updated
4949
+ */
4950
+ listenServiceSubscriptionUpdated() {
4951
+ this.eventDispatcherService.on(AppEventTypeEnum.SERVICE_SUBSCRIPTION_UPDATED).subscribe(() => this.resetCache());
4952
+ }
4953
+ }
4954
+ 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 });
4955
+ UserService.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "12.2.15", ngImport: i0, type: UserService, providedIn: 'root' });
4956
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.15", ngImport: i0, type: UserService, decorators: [{
4957
+ type: Injectable,
4958
+ args: [{
4959
+ providedIn: 'root'
4960
+ }]
4961
+ }], ctorParameters: function () { return [{ type: i1.HttpClient }, { type: JwtService }, { type: EventDispatcherService }, { type: SseService }, { type: undefined, decorators: [{
4962
+ type: Inject,
4963
+ args: ['environment']
4964
+ }] }]; } });
4965
+
4966
+ /**
4967
+ * Interceptor which check if client's basiq id exist and request it if not
4968
+ */
4969
+ class BasiqClientIdInterceptor {
4970
+ constructor(userService) {
4971
+ this.userService = userService;
4972
+ }
4973
+ intercept(request, next) {
4974
+ // Check if 'client id' URL segment contains null instead of id
4975
+ if (!request.url.startsWith(`${BasiqService.basiqApiUrl}/users/null`)) {
4976
+ return next.handle(request);
4977
+ }
4978
+ return this.userService.createBasiq().pipe(mergeMap((basiqClientId) => next.handle(this.addId(request, basiqClientId))));
4979
+ }
4980
+ addId(request, basiqClientId) {
4981
+ return request.clone({
4982
+ url: request.url.replace('null', basiqClientId)
4983
+ });
4984
+ }
4985
+ }
4986
+ BasiqClientIdInterceptor.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.2.15", ngImport: i0, type: BasiqClientIdInterceptor, deps: [{ token: UserService }], target: i0.ɵɵFactoryTarget.Injectable });
4987
+ BasiqClientIdInterceptor.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "12.2.15", ngImport: i0, type: BasiqClientIdInterceptor });
4988
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.15", ngImport: i0, type: BasiqClientIdInterceptor, decorators: [{
4989
+ type: Injectable
4990
+ }], ctorParameters: function () { return [{ type: UserService }]; } });
4991
+
4762
4992
  class InterceptorsModule {
4763
4993
  }
4764
4994
  InterceptorsModule.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.2.15", ngImport: i0, type: InterceptorsModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule });
@@ -4792,7 +5022,12 @@ InterceptorsModule.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", vers
4792
5022
  },
4793
5023
  {
4794
5024
  provide: HTTP_INTERCEPTORS,
4795
- useClass: BasiqInterceptor,
5025
+ useClass: BasiqTokenInterceptor,
5026
+ multi: true
5027
+ },
5028
+ {
5029
+ provide: HTTP_INTERCEPTORS,
5030
+ useClass: BasiqClientIdInterceptor,
4796
5031
  multi: true
4797
5032
  }
4798
5033
  ] });
@@ -4828,7 +5063,12 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.15", ngImpo
4828
5063
  },
4829
5064
  {
4830
5065
  provide: HTTP_INTERCEPTORS,
4831
- useClass: BasiqInterceptor,
5066
+ useClass: BasiqTokenInterceptor,
5067
+ multi: true
5068
+ },
5069
+ {
5070
+ provide: HTTP_INTERCEPTORS,
5071
+ useClass: BasiqClientIdInterceptor,
4832
5072
  multi: true
4833
5073
  }
4834
5074
  ]
@@ -4899,7 +5139,7 @@ class VehicleLogbookCollection extends Collection {
4899
5139
  if (this.items.length < 2) {
4900
5140
  return false;
4901
5141
  }
4902
- return VehicleLogbook.bestPeriodWeeks < (this.last.date.getTime() - this.first.date.getTime());
5142
+ return VehicleLogbook.bestPeriodDuration < (this.last.date.getTime() - this.first.date.getTime());
4903
5143
  }
4904
5144
  /**
4905
5145
  * Get collection of non-personal logbooks (work-related, sole-related).
@@ -8974,6 +9214,10 @@ class SoleDepreciationMethodService {
8974
9214
  this.toastService = toastService;
8975
9215
  this.cacheSubject = new ReplaySubject(1);
8976
9216
  this.url = 'sole-depreciation-methods';
9217
+ this.listenEvents();
9218
+ }
9219
+ listenEvents() {
9220
+ this.listenSoleDetailsChanges();
8977
9221
  }
8978
9222
  get() {
8979
9223
  if (!this.cache) {
@@ -9000,6 +9244,13 @@ class SoleDepreciationMethodService {
9000
9244
  return throwError$1(error);
9001
9245
  }));
9002
9246
  }
9247
+ listenSoleDetailsChanges() {
9248
+ this.eventDispatcherService.on([AppEventTypeEnum.SOLE_DETAILS_CREATED, AppEventTypeEnum.SOLE_DETAILS_UPDATED])
9249
+ .subscribe(() => {
9250
+ this.cache = null;
9251
+ this.get().subscribe();
9252
+ });
9253
+ }
9003
9254
  }
9004
9255
  SoleDepreciationMethodService.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.2.15", ngImport: i0, type: SoleDepreciationMethodService, deps: [{ token: i1.HttpClient }, { token: 'environment' }, { token: EventDispatcherService }, { token: ToastService }], target: i0.ɵɵFactoryTarget.Injectable });
9005
9256
  SoleDepreciationMethodService.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "12.2.15", ngImport: i0, type: SoleDepreciationMethodService, providedIn: 'root' });
@@ -9017,9 +9268,10 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.15", ngImpo
9017
9268
  * @TODO TT-1777 Alex: extend from rest service when it refactored
9018
9269
  */
9019
9270
  class SoleDetailsService {
9020
- constructor(http, environment) {
9271
+ constructor(http, environment, eventDispatcherService) {
9021
9272
  this.http = http;
9022
9273
  this.environment = environment;
9274
+ this.eventDispatcherService = eventDispatcherService;
9023
9275
  this.cacheSubject = new ReplaySubject(1);
9024
9276
  }
9025
9277
  get() {
@@ -9042,6 +9294,7 @@ class SoleDetailsService {
9042
9294
  return this.http.post(`${this.environment.apiV2}/sole-details`, soleDetails).pipe(map((soleDetailsBase) => {
9043
9295
  this.cache = plainToClass(SoleDetails, soleDetailsBase);
9044
9296
  this.cacheSubject.next(this.cache);
9297
+ this.eventDispatcherService.dispatch(new AppEvent(AppEventTypeEnum.SOLE_DETAILS_CREATED, soleDetails));
9045
9298
  return this.cache;
9046
9299
  }));
9047
9300
  }
@@ -9049,11 +9302,12 @@ class SoleDetailsService {
9049
9302
  return this.http.put(`${this.environment.apiV2}/sole-details/${soleDetails.id}`, soleDetails).pipe(map((soleDetailsBase) => {
9050
9303
  this.cache = plainToClass(SoleDetails, soleDetailsBase);
9051
9304
  this.cacheSubject.next(this.cache);
9305
+ this.eventDispatcherService.dispatch(new AppEvent(AppEventTypeEnum.SOLE_DETAILS_UPDATED, soleDetails));
9052
9306
  return this.cache;
9053
9307
  }));
9054
9308
  }
9055
9309
  }
9056
- SoleDetailsService.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.2.15", ngImport: i0, type: SoleDetailsService, deps: [{ token: i1.HttpClient }, { token: 'environment' }], target: i0.ɵɵFactoryTarget.Injectable });
9310
+ SoleDetailsService.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.2.15", ngImport: i0, type: SoleDetailsService, deps: [{ token: i1.HttpClient }, { token: 'environment' }, { token: EventDispatcherService }], target: i0.ɵɵFactoryTarget.Injectable });
9057
9311
  SoleDetailsService.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "12.2.15", ngImport: i0, type: SoleDetailsService, providedIn: 'root' });
9058
9312
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.15", ngImport: i0, type: SoleDetailsService, decorators: [{
9059
9313
  type: Injectable,
@@ -9063,7 +9317,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.15", ngImpo
9063
9317
  }], ctorParameters: function () { return [{ type: i1.HttpClient }, { type: undefined, decorators: [{
9064
9318
  type: Inject,
9065
9319
  args: ['environment']
9066
- }] }]; } });
9320
+ }] }, { type: EventDispatcherService }]; } });
9067
9321
 
9068
9322
  class SoleInvoiceService extends RestService {
9069
9323
  constructor() {
@@ -11042,50 +11296,6 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.15", ngImpo
11042
11296
  }]
11043
11297
  }] });
11044
11298
 
11045
- /**
11046
- * server sent events service
11047
- * https://symfony.com/doc/current/mercure.html
11048
- */
11049
- class SseService {
11050
- constructor(zone, jwtService, environment) {
11051
- this.zone = zone;
11052
- this.jwtService = jwtService;
11053
- this.environment = environment;
11054
- }
11055
- /**
11056
- * list to url for server events
11057
- */
11058
- on(topic) {
11059
- const url = new URL(this.environment.mercureUrl);
11060
- url.searchParams.append('topic', `${this.environment.apiV2}/users/${this.jwtService.decodeToken().username}/${topic}`);
11061
- // tslint:disable-next-line:typedef
11062
- return new Observable((observer) => {
11063
- const es = new EventSourcePolyfill(url, {
11064
- headers: {
11065
- Authorization: 'Bearer ' + this.jwtService.getToken(),
11066
- }
11067
- });
11068
- es.onmessage = (event) => {
11069
- this.zone.run(() => observer.next(event));
11070
- };
11071
- })
11072
- .pipe(map((messageEvent) => {
11073
- return JSON.parse(messageEvent.data);
11074
- }));
11075
- }
11076
- }
11077
- 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 });
11078
- SseService.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "12.2.15", ngImport: i0, type: SseService, providedIn: 'root' });
11079
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.15", ngImport: i0, type: SseService, decorators: [{
11080
- type: Injectable,
11081
- args: [{
11082
- providedIn: 'root'
11083
- }]
11084
- }], ctorParameters: function () { return [{ type: i0.NgZone }, { type: JwtService }, { type: undefined, decorators: [{
11085
- type: Inject,
11086
- args: ['environment']
11087
- }] }]; } });
11088
-
11089
11299
  /**
11090
11300
  * Service for work with chats
11091
11301
  */
@@ -13570,152 +13780,6 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.15", ngImpo
13570
13780
  }]
13571
13781
  }] });
13572
13782
 
13573
- /**
13574
- * Service to work with user
13575
- */
13576
- class UserService {
13577
- constructor(http, jwtService, eventDispatcherService, sseService, environment) {
13578
- this.http = http;
13579
- this.jwtService = jwtService;
13580
- this.eventDispatcherService = eventDispatcherService;
13581
- this.sseService = sseService;
13582
- this.environment = environment;
13583
- this.cacheSubject = new ReplaySubject(1);
13584
- this.listenEvents();
13585
- }
13586
- listenEvents() {
13587
- this.listenServiceSubscriptionUpdated();
13588
- }
13589
- get() {
13590
- if (!this.cache) {
13591
- this.fetch().subscribe(() => { }, (error) => {
13592
- // force logout user (clear localStorage) when get current user return error
13593
- if (error.status === 500) {
13594
- this.eventDispatcherService.dispatch(new AppEvent(AppEventTypeEnum.CURRENT_USER_GET_FAILED, null));
13595
- }
13596
- });
13597
- }
13598
- return this.cacheSubject.asObservable();
13599
- }
13600
- /**
13601
- * Get current user
13602
- */
13603
- fetch() {
13604
- return this.http.get(`${this.environment.apiV2}/users/current`)
13605
- .pipe(map((userBase) => {
13606
- const user = plainToClass(User, userBase);
13607
- localStorage.setItem('userId', user.id.toString());
13608
- // @TODO remove
13609
- localStorage.setItem('financialYear', user.financialYear.toString());
13610
- this.cache = user;
13611
- this.cacheSubject.next(this.cache);
13612
- return user;
13613
- }));
13614
- }
13615
- /**
13616
- * Register new user
13617
- */
13618
- register(data) {
13619
- return this.http.post(`${this.environment.apiV2}/users/registration`, data);
13620
- }
13621
- /**
13622
- * Update user
13623
- */
13624
- update(user) {
13625
- return this.http.put(`${this.environment.apiV2}/users/${user.id}`, user)
13626
- .pipe(map((userBase) => {
13627
- this.cache = plainToClass(User, userBase);
13628
- this.eventDispatcherService.dispatch(new AppEvent(AppEventTypeEnum.USER_UPDATED, null));
13629
- this.cacheSubject.next(this.cache);
13630
- }));
13631
- }
13632
- /**
13633
- * Change user password
13634
- */
13635
- changePassword(currentPassword, newPassword) {
13636
- return this.http.put(`${this.environment.apiV2}/users/password/change`, { currentPassword, newPassword });
13637
- }
13638
- /**
13639
- * Recovery user password
13640
- */
13641
- recoveryPassword(email) {
13642
- return this.http.put(`${this.environment.apiV2}/users/password/recovery`, { email });
13643
- }
13644
- /**
13645
- * Reset user password
13646
- */
13647
- resetPassword(newPassword, resetToken) {
13648
- return this.http.put(`${this.environment.apiV2}/users/password/reset`, { newPassword, resetToken });
13649
- }
13650
- resendConfirmationEmail(email) {
13651
- return this.http.post(`${this.environment.apiV2}/users/confirmation/resend`, { email });
13652
- }
13653
- /**
13654
- * Confirm registered user
13655
- */
13656
- confirm(verificationCode) {
13657
- return this.http.post(`${this.environment.apiV2}/users/confirmation`, { verificationCode });
13658
- }
13659
- /**
13660
- * Search existing user
13661
- */
13662
- search(email) {
13663
- return this.http.get(`${this.environment.apiV2}/users/search?email=${email}`)
13664
- .pipe(map((userBase) => {
13665
- return plainToClass(User, userBase);
13666
- }));
13667
- }
13668
- /**
13669
- * Finish onboarding process
13670
- */
13671
- finishOnboarding(user) {
13672
- return this.http.put(`${this.environment.apiV2}/users/status`, user)
13673
- .pipe(map(() => {
13674
- this.cache = user;
13675
- this.cacheSubject.next(this.cache);
13676
- }));
13677
- }
13678
- /**
13679
- * Update user photo
13680
- */
13681
- updatePhoto(photo) {
13682
- return this.http.post(`${this.environment.apiV2}/users/photo?_method=PUT`, photo)
13683
- .pipe(map((photoUrl) => {
13684
- this.cache = plainToClass(User, Object.assign(this.cache, { photo: photoUrl }));
13685
- this.cacheSubject.next(this.cache);
13686
- }));
13687
- }
13688
- switchFinancialYear(year) {
13689
- return this.http.get(`${this.environment.apiV2}/financial-year/switch`, { params: new HttpParams({ fromString: `financialYear=${year}` }) }).pipe(map(() => {
13690
- localStorage.setItem('financialYear', year.toString());
13691
- window.location.reload();
13692
- }));
13693
- }
13694
- /**
13695
- * clear service cache
13696
- */
13697
- resetCache() {
13698
- this.fetch().subscribe();
13699
- }
13700
- /**
13701
- * Update cache when user's service subscription is updated
13702
- */
13703
- listenServiceSubscriptionUpdated() {
13704
- this.eventDispatcherService.on(AppEventTypeEnum.SERVICE_SUBSCRIPTION_UPDATED).subscribe(() => this.resetCache());
13705
- }
13706
- }
13707
- 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 });
13708
- UserService.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "12.2.15", ngImport: i0, type: UserService, providedIn: 'root' });
13709
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.15", ngImport: i0, type: UserService, decorators: [{
13710
- type: Injectable,
13711
- args: [{
13712
- providedIn: 'root'
13713
- }]
13714
- }], ctorParameters: function () { return [{ type: i1.HttpClient }, { type: JwtService }, { type: EventDispatcherService }, { type: SseService }, { type: undefined, decorators: [{
13715
- type: Inject,
13716
- args: ['environment']
13717
- }] }]; } });
13718
-
13719
13783
  /**
13720
13784
  * Service to work with XLSX (generate, download, e.t.c.)
13721
13785
  */
@@ -14297,7 +14361,7 @@ class SoleBusinessForm extends AbstractForm {
14297
14361
  name: new FormControl(business.name, Validators.required),
14298
14362
  activity: new FormControl(business.activity, Validators.required),
14299
14363
  description: new FormControl(business.description),
14300
- website: new FormControl(business.website),
14364
+ website: new FormControl(business.website)
14301
14365
  }, business);
14302
14366
  // User have to create income source with new business.
14303
14367
  // Income source is not able for edit business
@@ -14314,11 +14378,20 @@ class SoleBusinessForm extends AbstractForm {
14314
14378
  })
14315
14379
  ])
14316
14380
  }));
14381
+ this.addControl('losses', new FormArray([
14382
+ new FormGroup({
14383
+ financialYear: new FormControl(new FinancialYear().year),
14384
+ openBalance: new FormControl(null, Validators.required)
14385
+ })
14386
+ ]));
14317
14387
  }
14318
14388
  }
14319
14389
  get forecastFormGroup() {
14320
14390
  return this.get('incomeSource').get('soleForecasts').at(0);
14321
14391
  }
14392
+ get lossFormGroup() {
14393
+ return this.get('losses').at(0);
14394
+ }
14322
14395
  }
14323
14396
 
14324
14397
  /**
@@ -14406,10 +14479,22 @@ class SoleDepreciationMethodForm extends AbstractForm {
14406
14479
  }
14407
14480
  }
14408
14481
 
14482
+ /**
14483
+ * Validator check if entered strong length is equal to passed length parameter
14484
+ */
14485
+ function requiredLengthValidator(length) {
14486
+ return (control) => {
14487
+ if (control.value && control.value.length !== length) {
14488
+ return { requiredLength: length };
14489
+ }
14490
+ return null;
14491
+ };
14492
+ }
14493
+
14409
14494
  class SoleDetailsForm extends AbstractForm {
14410
14495
  constructor(soleDetails) {
14411
14496
  super({
14412
- abn: new FormControl(soleDetails.abn, [Validators.required, Validators.minLength(11), Validators.maxLength(11)]),
14497
+ abn: new FormControl(soleDetails.abn, [Validators.required, requiredLengthValidator(11)]),
14413
14498
  isGST: new FormControl(soleDetails.isGST || false)
14414
14499
  }, soleDetails);
14415
14500
  }