diff --git a/app/Models/DailyChange.php b/app/Models/DailyChange.php index ac200af..10a7fbb 100644 --- a/app/Models/DailyChange.php +++ b/app/Models/DailyChange.php @@ -120,12 +120,18 @@ class DailyChange extends Model ) END) AS rate") ->selectRaw( - "CASE + "COALESCE(SUM(CASE WHEN tx1.transaction_type = 'BUY' - THEN tx1.quantity - ELSE -tx1.quantity - END - AS remaining_quantity" + THEN tx1.cost_basis_base * tx1.quantity + END), 0) + AS total_cost_basis_for_purchases" + ) + ->selectRaw( + "COALESCE(SUM(CASE + WHEN tx1.transaction_type = 'SELL' + THEN tx1.cost_basis_base * tx1.quantity + END), 0) + AS total_cost_basis_for_sales" ) ->selectRaw( "(CASE @@ -156,38 +162,14 @@ class DailyChange extends Model $join->on('cr.date', '=', 'daily_change.date') ->where('cr.currency', '=', $currency); }) - ->selectRaw(" - (SUM( - CASE - WHEN cost_basis_display.transaction_type = 'BUY' - THEN cost_basis_display.cost_basis_base * cost_basis_display.quantity * cost_basis_display.rate - END - ) - / SUM( - CASE - WHEN cost_basis_display.transaction_type = 'BUY' - THEN cost_basis_display.quantity - END - )) - * SUM(cost_basis_display.remaining_quantity) + ->selectRaw(' + SUM(cost_basis_display.rate * cost_basis_display.total_cost_basis_for_purchases) - SUM(cost_basis_display.rate * cost_basis_display.total_cost_basis_for_sales) AS total_cost_basis - ") - ->selectRaw("( + ') + ->selectRaw('( daily_change.total_market_value * COALESCE(cr.rate, 1) - ) - (SUM( - CASE - WHEN cost_basis_display.transaction_type = 'BUY' - THEN cost_basis_display.cost_basis_base * cost_basis_display.quantity * cost_basis_display.rate - END - ) - / SUM( - CASE - WHEN cost_basis_display.transaction_type = 'BUY' - THEN cost_basis_display.quantity - END - )) - * SUM(cost_basis_display.remaining_quantity) - as total_gain") + ) - (SUM(cost_basis_display.rate * cost_basis_display.total_cost_basis_for_purchases) - SUM(cost_basis_display.rate * cost_basis_display.total_cost_basis_for_sales)) + as total_gain') ->selectRaw('( daily_change.total_market_value * COALESCE(cr.rate, 1) ) as total_market_value') diff --git a/tests/MultiCurrencyTest.php b/tests/MultiCurrencyTest.php index 2d7077e..17f7385 100644 --- a/tests/MultiCurrencyTest.php +++ b/tests/MultiCurrencyTest.php @@ -544,17 +544,22 @@ class MultiCurrencyTest extends TestCase $this->actingAs($user = User::factory()->create()); + $monthAgo = now()->subMonth()->toDateString(); + $fiveWeeksAgo = now()->subWeeks(5)->toDateString(); + $fiveDaysAgo = now()->subDays(5)->toDateString(); + $portfolio = Portfolio::factory()->create(); - Transaction::factory(5)->buy()->lastMonth()->portfolio($portfolio->id)->symbol('AAPL')->create(); - Transaction::factory(5)->buy()->lastMonth()->portfolio($portfolio->id)->symbol('ACME')->create(); - Transaction::factory()->sell()->recent()->portfolio($portfolio->id)->symbol('ACME')->create(); + Transaction::factory(5)->buy()->costBasis(100)->date($monthAgo)->portfolio($portfolio->id)->symbol('AAPL')->create(); + Transaction::factory(5)->buy()->costBasis(190)->date($fiveWeeksAgo)->portfolio($portfolio->id)->symbol('ACME')->create(); + Transaction::factory()->sell()->date($fiveDaysAgo)->portfolio($portfolio->id)->symbol('ACME')->create(); $portfolio->syncDailyChanges(); $dailyChange = DailyChange::withDailyPerformance() ->portfolio($portfolio->id) - ->get() - ->sortBy('date') + ->get(); + + $dailyChange = $dailyChange->sortBy('date') ->groupBy('date') ->map(function ($group) { return (object) [ @@ -572,18 +577,39 @@ class MultiCurrencyTest extends TestCase ->getPortfolioMetrics(); $this->assertEqualsWithDelta($metrics->get('total_market_value'), $dailyChange->last()->total_market_value, 0.01); - // expected 2773.034 Failed asserting that 2816.46 matches . - - // "total_cost_basis" => 1771.476 - // "total_gain_dollars" => 300.234 - - // +"total_cost_basis": 1765.431 - // +"total_gain": 306.279 - $this->assertEqualsWithDelta($metrics->get('total_cost_basis'), $dailyChange->last()->total_cost_basis, 0.01); + $this->assertEqualsWithDelta(Holding::get()->sum('total_cost_basis'), $dailyChange->last()->total_cost_basis, 0.01); $this->assertEqualsWithDelta($metrics->get('realized_gain_dollars'), $dailyChange->last()->realized_gain_dollars, 0.01); $this->assertEqualsWithDelta($metrics->get('total_market_value') - $metrics->get('total_cost_basis'), $dailyChange->last()->total_gain, 0.01); + // add currency rates + $rates = collect([[ + 'currency' => 'GBP', + 'rate' => .88, + 'date' => $fiveWeeksAgo, + ], [ + 'currency' => 'GBP', + 'rate' => .88, + 'date' => $fiveDaysAgo, + ], [ + 'currency' => 'GBP', + 'rate' => .88, + 'date' => $monthAgo, + ], [ + 'currency' => 'GBP', + 'rate' => .88, + 'date' => now()->subDay()->toDateString(), + ], [ + 'currency' => 'GBP', + 'rate' => .88, + 'date' => now()->toDateString(), + ], [ + 'currency' => 'GBP', + 'rate' => .88, + 'date' => now()->addDay()->toDateString(), + ]]); + $rates->each(fn ($rate) => CurrencyRate::create($rate)); + // switch user display currency $user->options = array_merge($user->options ?? [], [ 'display_currency' => 'GBP', @@ -592,10 +618,14 @@ class MultiCurrencyTest extends TestCase $dailyChange = DailyChange::withDailyPerformance() ->portfolio($portfolio->id) - ->get() - ->sortBy('date') + ->get(); + + dump($dailyChange->toArray()); + + $dailyChange = $dailyChange->sortBy('date') ->groupBy('date') ->map(function ($group) { + return (object) [ 'date' => $group->first()->date->toDateString(), 'total_market_value' => $group->sum('total_market_value'), @@ -610,10 +640,10 @@ class MultiCurrencyTest extends TestCase ->portfolio($portfolio->id) ->getPortfolioMetrics(); - $this->assertEqualsWithDelta($metrics->get('total_market_value'), $dailyChange->last()->total_market_value, 0.01); + $this->assertEqualsWithDelta($metrics->get('total_market_value'), $dailyChange->last()->total_market_value, 0.01); // TODO: $this->assertEqualsWithDelta($metrics->get('total_cost_basis'), $dailyChange->last()->total_cost_basis, 0.01); $this->assertEqualsWithDelta($metrics->get('realized_gain_dollars'), $dailyChange->last()->realized_gain_dollars, 0.01); - $this->assertEqualsWithDelta($metrics->get('total_market_value') - $metrics->get('total_cost_basis'), $dailyChange->last()->total_gain, 0.01); + $this->assertEqualsWithDelta($metrics->get('total_market_value') - $metrics->get('total_cost_basis'), $dailyChange->last()->total_gain, 0.01); // TODO: } public function test_multi_currency_import_calculates_correct_holding_data(): void