taxtank-core 2.0.67 → 2.0.68

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.
@@ -17,12 +17,12 @@ import uniqBy from 'lodash/uniqBy';
17
17
  import first from 'lodash/first';
18
18
  import last from 'lodash/last';
19
19
  import orderBy from 'lodash/orderBy';
20
+ import round from 'lodash/round';
20
21
  import uniq from 'lodash/uniq';
21
22
  import moment from 'moment';
22
23
  import { DateRange as DateRange$1 } from 'moment-range';
23
24
  import * as i3 from 'taxtank-core/common';
24
25
  import { UserRolesEnum as UserRolesEnum$1, MixpanelService as MixpanelService$1 } from 'taxtank-core/common';
25
- import round from 'lodash/round';
26
26
  import range from 'lodash/range';
27
27
  import { Validators, FormGroup, FormArray, UntypedFormControl, UntypedFormArray, UntypedFormGroup, FormControl } from '@angular/forms';
28
28
  import compact from 'lodash/compact';
@@ -2469,6 +2469,22 @@ class PropertyCollection extends Collection {
2469
2469
  }
2470
2470
  return propertiesByCategory;
2471
2471
  }
2472
+ getEquityPositionByProperty(bankAccounts) {
2473
+ const loanAccounts = bankAccounts.getOwn().getLoanAndOffsetAccounts();
2474
+ const equityPositionByProperty = new Dictionary([]);
2475
+ this.items.forEach(property => {
2476
+ equityPositionByProperty.add(property.id, property.getEquityPosition(loanAccounts.getByPropertyId(property.id)));
2477
+ });
2478
+ return equityPositionByProperty;
2479
+ }
2480
+ getLvrByProperty(bankAccounts) {
2481
+ const loanAccounts = bankAccounts.getOwn().getLoanAndOffsetAccounts();
2482
+ const lvrByProperty = new Dictionary([]);
2483
+ this.items.forEach(property => {
2484
+ lvrByProperty.add(property.id, property.getLvr(loanAccounts.getByPropertyId(property.id)));
2485
+ });
2486
+ return lvrByProperty;
2487
+ }
2472
2488
  }
2473
2489
 
