diff --git a/app/Http/Controllers/DashboardController.php b/app/Http/Controllers/DashboardController.php index 7ea7131..4c78e19 100644 --- a/app/Http/Controllers/DashboardController.php +++ b/app/Http/Controllers/DashboardController.php @@ -12,7 +12,7 @@ class DashboardController extends Controller */ public function show(Request $request) { - $user = $request->user()->load('portfolios'); + $user = $request->user()->load(['portfolios', 'holdings', 'transactions']); // get portfolio metrics $metrics = cache()->tags(['metrics', 'dashboard', $user->id])->remember( @@ -21,6 +21,7 @@ class DashboardController extends Controller function () { return Holding::query() + ->myHoldings() ->getPortfolioMetrics() ->first(); } diff --git a/app/Http/Controllers/HoldingController.php b/app/Http/Controllers/HoldingController.php index 19d39f2..ac4a96b 100644 --- a/app/Http/Controllers/HoldingController.php +++ b/app/Http/Controllers/HoldingController.php @@ -15,12 +15,11 @@ class HoldingController extends Controller public function show(Request $request, Portfolio $portfolio, String $symbol) { - $holding = $request->user() - ->holdings() - ->where([ - 'holdings.portfolio_id' => $portfolio->id, - 'holdings.symbol' => $symbol - ])->firstOrFail(); + + $holding = Holding::query() + ->portfolio($portfolio->id) + ->symbol($symbol) + ->first(); $market_data = $holding->market_data; diff --git a/app/Models/Holding.php b/app/Models/Holding.php index 5037090..355d3cc 100644 --- a/app/Models/Holding.php +++ b/app/Models/Holding.php @@ -2,7 +2,11 @@ namespace App\Models; +use App\Models\Split; use App\Models\Dividend; +use App\Models\Portfolio; +use App\Models\MarketData; +use App\Models\Transaction; use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\Concerns\HasUuids; use Illuminate\Database\Eloquent\Factories\HasFactory; @@ -53,7 +57,8 @@ class Holding extends Model */ public function transactions() { - return $this->hasMany(Transaction::class, 'symbol', 'symbol'); + return $this->hasMany(Transaction::class, 'symbol', 'symbol') + ->where('transactions.portfolio_id', $this->portfolio_id); } /** @@ -63,7 +68,44 @@ class Holding extends Model */ public function dividends() { - return $this->hasMany(Dividend::class, 'symbol', 'symbol'); + + + + return $this->hasMany(Dividend::class, 'symbol', 'symbol') + ->select([ + 'dividends.symbol', + 'dividends.date', + 'dividends.dividend_amount', + ]) + ->selectRaw("SUM( + CASE WHEN transaction_type = 'BUY' + AND transactions.symbol = dividends.symbol + AND transactions.portfolio_id = '$this->portfolio_id' + AND dividends.date >= transactions.date + THEN transactions.quantity + ELSE 0 END + ) AS purchased") + ->selectRaw("SUM( + CASE WHEN transaction_type = 'SELL' + AND transactions.symbol = dividends.symbol + AND transactions.portfolio_id = '$this->portfolio_id' + AND dividends.date >= transactions.date + THEN transactions.quantity + ELSE 0 END + ) AS sold") + ->join('transactions', 'transactions.symbol', 'dividends.symbol') + ->groupBy([ + 'dividends.symbol', + 'dividends.date', + 'dividends.dividend_amount', + ]) + ->orderBy('dividends.date', 'DESC') + ->where('dividends.date', '>=', function ($query) { + $query->selectRaw('min(transactions.date)') + ->from('transactions') + ->whereRaw("transactions.portfolio_id = '$this->portfolio_id'") + ->whereRaw("transactions.symbol = '$this->symbol'"); + }); } /** @@ -83,7 +125,8 @@ class Holding extends Model */ public function splits() { - return $this->hasMany(Split::class, 'symbol', 'symbol'); + return $this->hasMany(Split::class, 'symbol', 'symbol') + ->orderBy('date', 'DESC'); } public function scopePortfolio($query, $portfolio) @@ -91,6 +134,11 @@ class Holding extends Model return $query->where('portfolio_id', $portfolio); } + public function scopeSymbol($query, $symbol) + { + return $query->where('symbol', $symbol); + } + public function scopeWithoutWishlists($query) { return $query->join('portfolios', 'portfolios.id', 'holdings.portfolio_id') ->where('portfolios.wishlist', 0); @@ -115,11 +163,6 @@ class Holding extends Model ->join('market_data', 'market_data.symbol', 'holdings.symbol'); } - public function scopeSymbol($query, $symbol) - { - return $query->where('symbol', $symbol); - } - // public function refreshDividends() // { // return Dividend::getDividendData($this->attributes['symbol']); diff --git a/app/Models/MarketData.php b/app/Models/MarketData.php index bd9dff2..4eb6fa1 100644 --- a/app/Models/MarketData.php +++ b/app/Models/MarketData.php @@ -25,6 +25,15 @@ class MarketData extends Model 'market_cap' ]; + protected $attributes = [ + 'market_value' => 0, + 'fifty_two_week_high' => 0, + 'fifty_two_week_low' => 0, + 'forward_pe' => 0, + 'trailing_pe' => 0, + 'market_cap' => 0 + ]; + public static function setSplitsHoldingSynced($symbol) { $market_data = self::where('symbol', $symbol)->get()->first(); diff --git a/app/Models/Transaction.php b/app/Models/Transaction.php index 0295981..7271893 100644 --- a/app/Models/Transaction.php +++ b/app/Models/Transaction.php @@ -126,14 +126,14 @@ class Transaction extends Model */ public function ensureCostBasisIsAddedToSale() { - $holding = Holding::firstOrNew([ + $average_cost_basis = Transaction::where([ 'portfolio_id' => $this->portfolio_id, - 'symbol' => $this->symbol - ],[ - 'average_cost_basis' => null - ]); + 'symbol' => $this->symbol, + 'transaction_type' => 'BUY', + ])->whereDate('date', '<=', $this->date) + ->average('cost_basis'); - $this->cost_basis = $holding->average_cost_basis ?? 0; + $this->cost_basis = $average_cost_basis ?? 0; return $this; } diff --git a/app/Models/User.php b/app/Models/User.php index d4462d9..1f0614d 100644 --- a/app/Models/User.php +++ b/app/Models/User.php @@ -77,15 +77,12 @@ class User extends Authenticatable ->withAggregate('market_data', 'fifty_two_week_low') ->withAggregate('market_data', 'fifty_two_week_high') ->withAggregate('market_data', 'updated_at') - ->selectRaw('COALESCE(transactions.cost_basis * transactions.quantity, 0) AS total_cost_basis') - ->selectRaw('COALESCE(market_data.market_value * transactions.quantity, 0) AS total_market_value') - ->selectRaw('COALESCE((market_data.market_value - transactions.cost_basis) * transactions.quantity, 0) AS market_gain_dollars') - ->selectRaw('COALESCE(((market_data.market_value - transactions.cost_basis) / transactions.cost_basis), 0) AS market_gain_percent') + ->selectRaw(' + CASE + WHEN transaction_type = \'SELL\' + THEN COALESCE(transactions.sale_price - transactions.cost_basis, 0) + ELSE COALESCE(market_data.market_value - transactions.cost_basis, 0) + END AS gain_dollars') ->join('market_data', 'transactions.symbol', 'market_data.symbol');; } - - public function daily_change(): HasManyDeep - { - return $this->hasManyDeep(DailyChange::class, ['portfolio_user', Portfolio::class]); - } } diff --git a/resources/views/components/partials/side-bar.blade.php b/resources/views/components/partials/side-bar.blade.php index 51fe43f..9d8b6ca 100644 --- a/resources/views/components/partials/side-bar.blade.php +++ b/resources/views/components/partials/side-bar.blade.php @@ -40,7 +40,7 @@ - +