From 48bbe466f4a18259edde753c2669c7aaa6e7fc35 Mon Sep 17 00:00:00 2001 From: Prasanna Anbazhagan Date: Tue, 16 Jan 2024 08:02:28 +0530 Subject: [PATCH] save commit --- lib/api/apis/basket_api.dart | 5 + lib/api/apis/investment_api.dart | 15 ++ lib/api/apis/transaction_api.dart | 2 +- lib/domain/models/basket.dart | 39 ++--- lib/domain/models/goal.dart | 95 ++---------- lib/domain/models/investment.dart | 145 +++++++++--------- lib/domain/{ => models}/irr_calculator.dart | 32 +++- lib/domain/models/sip.dart | 13 +- lib/domain/models/transaction.dart | 10 +- lib/domain/services/basket_service.dart | 39 +++++ lib/domain/services/goal_service.dart | 60 ++++++++ lib/domain/services/investment_service.dart | 65 ++++++++ .../usecases/fetch_baskets_use_case.dart | 30 ---- lib/domain/usecases/fetch_goals_use_case.dart | 57 ------- .../usecases/fetch_investments_use_case.dart | 35 ----- .../perform_sip_transactions_use_case.dart | 41 ----- lib/presentation/baskets_presenter.dart | 20 +-- lib/presentation/goals_presenter.dart | 2 +- lib/presentation/investments_presenter.dart | 2 +- test/domain/irr_calculator_test.dart | 6 +- 20 files changed, 337 insertions(+), 376 deletions(-) rename lib/domain/{ => models}/irr_calculator.dart (58%) create mode 100644 lib/domain/services/basket_service.dart create mode 100644 lib/domain/services/goal_service.dart create mode 100644 lib/domain/services/investment_service.dart delete mode 100644 lib/domain/usecases/fetch_baskets_use_case.dart delete mode 100644 lib/domain/usecases/fetch_goals_use_case.dart delete mode 100644 lib/domain/usecases/fetch_investments_use_case.dart delete mode 100644 lib/domain/usecases/perform_sip_transactions_use_case.dart diff --git a/lib/api/apis/basket_api.dart b/lib/api/apis/basket_api.dart index 03b02e1..ecf3a0f 100644 --- a/lib/api/apis/basket_api.dart +++ b/lib/api/apis/basket_api.dart @@ -18,6 +18,11 @@ class BasketApi { .get(); } + Future getBy({required final int id}) async { + return (_db.select(_db.basketTable)..where((t) => t.id.equals(id))) + .getSingle(); + } + Future update( {required final int id, required final String name, diff --git a/lib/api/apis/investment_api.dart b/lib/api/apis/investment_api.dart index f393363..1ecc27a 100644 --- a/lib/api/apis/investment_api.dart +++ b/lib/api/apis/investment_api.dart @@ -40,6 +40,21 @@ class InvestmentApi { .get(); } + Future getById({required final int id}) async { + return (_db.select(_db.investmentTable)..where((t) => t.id.equals(id))) + .getSingle(); + } + + Future> 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 update({ required final int id, required final String name, diff --git a/lib/api/apis/transaction_api.dart b/lib/api/apis/transaction_api.dart index f385aa1..fa3f5fd 100644 --- a/lib/api/apis/transaction_api.dart +++ b/lib/api/apis/transaction_api.dart @@ -21,7 +21,7 @@ class TransactionApi { createdOn: createdOn)); } - Future> get({final int? investmentId}) async { + Future> getBy({final int? investmentId}) async { if (investmentId == null) { return (_db.select(_db.transactionTable) ..orderBy([(t) => OrderingTerm.desc(t.createdOn)])) diff --git a/lib/domain/models/basket.dart b/lib/domain/models/basket.dart index 8d7715f..7ff7ee4 100644 --- a/lib/domain/models/basket.dart +++ b/lib/domain/models/basket.dart @@ -1,3 +1,4 @@ +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'; @@ -5,33 +6,35 @@ 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 investments}) { - return Basket( - id: basket.id, - name: basket.name, - description: basket.description, - investments: investments); + Future getTotalInvestments() { + return _investmentApi.getBy(basketId: id).then((value) => value.length); } - double get totalValue { - return investments.fold(0, (previousValue, investment) { - return previousValue + investment.totalInvestedAmount; - }); + Future 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); } } diff --git a/lib/domain/models/goal.dart b/lib/domain/models/goal.dart index a2076fb..3a09a9c 100644 --- a/lib/domain/models/goal.dart +++ b/lib/domain/models/goal.dart @@ -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 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 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); } diff --git a/lib/domain/models/investment.dart b/lib/domain/models/investment.dart index 8e78782..1c671b9 100644 --- a/lib/domain/models/investment.dart +++ b/lib/domain/models/investment.dart @@ -1,9 +1,9 @@ -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 { @@ -11,17 +11,15 @@ class Investment { 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 transactions; - final List sips; - final List taggedGoals; + + final TransactionApi _transactionApi; + final IRRCalculator _irrCalculator; + final BasketApi _basketApi; Investment( {required this.id, @@ -29,82 +27,77 @@ class Investment { 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 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 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> getTransactions() async { + return _transactionApi.getBy(investmentId: id).then((transactions) => + transactions + .map((transactionDO) => + Transaction.from(transactionDO: transactionDO)) + .toList()); + } + + Future 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 transactions, - required final List sips, - required final List - 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); } } diff --git a/lib/domain/irr_calculator.dart b/lib/domain/models/irr_calculator.dart similarity index 58% rename from lib/domain/irr_calculator.dart rename to lib/domain/models/irr_calculator.dart index 2779002..4afe961 100644 --- a/lib/domain/irr_calculator.dart +++ b/lib/domain/models/irr_calculator.dart @@ -5,8 +5,8 @@ import 'package:wealth_wave/domain/models/transaction.dart'; class IRRCalculator { double? calculateIRR( {required final List transactions, - required final double finalValue, - required final DateTime finalDate}) { + required final double value, + required final DateTime valueUpdatedOn}) { if (transactions.isEmpty) return null; transactions.sort((a, b) => a.createdOn.compareTo(b.createdOn)); @@ -18,8 +18,8 @@ class IRRCalculator { .toList(); cashFlows.add(_CashFlow( - amount: finalValue, - years: finalDate.difference(initialDate).inDays / 365)); + amount: value, + years: valueUpdatedOn.difference(initialDate).inDays / 365)); double guess = 0.1; // Initial guess for IRR for (int i = 0; i < 100; i++) { @@ -35,6 +35,30 @@ class IRRCalculator { } return null; } + + double calculateTransactedValueOnIRR( + {required final List transactions, + required final double irr, + required final DateTime date}) { + double futureValue = 0; + + for (var transaction in transactions) { + double years = date.difference(transaction.createdOn).inDays / 365; + futureValue += transaction.amount / pow(1 + irr, years); + } + + return futureValue; + } + + double calculateValueOnIRR({ + required final double irr, + required final DateTime date, + required final double value, + required final DateTime valueUpdatedOn, + }) { + double years = date.difference(valueUpdatedOn).inDays / 365; + return value / pow(1 + irr, years); + } } class _CashFlow { diff --git a/lib/domain/models/sip.dart b/lib/domain/models/sip.dart index da4f313..b413ea8 100644 --- a/lib/domain/models/sip.dart +++ b/lib/domain/models/sip.dart @@ -1,4 +1,4 @@ -import 'package:wealth_wave/api/db/app_database.dart'; + class SIP { final int id; @@ -17,15 +17,4 @@ class SIP { required this.endDate, required this.frequency, required this.executedTill}); - - static SIP from({required final SipDO sip}) { - return SIP( - id: sip.id, - description: sip.description, - amount: sip.amount, - startDate: sip.startDate, - endDate: sip.endDate, - frequency: sip.frequency, - executedTill: sip.executedTill); - } } diff --git a/lib/domain/models/transaction.dart b/lib/domain/models/transaction.dart index 8667378..56655ef 100644 --- a/lib/domain/models/transaction.dart +++ b/lib/domain/models/transaction.dart @@ -12,11 +12,11 @@ class Transaction { required this.amount, required this.createdOn}); - static Transaction from({required final TransactionDO transaction}) { + static Transaction from({required final TransactionDO transactionDO}) { return Transaction( - id: transaction.id, - description: transaction.description, - amount: transaction.amount, - createdOn: transaction.amountInvestedOn); + id: transactionDO.id, + description: transactionDO.description, + amount: transactionDO.amount, + createdOn: transactionDO.createdOn); } } diff --git a/lib/domain/services/basket_service.dart b/lib/domain/services/basket_service.dart new file mode 100644 index 0000000..8a00aba --- /dev/null +++ b/lib/domain/services/basket_service.dart @@ -0,0 +1,39 @@ +import 'package:wealth_wave/api/apis/basket_api.dart'; +import 'package:wealth_wave/domain/models/basket.dart'; + +class BasketService { + final BasketApi _basketApi; + + BasketService({BasketApi? basketApi}) : _basketApi = basketApi ?? BasketApi(); + + Future create( + {required final String name, required final String description}) { + return _basketApi + .create(name: name, description: description) + .then((basketId) => _basketApi.getBy(id: basketId)) + .then((basketDO) => Basket.from(basketDO: basketDO)); + } + + Future> get() async { + return _basketApi.get().then((baskets) => + baskets.map((basketDO) => Basket.from(basketDO: basketDO)).toList()); + } + + Future getBy({required final int id}) async { + return _basketApi.getBy(id: id).then((basketDO) { + return Basket.from(basketDO: basketDO); + }); + } + + Future update(Basket basket) { + return _basketApi + .update( + id: basket.id, name: basket.name, description: basket.description) + .then((value) => _basketApi.getBy(id: basket.id)) + .then((basketDO) => Basket.from(basketDO: basketDO)); + } + + Future deleteBy({required final int id}) { + return _basketApi.deleteBy(id: id); + } +} diff --git a/lib/domain/services/goal_service.dart b/lib/domain/services/goal_service.dart new file mode 100644 index 0000000..ae530d5 --- /dev/null +++ b/lib/domain/services/goal_service.dart @@ -0,0 +1,60 @@ +import 'package:wealth_wave/api/apis/goal_api.dart'; +import 'package:wealth_wave/contract/goal_importance.dart'; +import 'package:wealth_wave/domain/models/goal.dart'; + +class GoalService { + final GoalApi _goalApi; + + GoalService({GoalApi? goalApi}) : _goalApi = goalApi ?? GoalApi(); + + Future create({ + required final String name, + required final String description, + required final double amount, + required final DateTime maturityDate, + required final double inflation, + required final GoalImportance importance, + }) { + return _goalApi + .create( + name: name, + description: description, + amount: amount, + amountUpdatedOn: DateTime.now(), + maturityDate: maturityDate, + inflation: inflation, + importance: importance) + .then((goalId) => _goalApi.getBy(id: goalId)) + .then((goalDO) => Goal.from(goalDO: goalDO)); + } + + Future> get() async { + return _goalApi.get().then( + (goals) => goals.map((goalDO) => Goal.from(goalDO: goalDO)).toList()); + } + + Future getBy({required final int id}) async { + return _goalApi.getBy(id: id).then((goalDO) { + return Goal.from(goalDO: goalDO); + }); + } + + Future update(Goal goal) { + return _goalApi + .update( + id: goal.id, + name: goal.name, + description: goal.description, + amount: goal.amount, + amountUpdatedOn: goal.amountUpdatedOn, + maturityDate: goal.maturityDate, + inflation: goal.inflation, + importance: goal.importance) + .then((value) => _goalApi.getBy(id: goal.id)) + .then((goalDO) => Goal.from(goalDO: goalDO)); + } + + Future deleteBy({required final int id}) { + return _goalApi.deleteBy(id: id); + } +} diff --git a/lib/domain/services/investment_service.dart b/lib/domain/services/investment_service.dart new file mode 100644 index 0000000..68eb8d8 --- /dev/null +++ b/lib/domain/services/investment_service.dart @@ -0,0 +1,65 @@ +import 'package:wealth_wave/api/apis/investment_api.dart'; +import 'package:wealth_wave/contract/risk_level.dart'; +import 'package:wealth_wave/domain/models/investment.dart'; + +class InvestmentService { + final InvestmentApi _investmentApi; + + InvestmentService({final InvestmentApi? investmentApi}) + : _investmentApi = investmentApi ?? InvestmentApi(); + + Future create( + {required final String name, + required final String description, + required final int basketId, + required final RiskLevel riskLevel, + required final double? value, + required final DateTime? valueUpdatedOn, + required final double? irr, + required final DateTime? maturityDate}) { + return _investmentApi + .create( + name: name, + description: description, + basketId: basketId, + riskLevel: riskLevel, + value: value, + maturityDate: maturityDate, + irr: irr, + valueUpdatedOn: valueUpdatedOn) + .then((investmentId) => _investmentApi.getBy(id: investmentId)) + .then((investmentDO) => Investment.from(investmentDO: investmentDO)); + } + + Future> get() async { + return _investmentApi.get().then((investments) => investments + .map((investmentDO) => Investment.from(investmentDO: investmentDO)) + .toList()); + } + + Future getBy({required final int id}) async { + return _investmentApi.getBy(id: id).then((investmentDO) { + return Investment.from(investmentDO: investmentDO); + }); + } + + Future update(Investment investment) { + return _investmentApi + .update( + id: investment.id, + name: investment.name, + description: investment.description, + value: investment.value, + valueUpdatedOn: investment.valueUpdatedOn, + irr: investment.irr, + maturityDate: investment.maturityDate, + riskLevel: investment.riskLevel, + basketId: investment.basketId) + .then((value) => _investmentApi.getBy(id: investment.id)) + .then((investmentDO) => Investment.from(investmentDO: investmentDO)); + } + + Future deleteBy({required final int id}) { + return _investmentApi.deleteBy(id: id); + } +} diff --git a/lib/domain/usecases/fetch_baskets_use_case.dart b/lib/domain/usecases/fetch_baskets_use_case.dart deleted file mode 100644 index d9d253d..0000000 --- a/lib/domain/usecases/fetch_baskets_use_case.dart +++ /dev/null @@ -1,30 +0,0 @@ -import 'package:wealth_wave/api/apis/basket_api.dart'; -import 'package:wealth_wave/api/db/app_database.dart'; -import 'package:wealth_wave/domain/models/basket.dart'; -import 'package:wealth_wave/domain/models/investment.dart'; -import 'package:wealth_wave/domain/usecases/fetch_investments_use_case.dart'; - -class FetchBasketsUseCase { - final BasketApi _basketApi; - final FetchInvestmentsUseCase _fetchInvestmentsUseCase; - - FetchBasketsUseCase( - {BasketApi? basketApi, FetchInvestmentsUseCase? fetchInvestmentsUseCase}) - : _basketApi = basketApi ?? BasketApi(), - _fetchInvestmentsUseCase = - fetchInvestmentsUseCase ?? FetchInvestmentsUseCase(); - - Future> invoke() async { - List baskets = await _basketApi.get(); - List investments = - await _fetchInvestmentsUseCase.fetchInvestments(); - - return baskets.map((basket) { - List investmentsOfBasket = investments - .where((investment) => investment.basketId == basket.id) - .toList(); - - return Basket.from(basket: basket, investments: investmentsOfBasket); - }).toList(); - } -} diff --git a/lib/domain/usecases/fetch_goals_use_case.dart b/lib/domain/usecases/fetch_goals_use_case.dart deleted file mode 100644 index cbccf4e..0000000 --- a/lib/domain/usecases/fetch_goals_use_case.dart +++ /dev/null @@ -1,57 +0,0 @@ -import 'package:wealth_wave/api/apis/goal_api.dart'; -import 'package:wealth_wave/api/db/app_database.dart'; -import 'package:wealth_wave/domain/models/goal.dart'; -import 'package:wealth_wave/domain/models/investment.dart'; -import 'package:wealth_wave/domain/usecases/fetch_investments_use_case.dart'; - -class FetchGoalsUseCase { - final GoalApi _goalApi; - final FetchInvestmentsUseCase _fetchInvestmentsUseCase; - - FetchGoalsUseCase( - {GoalApi? goalApi, FetchInvestmentsUseCase? fetchInvestmentsUseCase}) - : _goalApi = goalApi ?? GoalApi(), - _fetchInvestmentsUseCase = - fetchInvestmentsUseCase ?? FetchInvestmentsUseCase(); - - Future> invoke() async { - List goals = await _goalApi.get(); - List investments = - await _fetchInvestmentsUseCase.fetchInvestments(); - List goalInvestmentMappings = - await _goalApi.getGoalInvestmentMappings(); - - return goals.map((goal) { - List goalInvestmentOfGoal = - goalInvestmentMappings - .where((goalInvestment) => goalInvestment.goalId == goal.id) - .toList(); - - Map investmentsOfGoal = {}; - for (var goalInvestment in goalInvestmentOfGoal) { - Investment investment = investments.firstWhere( - (investment) => investment.id == goalInvestment.investmentId); - investmentsOfGoal[investment] = goalInvestment.sharePercentage; - } - - return Goal.from(goal: goal, taggedInvestments: investmentsOfGoal); - }).toList(); - } - - Future getGoal(final int id) async { - GoalDO goal = await _goalApi.getGoal(id: id); - List investments = - await _fetchInvestmentsUseCase.fetchInvestments(); - List goalInvestmentMapping = - await _goalApi.getGoalInvestmentMappings(goalId: id); - - Map investmentsOfGoal = {}; - for (var goalInvestment in goalInvestmentMapping) { - Investment investment = investments.firstWhere( - (investment) => investment.id == goalInvestment.investmentId); - investmentsOfGoal[investment] = goalInvestment.sharePercentage; - } - - return Goal.from(goal: goal, taggedInvestments: investmentsOfGoal); - } -} diff --git a/lib/domain/usecases/fetch_investments_use_case.dart b/lib/domain/usecases/fetch_investments_use_case.dart deleted file mode 100644 index 53606e1..0000000 --- a/lib/domain/usecases/fetch_investments_use_case.dart +++ /dev/null @@ -1,35 +0,0 @@ -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 FetchInvestmentsUseCase { - final InvestmentApi _investmentApi; - - FetchInvestmentsUseCase({InvestmentApi? investmentApi}) - : _investmentApi = investmentApi ?? InvestmentApi(); - - Future> fetchInvestments() async { - List investments = - await _investmentApi.getEnrichedInvestments(); - List transactions = await _investmentApi.getTransactions(); - List sips = await _investmentApi.getSips(); - List goalInvestmentMappings = - await _investmentApi.getGoalInvestmentMappings(); - - return investments - .map((investment) => Investment.from( - investment: investment, - sips: sips - .where((sip) => sip.investmentId == investment.id) - .toList(), - transactions: transactions - .where( - (transaction) => transaction.investmentId == investment.id) - .toList(), - goalInvestmentMappings: goalInvestmentMappings - .where((goalInvestmentMapping) => - goalInvestmentMapping.investmentId == investment.id) - .toList())) - .toList(); - } -} diff --git a/lib/domain/usecases/perform_sip_transactions_use_case.dart b/lib/domain/usecases/perform_sip_transactions_use_case.dart deleted file mode 100644 index 505e760..0000000 --- a/lib/domain/usecases/perform_sip_transactions_use_case.dart +++ /dev/null @@ -1,41 +0,0 @@ -import 'package:wealth_wave/api/apis/investment_api.dart'; - -class PerformSipTransactionsUseCase { - final InvestmentApi _investmentApi; - - PerformSipTransactionsUseCase({final InvestmentApi? investmentApi}) - : _investmentApi = investmentApi ?? InvestmentApi(); - - Future performSipTransactions() async { - return _investmentApi.getSips().then((sips) { - for (var sip in sips) { - if (sip.startDate.isBefore(DateTime.now())) { - var diff = sip.startDate.difference(DateTime.now()).inDays; - var frequency = sip.frequency; - if (diff > frequency) { - for (DateTime i = sip.startDate; - i.isBefore(DateTime.now()); - i.add(Duration(days: frequency.toInt()))) { - _investmentApi - .createTransaction( - investmentId: sip.investmentId, - description: 'SIP', - amount: sip.amount, - date: sip.startDate) - .await; - } - } - - _investmentApi - .createTransaction( - investmentId: sip.investmentId, - amount: sip.amount, - date: sip.startDate) - .then((_) => _investmentApi.updateSip( - id: sip.id, - startDate: sip.startDate.add(Duration(days: 30)))); - } - } - }); - } -} diff --git a/lib/presentation/baskets_presenter.dart b/lib/presentation/baskets_presenter.dart index 7745f8b..ebf3bec 100644 --- a/lib/presentation/baskets_presenter.dart +++ b/lib/presentation/baskets_presenter.dart @@ -1,25 +1,19 @@ import 'package:wealth_wave/api/apis/basket_api.dart'; import 'package:wealth_wave/core/presenter.dart'; import 'package:wealth_wave/domain/models/basket.dart'; -import 'package:wealth_wave/domain/usecases/fetch_baskets_use_case.dart'; +import 'package:wealth_wave/domain/services/basket_service.dart'; class BasketsPresenter extends Presenter { - final FetchBasketsUseCase _fetchBasketsUseCase; - final BasketApi _basketApi; + final BasketService _basketService; - BasketsPresenter( - {final FetchBasketsUseCase? fetchBasketsUseCase, - final BasketApi? basketApi}) - : _fetchBasketsUseCase = fetchBasketsUseCase ?? FetchBasketsUseCase(), - _basketApi = basketApi ?? BasketApi(), + BasketsPresenter({final BasketService? basketService}) + : _basketService = basketService ?? BasketService(), super(BasketsViewState()); void fetchBaskets() { - _fetchBasketsUseCase - .invoke() - .then((baskets) => updateViewState((viewState) { - viewState.baskets = baskets; - })); + _basketService.get().then((baskets) => updateViewState((viewState) { + viewState.baskets = baskets; + })); } void deleteBasket({required final int id}) { diff --git a/lib/presentation/goals_presenter.dart b/lib/presentation/goals_presenter.dart index 5f334d7..ae0ec1b 100644 --- a/lib/presentation/goals_presenter.dart +++ b/lib/presentation/goals_presenter.dart @@ -1,7 +1,7 @@ import 'package:wealth_wave/api/apis/goal_api.dart'; import 'package:wealth_wave/core/presenter.dart'; import 'package:wealth_wave/domain/models/goal.dart'; -import 'package:wealth_wave/domain/usecases/fetch_goals_use_case.dart'; +import 'package:wealth_wave/domain/services/goal_service.dart'; class GoalsPresenter extends Presenter { final GoalApi _goalApi; diff --git a/lib/presentation/investments_presenter.dart b/lib/presentation/investments_presenter.dart index 31f087f..9b50bad 100644 --- a/lib/presentation/investments_presenter.dart +++ b/lib/presentation/investments_presenter.dart @@ -1,7 +1,7 @@ import 'package:wealth_wave/api/apis/investment_api.dart'; import 'package:wealth_wave/core/presenter.dart'; import 'package:wealth_wave/domain/models/investment.dart'; -import 'package:wealth_wave/domain/usecases/fetch_investments_use_case.dart'; +import 'package:wealth_wave/domain/services/investment_service.dart'; class InvestmentsPresenter extends Presenter { final InvestmentApi _investmentApi; diff --git a/test/domain/irr_calculator_test.dart b/test/domain/irr_calculator_test.dart index 2999811..74d98c3 100644 --- a/test/domain/irr_calculator_test.dart +++ b/test/domain/irr_calculator_test.dart @@ -1,5 +1,5 @@ import 'package:test/test.dart'; -import 'package:wealth_wave/domain/irr_calculator.dart'; +import 'package:wealth_wave/domain/models/irr_calculator.dart'; import 'package:wealth_wave/domain/models/transaction.dart'; void main() { @@ -28,8 +28,8 @@ void main() { final irr = calculator.calculateIRR( transactions: transactions, - finalValue: finalValue, - finalDate: finalDate); + value: finalValue, + valueUpdatedOn: finalDate); expect(irr, closeTo(0.2, 0.02)); // Expected IRR is 20%, tolerance is 1% });