Skip to content

Commit

Permalink
save commit
Browse files Browse the repository at this point in the history
  • Loading branch information
praslnx8 committed Jan 16, 2024
1 parent dc84657 commit 48bbe46
Show file tree
Hide file tree
Showing 20 changed files with 337 additions and 376 deletions.
5 changes: 5 additions & 0 deletions lib/api/apis/basket_api.dart
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,11 @@ class BasketApi {
.get();
}

Future<BasketDO> getBy({required final int id}) async {
return (_db.select(_db.basketTable)..where((t) => t.id.equals(id)))
.getSingle();
}

Future<int> update(
{required final int id,
required final String name,
Expand Down
15 changes: 15 additions & 0 deletions lib/api/apis/investment_api.dart
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,21 @@ class InvestmentApi {
.get();
}

Future<InvestmentDO> getById({required final int id}) async {
return (_db.select(_db.investmentTable)..where((t) => t.id.equals(id)))
.getSingle();
}

Future<List<InvestmentDO>> getBy({final int? basketId}) async {
if (basketId != null) {
return (_db.select(_db.investmentTable)
..where((t) => t.basketId.equals(basketId)))
.get();
}

throw Exception('basketId is null');
}

Future<int> update({
required final int id,
required final String name,
Expand Down
2 changes: 1 addition & 1 deletion lib/api/apis/transaction_api.dart
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ class TransactionApi {
createdOn: createdOn));
}

Future<List<TransactionDO>> get({final int? investmentId}) async {
Future<List<TransactionDO>> getBy({final int? investmentId}) async {
if (investmentId == null) {
return (_db.select(_db.transactionTable)
..orderBy([(t) => OrderingTerm.desc(t.createdOn)]))
Expand Down
39 changes: 21 additions & 18 deletions lib/domain/models/basket.dart
Original file line number Diff line number Diff line change
@@ -1,37 +1,40 @@
import 'package:wealth_wave/api/apis/investment_api.dart';
import 'package:wealth_wave/api/db/app_database.dart';
import 'package:wealth_wave/domain/models/investment.dart';

class Basket {
final int id;
final String name;
final String? description;
final int investmentCount;
final double investedValue;

final InvestmentApi _investmentApi;

Basket(
{required this.id,
required this.name,
required this.description,
required this.investmentCount,
required this.investedValue});
InvestmentApi? investmentApi})
: _investmentApi = investmentApi ?? InvestmentApi();

static Basket from(
{required final BasketDO basket,
required final List<Investment> investments}) {
return Basket(
id: basket.id,
name: basket.name,
description: basket.description,
investments: investments);
Future<int> getTotalInvestments() {
return _investmentApi.getBy(basketId: id).then((value) => value.length);
}

double get totalValue {
return investments.fold(0, (previousValue, investment) {
return previousValue + investment.totalInvestedAmount;
});
Future<double> getInvestedValue() async {
return _investmentApi
.getBy(basketId: id)
.then((investments) => investments
.map((investmentDO) => Investment.from(investmentDO: investmentDO)))
.then((investments) => Future.wait(investments
.map((investment) => investment.getTotalInvestedAmount())))
.then((investedAmounts) =>
investedAmounts.reduce((value, element) => value + element));
}

int get investmentCount {
return investments.length;
static Basket from({required final BasketDO basketDO}) {
return Basket(
id: basketDO.id,
name: basketDO.name,
description: basketDO.description);
}
}
95 changes: 16 additions & 79 deletions lib/domain/models/goal.dart
Original file line number Diff line number Diff line change
@@ -1,98 +1,35 @@
import 'package:wealth_wave/api/db/app_database.dart';
import 'package:wealth_wave/contract/goal_importance.dart';
import 'package:wealth_wave/domain/models/investment.dart';

class Goal {
final int id;
final String name;
final String? description;
final double amount;
final DateTime createdDate;
final DateTime amountUpdatedOn;
final DateTime maturityDate;
final double inflation;
final double targetAmount;
final DateTime targetDate;
final GoalImportance importance;
final Map<Investment, double> taggedInvestments;

Goal(
{required this.id,
required this.name,
required this.description,
required this.amount,
required this.createdDate,
required this.maturityDate,
required this.inflation,
required this.targetAmount,
required this.targetDate,
required this.importance,
required this.taggedInvestments});

double getIrr({bool considerFutureTransactions = false}) {
double totalValue = 0.0;
double weightedSum = 0.0;

for (var investment in taggedInvestments.keys) {
//totalValue += investment.getFutureValueOn(date: targetDate, considerFutureTransactions: false);
//weightedSum += investedAmount * growthRate;
}

if (totalValue == 0.0) {
return 0.0;
}

return weightedSum / totalValue;
}

double getInvestedAmount() {
return taggedInvestments.keys
.map((e) => e.totalInvestedAmount * (taggedInvestments[e] ?? 0))
.reduce((a, b) => a + b);
}

double getInvestedValue() {
if (taggedInvestments.isEmpty) {
return 0;
}
// return taggedInvestments.keys
// .map((e) => (e.value / 100) * (taggedInvestments[e] ?? 0))
// .reduce((a, b) => a + b);
return 0;
required this.amountUpdatedOn,
required this.importance});

static Goal from({required final GoalDO goalDO}) {
return Goal(
id: goalDO.id,
name: goalDO.name,
description: goalDO.description,
amount: goalDO.amount,
maturityDate: goalDO.maturityDate,
inflation: goalDO.inflation,
amountUpdatedOn: goalDO.amountUpdatedOn,
importance: goalDO.importance);
}

double getProgress() {
double progress =
targetAmount > 0 ? getFutureValueOnTargetDate() / targetAmount : 0;
if (progress > 1) {
return 1;
}
return progress;
}

double getYearsLeft() {
return targetDate.difference(DateTime.now()).inDays.toDouble() / 365;
}

double getFutureValueOnTargetDate() {
if (taggedInvestments.isEmpty) {
return 0;
}
// return taggedInvestments.entries
// .map((e) => e.key.getFutureValueOn(targetDate) * e.value / 100)
// .reduce((a, b) => a + b);
return 0;
}

static Goal from(
{required final GoalDO goal,
required final Map<Investment, double> taggedInvestments}) =>
Goal(
id: goal.id,
name: goal.name,
description: goal.description,
amount: goal.amount,
createdDate: goal.date,
inflation: goal.inflation,
targetAmount: goal.targetAmount,
targetDate: goal.targetDate,
importance: goal.importance,
taggedInvestments: taggedInvestments);
}
145 changes: 69 additions & 76 deletions lib/domain/models/investment.dart
Original file line number Diff line number Diff line change
@@ -1,110 +1,103 @@
import 'dart:math';

import 'package:wealth_wave/api/apis/basket_api.dart';
import 'package:wealth_wave/api/apis/transaction_api.dart';
import 'package:wealth_wave/api/db/app_database.dart';
import 'package:wealth_wave/contract/risk_level.dart';
import 'package:wealth_wave/domain/irr_calculator.dart';
import 'package:wealth_wave/domain/models/sip.dart';
import 'package:wealth_wave/domain/models/basket.dart';
import 'package:wealth_wave/domain/models/irr_calculator.dart';
import 'package:wealth_wave/domain/models/transaction.dart';

class Investment {
final int id;
final String name;
final String? description;
final RiskLevel riskLevel;
final double? currentValue;
final double? value;
final double? irr;
final DateTime? currentValueUpdatedOn;
final DateTime? valueUpdatedOn;
final DateTime? maturityDate;
final int? basketId;
final String? basketName;
final double totalInvestedAmount;
final int totalTransactions;
final List<Transaction> transactions;
final List<SIP> sips;
final List<GoalInvestmentEnrichedMappingDO> taggedGoals;

final TransactionApi _transactionApi;
final IRRCalculator _irrCalculator;
final BasketApi _basketApi;

Investment(
{required this.id,
required this.name,
required this.description,
required this.riskLevel,
required this.irr,
required this.currentValue,
required this.currentValueUpdatedOn,
required this.value,
required this.valueUpdatedOn,
required this.basketId,
required this.basketName,
required this.maturityDate,
required this.totalInvestedAmount,
required this.totalTransactions,
required this.transactions,
required this.sips,
required this.taggedGoals});

double? getIrr() {
if (irr != null) {
return irr;
} else if (currentValue != null && currentValueUpdatedOn != null) {
return IRRCalculator().calculateIRR(
transactions: transactions,
finalValue: currentValue!,
finalDate: currentValueUpdatedOn!,
);
}
TransactionApi? transactionApi,
IRRCalculator? irrCalculator,
BasketApi? basketApi})
: _transactionApi = transactionApi ?? TransactionApi(),
_irrCalculator = irrCalculator ?? IRRCalculator(),
_basketApi = basketApi ?? BasketApi();

return null;
Future<double> getTotalInvestedAmount() async {
return _transactionApi
.getBy(investmentId: id)
.then((transactions) => transactions
.map((transactionDO) =>
Transaction.from(transactionDO: transactionDO))
.toList())
.then((transactions) => transactions
.map((transaction) => transaction.amount)
.reduce((value, element) => value + element));
}

double getFutureValueOn({required DateTime date, required bool considerFutureTransactions}) {
double? irr = getIrr();
if (currentValue != null) {
Future<double> getValueOn(DateTime date) async {
if (value != null && valueUpdatedOn != null) {
final transactions = await getTransactions();
final irr = _irrCalculator.calculateIRR(
transactions: transactions,
value: value!,
valueUpdatedOn: valueUpdatedOn!);
if (irr == null) {
return currentValue!;
} else {
return currentValue! *
pow(1 + irr, date.difference(currentValueUpdatedOn!).inDays / 365);
return value!;
}
return _irrCalculator.calculateValueOnIRR(
irr: irr, date: date, value: value!, valueUpdatedOn: valueUpdatedOn!);
} else if (irr != null) {
final transactions = await getTransactions();
return _irrCalculator.calculateTransactedValueOnIRR(
transactions: transactions, irr: irr!, date: date);
} else {
if (irr == null) {
return 0;
}
double futureValue = 0;
for (var transaction in transactions) {
//TODO consider maturity date of investment
//TODO filter transaction above the date given.
double years = date.difference(transaction.createdOn).inDays / 365;
futureValue += transaction.amount / pow(1 + irr, years);
}
for(var sip in sips) {
//Include future value of sip.
}
throw Exception('Value and IRR are null');
}
}

return futureValue;
Future<List<Transaction>> getTransactions() async {
return _transactionApi.getBy(investmentId: id).then((transactions) =>
transactions
.map((transactionDO) =>
Transaction.from(transactionDO: transactionDO))
.toList());
}

Future<Basket?> getBasket() async {
if (basketId != null) {
return _basketApi
.getBy(id: basketId!)
.then((basketDO) => Basket.from(basketDO: basketDO));
}
return null;
}

static Investment from(
{required final InvestmentEnrichedDO investment,
required final List<TransactionDO> transactions,
required final List<SipDO> sips,
required final List<GoalInvestmentEnrichedMappingDO>
goalInvestmentMappings}) {
static Investment from({required final InvestmentDO investmentDO}) {
return Investment(
id: investment.id,
name: investment.name,
description: investment.description,
riskLevel: investment.riskLevel,
maturityDate: investment.maturityDate,
currentValue: investment.currentValue,
currentValueUpdatedOn: investment.currentValueUpdatedOn,
irr: investment.irr,
basketId: investment.basketId ?? 0,
basketName: investment.basketName ?? '',
totalInvestedAmount: investment.totalInvestedAmount ?? 0,
totalTransactions: investment.totalTransactions ?? 0,
transactions: transactions
.map((transaction) => Transaction.from(transaction: transaction))
.toList(),
sips: sips.map((sip) => SIP.from(sip: sip)).toList(),
taggedGoals: goalInvestmentMappings);
id: investmentDO.id,
name: investmentDO.name,
description: investmentDO.description,
riskLevel: investmentDO.riskLevel,
irr: investmentDO.irr,
value: investmentDO.value,
valueUpdatedOn: investmentDO.valueUpdatedOn,
basketId: investmentDO.basketId,
maturityDate: investmentDO.maturityDate);
}
}
Loading

0 comments on commit 48bbe46

Please sign in to comment.