2474
2490
  class PropertyCategoryMovementCollection extends Collection {
@@ -6171,6 +6187,12 @@ class Property extends Property$1 {
6171
6187
  getGrowth() {
6172
6188
  return this.valuation.marketValue - this.purchasePrice;
6173
6189
  }
6190
+ getEquityPosition(bankAccounts) {
6191
+ return this.marketValue - Math.abs(bankAccounts.getLoanValue(this));
6192
+ }
6193
+ getLvr(bankAccounts) {
6194
+ return bankAccounts.getActiveLoanAccountsByProperties([this.id]).propertiesBalanceAmount / this.marketValue * 100;
6195
+ }
6174
6196
  }
6175
6197
  __decorate([
6176
6198
  Type(() => Number)
@@ -9477,6 +9499,9 @@ class BankAccountCollection extends Collection {
9477
9499
  getActiveLoanAccountsByProperties(ids) {
9478
9500
  return this.getActive().getLoanAccounts().getByPropertiesIds(ids);
9479
9501
  }
9502
+ getLoanValue(property) {
9503
+ return this.items.reduce((propertyAmount, bankAccount) => propertyAmount + bankAccount.getPropertyBalanceAmount(property.id), 0);
9504
+ }
9480
9505
  }
9481
9506
 
9482
9507
  /**
@@ -9756,6 +9781,20 @@ class FinancialGoalCollection extends Collection {
9756
9781
  getActive() {
9757
9782
  return this.filterBy('status', [FinancialGoalStatusEnum.ACTIVE, FinancialGoalStatusEnum.PAUSE]);
9758
9783
  }
9784
+ getPropertiesByGoal(properties) {
9785
+ const propertiesByGoal = new CollectionDictionary(new PropertyCollection());
9786
+ this.items.forEach(goal => {
9787
+ propertiesByGoal.add(goal.id, properties.filterBy('id', goal.properties));
9788
+ });
9789
+ return propertiesByGoal;
9790
+ }
9791
+ getBankAccountsByGoal(bankAccounts) {
9792
+ const bankAccountsByGoal = new CollectionDictionary(new BankAccountCollection());
9793
+ this.items.forEach(goal => {
9794
+ bankAccountsByGoal.add(goal.id, bankAccounts.filterBy('id', goal.bankAccount));
9795
+ });
9796
+ return bankAccountsByGoal;
9797
+ }
9759
9798
  }
9760
9799
 
9761
9800
  /**
@@ -10803,6 +10842,12 @@ class Dictionary {
10803
10842
  get(key) {
10804
10843
  return this.items[key] !== undefined ? this.items[key] : null;
10805
10844
  }
10845
+ sum(keys) {
10846
+ return round(keys.reduce((sum, key) => sum + (+this.get(key)), 0), 2);
10847
+ }
10848
+ avg(keys) {
10849
+ return round(this.sum(keys) / keys.length, 2);
10850
+ }
10806
10851
  merge(dictionary) {
10807
10852
  Object.assign(this.items, dictionary.items);
10808
10853
  return this;
@@ -11591,6 +11636,9 @@ class FinancialGoal extends AbstractModel {
11591
11636
  }
11592
11637
  return payments;
11593
11638
  }
11639
+ get propertyIds() {
11640
+ return this.properties.map(property => property.id);
11641
+ }
11594
11642
  }
11595
11643
  __decorate([
11596
11644
  Type(() => Date)
@@ -21049,6 +21097,10 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.10", ngImpo
21049
21097
  * Logic here works like collections methods but for several entities
21050
21098
  */
21051
21099
  class PropertyCalculationService {
21100
+ constructor() {
21101
+ this.propertyService = inject(PropertyService);
21102
+ this.bankAccountService = inject(BankAccountService);
21103
+ }
21052
21104
  getTaxPosition(transactions, depreciations) {
21053
21105
  // @TODO hack: math abs added because we have mismatching of real values signs
21054
21106
  return transactions.grossClaimAmount - Math.abs(depreciations.claimAmount);
@@ -21085,18 +21137,8 @@ class PropertyCalculationService {
21085
21137
  return properties.items.reduce((totalAmount, property) => totalAmount + bankAccounts.items
21086
21138
  .reduce((propertyAmount, bankAccount) => propertyAmount + bankAccount.getPropertyBalanceAmount(property.id), 0), 0);
21087
21139
  }
21088
- /**
21089
- * LVR
21090
- */
21091
- getLvr(properties, bankAccounts) {
21092
- // Math abs is required for correct percentage calculation
21093
- return bankAccounts.getActiveLoanAccountsByProperties(properties.getIds()).propertiesBalanceAmount / properties.marketValue;
21094
- }
21095
21140
  getLvr$(properties$, bankAccounts$) {
21096
- return combineLatest([
21097
- properties$,
21098
- bankAccounts$
21099
- ]).pipe(map(([properties, bankAccounts]) => this.getLvr(properties, bankAccounts)));
21141
+ return combineLatest([properties$, bankAccounts$]).pipe(map(([properties, bankAccounts]) => this.getLvr(properties, bankAccounts)));
21100
21142
  }
21101
21143
  getLvrCommencement(properties, loans, bankAccounts) {
21102
21144
  // Math abs is required for correct percentage calculation
@@ -21124,6 +21166,14 @@ class PropertyCalculationService {
21124
21166
  loans$
21125
21167
  ]).pipe(map(([properties, bankAccounts, loans]) => this.getLvrGrowth(properties, bankAccounts, loans)));
21126
21168
  }
21169
+ getEquityPosition$(propertyIds) {
21170
+ return combineLatest([this.propertyService.getBy('id', propertyIds), this.bankAccountService.getActive()])
21171
+ .pipe(map(([properties, bankAccounts]) => this.getEquityPosition(properties, bankAccounts.getOwn().getLoanAndOffsetAccounts().getByPropertiesIds(propertyIds))));
21172
+ }
21173
+ getLVR$(propertyIds) {
21174
+ return combineLatest([this.propertyService.getBy('id', propertyIds), this.bankAccountService.getActive()])
21175
+ .pipe(map(([properties, bankAccounts]) => this.getLvr(properties, bankAccounts.getOwn().getLoanAndOffsetAccounts().getByPropertiesIds(propertyIds))));
21176
+ }
21127
21177
  /**
21128
21178
  * Equity position = Market value - current loan value
21129
21179
  */
@@ -21131,6 +21181,13 @@ class PropertyCalculationService {
21131
21181
  // Math abs is required for correct percentage calculation
21132
21182
  return properties.marketValue - Math.abs(this.getLoanValue(properties, bankAccounts));
21133
21183
  }
21184
+ getLvr(properties, bankAccounts) {
21185
+ if (!properties.marketValue) {
21186
+ return 0;
21187
+ }
21188
+ // Math abs is required for correct percentage calculation
21189
+ return bankAccounts.getActiveLoanAccountsByProperties(properties.getIds()).propertiesBalanceAmount / properties.marketValue;
21190
+ }
21134
21191
  /**
21135
21192
  * Purchase Equity = Purchase price - initial loan value
21136
21193
  */
@@ -23262,7 +23319,7 @@ function greaterThanValidator(value) {
23262
23319
  /**
23263
23320
  * Validator that enforces the current control's value to be >= another control's value.
23264
23321
  */
23265
- function greaterThanControlValidator(controlName) {
23322
+ function greaterThanControlValidator(controlName, alias) {
23266
23323
  return (control) => {
23267
23324
  // skip validation until control is attached to a parent FormGroup
23268
23325
  if (!control?.parent) {
@@ -23271,7 +23328,7 @@ function greaterThanControlValidator(controlName) {
23271
23328
  const group = control.parent;
23272
23329
  const fieldToCompare = group.get(controlName);
23273
23330
  const isLessThan = Number(fieldToCompare.value) > Number(control.value);
23274
- return isLessThan ? { greaterThanControl: { min: fieldToCompare.value, actual: control.value } } : null;
23331
+ return isLessThan ? { greaterThanControl: `The value should be greater than ${alias}` } : null;
23275
23332
  };
23276
23333
  }
23277
23334
 
@@ -23457,9 +23514,25 @@ class LoanForm extends AbstractForm {
23457
23514
  }
23458
23515
  }
23459
23516
 
23517
+ /**
23518
+ * Validator that enforces the current control's value to be >= another control's value.
23519
+ */
23520
+ function lessThanControlValidator(controlName, alias) {
23521
+ return (control) => {
23522
+ // skip validation until control is attached to a parent FormGroup
23523
+ if (!control?.parent) {
23524
+ return null;
23525
+ }
23526
+ const group = control.parent;
23527
+ const fieldToCompare = group.get(controlName);
23528
+ const isLessThan = Number(fieldToCompare.value) > Number(control.value);
23529
+ return isLessThan ? null : { lessThanControl: `The value should be less than ${alias}` };
23530
+ };
23531
+ }
23532
+
23460
23533
  const END_DATE_VALIDATION_ERROR = 'Target date must be more than start date';
23461
23534
  class FinancialGoalForm extends AbstractForm {
23462
- constructor(goal = plainToClass(FinancialGoal, {})) {
23535
+ constructor(goal, equityByProperty, lvrByProperty) {
23463
23536
  super({
23464
23537
  type: new FormControl({ value: goal.type ?? FinancialGoalTypeEnum.DEBIT, disabled: !!goal.id }, Validators.required),
23465
23538
  name: new FormControl(goal.name, Validators.required),
@@ -23467,10 +23540,11 @@ class FinancialGoalForm extends AbstractForm {
23467
23540
  conditionalValidator(() => !this.isPropertyType(), Validators.required),
23468
23541
  ]),
23469
23542
  targetValue: new FormControl(goal.targetValue, [
23470
- greaterThanControlValidator('initialValue'),
23471
- Validators.required
23543
+ Validators.required,
23544
+ conditionalValidator(() => this.isLvrType(), lessThanControlValidator('initialValue', 'Start Value')),
23545
+ conditionalValidator(() => !this.isLvrType(), greaterThanControlValidator('initialValue', 'Start Value')),
23472
23546
  ]),
23473
- initialValue: new FormControl({ value: goal.initialValue, disabled: false }, Validators.required),
23547
+ initialValue: new FormControl({ value: goal.initialValue, disabled: true }, Validators.required),
23474
23548
  startDate: new FormControl({ value: goal.startDate, disabled: true }),
23475
23549
  endDate: new FormControl(goal.endDate, [Validators.required, minDateValidator(goal.startDate, END_DATE_VALIDATION_ERROR)]),
23476
23550
  paymentFrequency: new FormControl(goal.paymentFrequency, [
@@ -23482,10 +23556,12 @@ class FinancialGoalForm extends AbstractForm {
23482
23556
  inCalendar: new FormControl(goal.inCalendar),
23483
23557
  file: new FormControl(goal.file),
23484
23558
  description: new FormControl(goal.description),
23485
- properties: new FormControl(goal.properties, [
23559
+ properties: new FormControl({ value: goal.properties, disabled: !!goal.id }, [
23486
23560
  conditionalValidator(() => this.isPropertyType(), Validators.required),
23487
23561
  ]),
23488
23562
  }, goal);
23563
+ this.equityByProperty = equityByProperty;
23564
+ this.lvrByProperty = lvrByProperty;
23489
23565
  this.includeDisabledFields = true;
23490
23566
  this.bankAccountTypes = [];
23491
23567
  this.bankAccountTypes = this.getBankAccountTypes(goal.type);
@@ -23496,17 +23572,15 @@ class FinancialGoalForm extends AbstractForm {
23496
23572
  this.listenBankAccountChanges();
23497
23573
  this.listenPaymentChanges();
23498
23574
  }
23499
- isPropertyType() {
23500
- return [FinancialGoalTypeEnum.PROPERTY_EQUITY, FinancialGoalTypeEnum.PROPERTY_LVR].includes(this.value.type);
23501
- }
23502
23575
  listenTypeChanges() {
23503
23576
  this.get('type').valueChanges.subscribe((type) => {
23504
23577
  this.get('bankAccount').setValue(null, { onlySelf: true });
23505
- this.get('properties').setValue([], { onlySelf: true });
23578
+ this.get('properties').setValue([], { onlySelf: true, emitEvent: false });
23579
+ this.get('initialValue').setValue(null, { onlySelf: true, emitEvent: false });
23506
23580
  if (this.isPropertyType()) {
23507
- this.get('inCalendar').setValue(false, { onlySelf: true });
23508
- this.get('paymentFrequency').setValue(false, { onlySelf: true });
23509
- this.get('paymentAmount').setValue(false, { onlySelf: true });
23581
+ this.get('inCalendar').setValue(false, { onlySelf: true, emitEvent: false });
23582
+ this.get('paymentFrequency').setValue(false, { onlySelf: true, emitEvent: false });
23583
+ this.get('paymentAmount').setValue(false, { onlySelf: true, emitEvent: false });
23510
23584
  }
23511
23585
  this.bankAccountTypes = this.getBankAccountTypes(type);
23512
23586
  });
@@ -23531,11 +23605,9 @@ class FinancialGoalForm extends AbstractForm {
23531
23605
  this.get('endDate').setValue(this.calculateEndDate(), { emitEvent: false });
23532
23606
  });
23533
23607
  }
23534
- /**
23535
- * keeps updated initialValue when bankAccount updated. only for add form
23536
- */
23537
23608
  listenBankAccountChanges() {
23538
- this.get('bankAccount').valueChanges.pipe(filter((bankAccount) => !!bankAccount))
23609
+ this.get('bankAccount').valueChanges
23610
+ .pipe(filter((bankAccount) => !!bankAccount))
23539
23611
  .subscribe(bankAccount => {
23540
23612
  this.get('initialValue').setValue(bankAccount.currentBalance);
23541
23613
  });
@@ -23583,6 +23655,12 @@ class FinancialGoalForm extends AbstractForm {
23583
23655
  return [];
23584
23656
  }
23585
23657
  }
23658
+ isPropertyType() {
23659
+ return [FinancialGoalTypeEnum.PROPERTY_EQUITY, FinancialGoalTypeEnum.PROPERTY_LVR].includes(this.value.type);
23660
+ }
23661
+ isLvrType() {
23662
+ return this.value.type === FinancialGoalTypeEnum.PROPERTY_LVR;
23663
+ }
23586
23664
  }
23587
23665
 
23588
23666
  class FirmForm extends AbstractForm {