Files

169 lines
6.6 KiB
PHP
Raw Permalink Normal View History

2024-08-10 13:30:19 -05:00
<?php
2025-01-28 17:33:54 -06:00
declare(strict_types=1);
2024-08-10 13:30:19 -05:00
namespace App\Models;
use App\Traits\HasCompositePrimaryKey;
use Illuminate\Database\Eloquent\Factories\HasFactory;
2025-01-28 17:14:49 -06:00
use Illuminate\Database\Eloquent\Model;
2025-04-09 19:25:15 -05:00
use Illuminate\Support\Facades\DB;
2024-08-10 13:30:19 -05:00
class DailyChange extends Model
{
2025-01-28 17:14:49 -06:00
use HasCompositePrimaryKey, HasFactory;
2024-08-10 13:30:19 -05:00
public $timestamps = false;
protected $primaryKey = ['date', 'portfolio_id'];
protected $table = 'daily_change';
protected $fillable = [
'portfolio_id',
'date',
'total_market_value',
'notes',
];
protected $hidden = [];
protected $casts = [
'date' => 'datetime',
2025-04-09 19:25:15 -05:00
'total_market_value' => 'float',
'total_cost_basis' => 'float',
2025-08-21 20:54:14 -05:00
'total_market_gain' => 'float',
2025-04-09 19:25:15 -05:00
'realized_gain_dollars' => 'float',
'total_dividends_earned' => 'float',
2024-08-10 13:30:19 -05:00
];
2025-01-28 17:14:49 -06:00
2024-08-21 20:42:32 -05:00
public function scopePortfolio($query, $portfolio)
{
2025-04-09 19:25:15 -05:00
return $query->where('daily_change.portfolio_id', $portfolio);
2024-08-21 20:42:32 -05:00
}
2024-08-28 22:06:47 -05:00
2025-08-21 21:46:53 -05:00
public function scopeMyDailyChanges($query)
2024-08-28 22:06:47 -05:00
{
2025-08-21 21:46:53 -05:00
return $query->whereHas('portfolio', function ($query) {
2024-08-28 22:06:47 -05:00
$query->whereHas('users', function ($query) {
2024-09-25 20:59:09 -05:00
return $query->where('id', auth()->id());
2024-08-28 22:06:47 -05:00
});
});
}
2025-01-28 17:14:49 -06:00
public function scopeWithoutWishlists($query)
{
return $query->whereHas('portfolio', function ($query) {
$query->where('portfolios.wishlist', 0);
});
}
2025-01-28 17:14:49 -06:00
2025-04-09 19:25:15 -05:00
public function scopeWithDailyPerformance($query)
{
$currency = auth()->user()?->getCurrency() ?? config('investbrain.base_currency');
2025-08-21 20:12:59 -05:00
$dividendSub = DB::table('holdings')
->join('dividends', 'dividends.symbol', '=', 'holdings.symbol')
->leftJoin('currency_rates as cr', function ($join) use ($currency) {
$join->on('cr.date', '=', 'dividends.date')
->where('cr.currency', '=', $currency);
})
->join('transactions as tx', function ($join) {
$join->on('tx.symbol', '=', 'holdings.symbol')
->on('tx.portfolio_id', '=', 'holdings.portfolio_id')
->whereColumn('tx.date', '<=', 'dividends.date');
})
->select(['holdings.portfolio_id', 'dividends.date'])
->selectRaw("
((CASE WHEN tx.transaction_type = 'BUY'
THEN tx.quantity ELSE 0 END)
- (CASE WHEN tx.transaction_type = 'SELL'
THEN tx.quantity ELSE 0 END))
* SUM(
dividends.dividend_amount_base
* COALESCE(cr.rate, 1)
)
AS total_dividends_earned")
->groupBy(['holdings.portfolio_id', 'dividends.date', 'tx.transaction_type', 'tx.quantity']);
2025-08-21 19:51:48 -05:00
$transactionTotals = DB::table('transactions')
->select(['transactions.portfolio_id', 'transactions.date'])
->selectRaw("
SUM(
(CASE WHEN transactions.transaction_type = 'BUY' THEN 1 ELSE -1 END)
* transactions.quantity
* transactions.cost_basis_base
* COALESCE(cr.rate, 1)
) AS daily_cost_basis
")
2025-08-21 20:12:59 -05:00
->selectRaw("
SUM(
(CASE
WHEN transactions.transaction_type = 'SELL'
THEN ( transactions.sale_price_base - transactions.cost_basis_base )
* transactions.quantity
* COALESCE(cr.rate, 1)
END)
) AS daily_realized_gains
")
2025-08-21 19:51:48 -05:00
->leftJoin('currency_rates as cr', function ($join) use ($currency) {
$join
->on(DB::raw('DATE(cr.date)'), '=', DB::raw('DATE(transactions.date)'))
->where('cr.currency', $currency);
})
->groupBy('transactions.portfolio_id', 'transactions.date');
$cumulativeCostBasis = DB::table(DB::raw("({$transactionTotals->toSql()}) AS transaction_totals"))
->mergeBindings($transactionTotals)
->select(['portfolio_id', 'date'])
->selectRaw('SUM(daily_cost_basis) AS cumulative_cost_basis')
2025-08-21 20:12:59 -05:00
->selectRaw('SUM(daily_realized_gains) AS cumulative_realized_gains')
2025-08-21 19:51:48 -05:00
->groupBy('portfolio_id', 'date');
2025-04-09 19:25:15 -05:00
return $query
->select(['daily_change.date', 'daily_change.portfolio_id'])
2025-08-21 20:12:59 -05:00
->selectRaw('daily_change.total_market_value * COALESCE(cr.rate, 1) AS total_market_value')
->selectRaw('SUM(COALESCE(ccb.cumulative_cost_basis, 0)) AS total_cost_basis')
2025-08-21 20:54:14 -05:00
->selectRaw('daily_change.total_market_value * COALESCE(cr.rate, 1)
- SUM(COALESCE(ccb.cumulative_cost_basis, 0))
AS total_market_gain')
2025-08-21 20:12:59 -05:00
->selectRaw('SUM(COALESCE(ccb.cumulative_realized_gains, 0)) AS realized_gain_dollars')
->selectSub(function ($query) use ($dividendSub) {
$query->fromSub($dividendSub, 'd')
->selectRaw('SUM(d.total_dividends_earned)')
->whereColumn('d.date', '<=', 'daily_change.date')
->whereColumn('d.portfolio_id', '=', 'daily_change.portfolio_id');
}, 'total_dividends_earned')
2025-04-09 19:25:15 -05:00
->leftJoin('currency_rates as cr', function ($join) use ($currency) {
2025-08-21 19:51:48 -05:00
$join
->on(DB::raw('DATE(cr.date)'), '=', DB::raw('DATE(daily_change.date)'))
->where('cr.currency', $currency);
})
->leftJoinSub($cumulativeCostBasis, 'ccb', function ($join) {
$join
->on('ccb.portfolio_id', '=', 'daily_change.portfolio_id')
->whereRaw('ccb.date <= daily_change.date');
2025-04-09 19:25:15 -05:00
})
2025-08-21 19:51:48 -05:00
->groupBy(['daily_change.date', 'daily_change.portfolio_id', 'cr.rate'])
2025-04-09 19:25:15 -05:00
->orderBy('daily_change.date');
}
2025-08-21 20:54:14 -05:00
public function scopeWithMultipleDailyPerformance($query)
2025-08-11 19:58:17 -05:00
{
2025-08-21 20:54:14 -05:00
return DB::table(DB::raw("({$query->toSql()}) AS daily_query"))
->addBinding($query->getQuery()->getBindings(), 'join')
2025-08-21 21:09:48 -05:00
->select('date')
2025-08-21 20:54:14 -05:00
->selectRaw('SUM(total_market_value) AS total_market_value')
->selectRaw('SUM(total_cost_basis) AS total_cost_basis')
->selectRaw('SUM(total_market_gain) AS total_market_gain')
->selectRaw('SUM(realized_gain_dollars) AS realized_gain_dollars')
->selectRaw('SUM(total_dividends_earned) AS total_dividends_earned')
->groupBy('date');
2025-08-11 19:58:17 -05:00
}
2024-08-15 21:35:43 -05:00
public function portfolio()
{
return $this->belongsTo(Portfolio::class);
}
2024-08-10 13:30:19 -05:00
}