taxtank-core 2.0.66 → 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.
- package/fesm2022/taxtank-core.mjs +130 -39
- package/fesm2022/taxtank-core.mjs.map +1 -1
- package/index.d.ts +23 -12
- package/package.json +1 -1
|
@@ -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
|
/**
|
|
@@ -9754,7 +9779,21 @@ class ClientPortfolioReportCollection extends Collection {
|
|
|
9754
9779
|
|
|
9755
9780
|
class FinancialGoalCollection extends Collection {
|
|
9756
9781
|
getActive() {
|
|
9757
|
-
return this.filterBy('status', FinancialGoalStatusEnum.ACTIVE);
|
|
9782
|
+
return this.filterBy('status', [FinancialGoalStatusEnum.ACTIVE, FinancialGoalStatusEnum.PAUSE]);
|
|
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;
|
|
9758
9797
|
}
|
|
9759
9798
|
}
|
|
9760
9799
|
|
|
@@ -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;
|
|
@@ -11504,12 +11549,15 @@ class FinancialGoal extends AbstractModel {
|
|
|
11504
11549
|
constructor() {
|
|
11505
11550
|
super(...arguments);
|
|
11506
11551
|
this.startDate = moment().startOf('day').toDate();
|
|
11507
|
-
this.
|
|
11508
|
-
this.
|
|
11552
|
+
this.inCalendar = false;
|
|
11553
|
+
this.properties = [];
|
|
11509
11554
|
}
|
|
11510
11555
|
isCompleted() {
|
|
11511
11556
|
return this.status === FinancialGoalStatusEnum.COMPLETE;
|
|
11512
11557
|
}
|
|
11558
|
+
isPropertyType() {
|
|
11559
|
+
return [FinancialGoalTypeEnum.PROPERTY_EQUITY, FinancialGoalTypeEnum.PROPERTY_LVR].includes(this.type);
|
|
11560
|
+
}
|
|
11513
11561
|
/**
|
|
11514
11562
|
* today's forecasted progress
|
|
11515
11563
|
*/
|
|
@@ -11523,6 +11571,9 @@ class FinancialGoal extends AbstractModel {
|
|
|
11523
11571
|
* How much user saved so far.
|
|
11524
11572
|
*/
|
|
11525
11573
|
get progress() {
|
|
11574
|
+
if (this.isPropertyType()) {
|
|
11575
|
+
return 0;
|
|
11576
|
+
}
|
|
11526
11577
|
return this.isCompleted()
|
|
11527
11578
|
? Math.abs(this.finalValue - this.initialValue)
|
|
11528
11579
|
: Math.abs(this.bankAccount.currentBalance - this.initialValue);
|
|
@@ -11585,6 +11636,9 @@ class FinancialGoal extends AbstractModel {
|
|
|
11585
11636
|
}
|
|
11586
11637
|
return payments;
|
|
11587
11638
|
}
|
|
11639
|
+
get propertyIds() {
|
|
11640
|
+
return this.properties.map(property => property.id);
|
|
11641
|
+
}
|
|
11588
11642
|
}
|
|
11589
11643
|
__decorate([
|
|
11590
11644
|
Type(() => Date)
|
|
@@ -21043,6 +21097,10 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.10", ngImpo
|
|
|
21043
21097
|
* Logic here works like collections methods but for several entities
|
|
21044
21098
|
*/
|
|
21045
21099
|
class PropertyCalculationService {
|
|
21100
|
+
constructor() {
|
|
21101
|
+
this.propertyService = inject(PropertyService);
|
|
21102
|
+
this.bankAccountService = inject(BankAccountService);
|
|
21103
|
+
}
|
|
21046
21104
|
getTaxPosition(transactions, depreciations) {
|
|
21047
21105
|
// @TODO hack: math abs added because we have mismatching of real values signs
|
|
21048
21106
|
return transactions.grossClaimAmount - Math.abs(depreciations.claimAmount);
|
|
@@ -21079,18 +21137,8 @@ class PropertyCalculationService {
|
|
|
21079
21137
|
return properties.items.reduce((totalAmount, property) => totalAmount + bankAccounts.items
|
|
21080
21138
|
.reduce((propertyAmount, bankAccount) => propertyAmount + bankAccount.getPropertyBalanceAmount(property.id), 0), 0);
|
|
21081
21139
|
}
|
|
21082
|
-
/**
|
|
21083
|
-
* LVR
|
|
21084
|
-
*/
|
|
21085
|
-
getLvr(properties, bankAccounts) {
|
|
21086
|
-
// Math abs is required for correct percentage calculation
|
|
21087
|
-
return bankAccounts.getActiveLoanAccountsByProperties(properties.getIds()).propertiesBalanceAmount / properties.marketValue;
|
|
21088
|
-
}
|
|
21089
21140
|
getLvr$(properties$, bankAccounts$) {
|
|
21090
|
-
return combineLatest([
|
|
21091
|
-
properties$,
|
|
21092
|
-
bankAccounts$
|
|
21093
|
-
]).pipe(map(([properties, bankAccounts]) => this.getLvr(properties, bankAccounts)));
|
|
21141
|
+
return combineLatest([properties$, bankAccounts$]).pipe(map(([properties, bankAccounts]) => this.getLvr(properties, bankAccounts)));
|
|
21094
21142
|
}
|
|
21095
21143
|
getLvrCommencement(properties, loans, bankAccounts) {
|
|
21096
21144
|
// Math abs is required for correct percentage calculation
|
|
@@ -21118,6 +21166,14 @@ class PropertyCalculationService {
|
|
|
21118
21166
|
loans$
|
|
21119
21167
|
]).pipe(map(([properties, bankAccounts, loans]) => this.getLvrGrowth(properties, bankAccounts, loans)));
|
|
21120
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
|
+
}
|
|
21121
21177
|
/**
|
|
21122
21178
|
* Equity position = Market value - current loan value
|
|
21123
21179
|
*/
|
|
@@ -21125,6 +21181,13 @@ class PropertyCalculationService {
|
|
|
21125
21181
|
// Math abs is required for correct percentage calculation
|
|
21126
21182
|
return properties.marketValue - Math.abs(this.getLoanValue(properties, bankAccounts));
|
|
21127
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
|
+
}
|
|
21128
21191
|
/**
|
|
21129
21192
|
* Purchase Equity = Purchase price - initial loan value
|
|
21130
21193
|
*/
|
|
@@ -23256,7 +23319,7 @@ function greaterThanValidator(value) {
|
|
|
23256
23319
|
/**
|
|
23257
23320
|
* Validator that enforces the current control's value to be >= another control's value.
|
|
23258
23321
|
*/
|
|
23259
|
-
function greaterThanControlValidator(controlName) {
|
|
23322
|
+
function greaterThanControlValidator(controlName, alias) {
|
|
23260
23323
|
return (control) => {
|
|
23261
23324
|
// skip validation until control is attached to a parent FormGroup
|
|
23262
23325
|
if (!control?.parent) {
|
|
@@ -23265,7 +23328,7 @@ function greaterThanControlValidator(controlName) {
|
|
|
23265
23328
|
const group = control.parent;
|
|
23266
23329
|
const fieldToCompare = group.get(controlName);
|
|
23267
23330
|
const isLessThan = Number(fieldToCompare.value) > Number(control.value);
|
|
23268
|
-
return isLessThan ? {
|
|
23331
|
+
return isLessThan ? { greaterThanControl: `The value should be greater than ${alias}` } : null;
|
|
23269
23332
|
};
|
|
23270
23333
|
}
|
|
23271
23334
|
|
|
@@ -23451,38 +23514,57 @@ class LoanForm extends AbstractForm {
|
|
|
23451
23514
|
}
|
|
23452
23515
|
}
|
|
23453
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
|
+
|
|
23454
23533
|
const END_DATE_VALIDATION_ERROR = 'Target date must be more than start date';
|
|
23455
23534
|
class FinancialGoalForm extends AbstractForm {
|
|
23456
|
-
constructor(goal
|
|
23535
|
+
constructor(goal, equityByProperty, lvrByProperty) {
|
|
23457
23536
|
super({
|
|
23458
|
-
type: new FormControl({
|
|
23459
|
-
value: goal.type ?? FinancialGoalTypeEnum.DEBIT,
|
|
23460
|
-
disabled: !!goal.id
|
|
23461
|
-
}, Validators.required),
|
|
23537
|
+
type: new FormControl({ value: goal.type ?? FinancialGoalTypeEnum.DEBIT, disabled: !!goal.id }, Validators.required),
|
|
23462
23538
|
name: new FormControl(goal.name, Validators.required),
|
|
23463
23539
|
bankAccount: new FormControl({ value: goal.bankAccount, disabled: !!goal.id }, [
|
|
23464
|
-
conditionalValidator(() =>
|
|
23540
|
+
conditionalValidator(() => !this.isPropertyType(), Validators.required),
|
|
23465
23541
|
]),
|
|
23466
23542
|
targetValue: new FormControl(goal.targetValue, [
|
|
23467
|
-
|
|
23468
|
-
conditionalValidator(() => this.
|
|
23469
|
-
greaterThanControlValidator('initialValue'),
|
|
23470
|
-
Validators.required
|
|
23543
|
+
Validators.required,
|
|
23544
|
+
conditionalValidator(() => this.isLvrType(), lessThanControlValidator('initialValue', 'Start Value')),
|
|
23545
|
+
conditionalValidator(() => !this.isLvrType(), greaterThanControlValidator('initialValue', 'Start Value')),
|
|
23471
23546
|
]),
|
|
23472
23547
|
initialValue: new FormControl({ value: goal.initialValue, disabled: true }, Validators.required),
|
|
23473
23548
|
startDate: new FormControl({ value: goal.startDate, disabled: true }),
|
|
23474
23549
|
endDate: new FormControl(goal.endDate, [Validators.required, minDateValidator(goal.startDate, END_DATE_VALIDATION_ERROR)]),
|
|
23475
|
-
paymentFrequency: new FormControl(goal.paymentFrequency,
|
|
23476
|
-
|
|
23550
|
+
paymentFrequency: new FormControl(goal.paymentFrequency, [
|
|
23551
|
+
conditionalValidator(() => !this.isPropertyType(), Validators.required),
|
|
23552
|
+
]),
|
|
23553
|
+
paymentAmount: new FormControl(goal.paymentAmount, [
|
|
23554
|
+
conditionalValidator(() => !this.isPropertyType(), Validators.required),
|
|
23555
|
+
]),
|
|
23477
23556
|
inCalendar: new FormControl(goal.inCalendar),
|
|
23478
23557
|
file: new FormControl(goal.file),
|
|
23479
23558
|
description: new FormControl(goal.description),
|
|
23559
|
+
properties: new FormControl({ value: goal.properties, disabled: !!goal.id }, [
|
|
23560
|
+
conditionalValidator(() => this.isPropertyType(), Validators.required),
|
|
23561
|
+
]),
|
|
23480
23562
|
}, goal);
|
|
23563
|
+
this.equityByProperty = equityByProperty;
|
|
23564
|
+
this.lvrByProperty = lvrByProperty;
|
|
23481
23565
|
this.includeDisabledFields = true;
|
|
23482
23566
|
this.bankAccountTypes = [];
|
|
23483
|
-
this.isDebit = true;
|
|
23484
23567
|
this.bankAccountTypes = this.getBankAccountTypes(goal.type);
|
|
23485
|
-
this.isDebit = this.getIsDebit(goal.type);
|
|
23486
23568
|
this.listenEvents();
|
|
23487
23569
|
}
|
|
23488
23570
|
listenEvents() {
|
|
@@ -23493,8 +23575,14 @@ class FinancialGoalForm extends AbstractForm {
|
|
|
23493
23575
|
listenTypeChanges() {
|
|
23494
23576
|
this.get('type').valueChanges.subscribe((type) => {
|
|
23495
23577
|
this.get('bankAccount').setValue(null, { onlySelf: true });
|
|
23578
|
+
this.get('properties').setValue([], { onlySelf: true, emitEvent: false });
|
|
23579
|
+
this.get('initialValue').setValue(null, { onlySelf: true, emitEvent: false });
|
|
23580
|
+
if (this.isPropertyType()) {
|
|
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 });
|
|
23584
|
+
}
|
|
23496
23585
|
this.bankAccountTypes = this.getBankAccountTypes(type);
|
|
23497
|
-
this.isDebit = this.getIsDebit(type);
|
|
23498
23586
|
});
|
|
23499
23587
|
}
|
|
23500
23588
|
/**
|
|
@@ -23517,11 +23605,9 @@ class FinancialGoalForm extends AbstractForm {
|
|
|
23517
23605
|
this.get('endDate').setValue(this.calculateEndDate(), { emitEvent: false });
|
|
23518
23606
|
});
|
|
23519
23607
|
}
|
|
23520
|
-
/**
|
|
23521
|
-
* keeps updated initialValue when bankAccount updated. only for add form
|
|
23522
|
-
*/
|
|
23523
23608
|
listenBankAccountChanges() {
|
|
23524
|
-
this.get('bankAccount').valueChanges
|
|
23609
|
+
this.get('bankAccount').valueChanges
|
|
23610
|
+
.pipe(filter((bankAccount) => !!bankAccount))
|
|
23525
23611
|
.subscribe(bankAccount => {
|
|
23526
23612
|
this.get('initialValue').setValue(bankAccount.currentBalance);
|
|
23527
23613
|
});
|
|
@@ -23563,12 +23649,17 @@ class FinancialGoalForm extends AbstractForm {
|
|
|
23563
23649
|
switch (type) {
|
|
23564
23650
|
case FinancialGoalTypeEnum.CREDIT:
|
|
23565
23651
|
return [BankAccountTypeEnum.MORTGAGE, BankAccountTypeEnum.LOAN, BankAccountTypeEnum.CREDIT_CARD];
|
|
23566
|
-
|
|
23652
|
+
case FinancialGoalTypeEnum.DEBIT:
|
|
23567
23653
|
return [BankAccountTypeEnum.TRANSACTION, BankAccountTypeEnum.SAVINGS, BankAccountTypeEnum.OFFSET];
|
|
23654
|
+
default:
|
|
23655
|
+
return [];
|
|
23568
23656
|
}
|
|
23569
23657
|
}
|
|
23570
|
-
|
|
23571
|
-
return
|
|
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;
|
|
23572
23663
|
}
|
|
23573
23664
|
}
|
|
23574
23665
|
|