Files
project-work/worker-toolkit-stocks-in-the-future/repo/app/models/portfolio_position.rb
Eric Bell 2854619bc9 chore: init commit
in worker.../repo/GITFOLDER.zip is the .git folder.
2026-08-11 14:44:09 -04:00

56 lines
1.6 KiB
Ruby

# frozen_string_literal: true
class PortfolioPosition
attr_reader :stock, :shares, :portfolio, :change_amount, :total_return_amount
delegate :current_price, :price_cents, :ticker, to: :stock, prefix: :stock
def initialize(stock:, shares:, portfolio: nil, financial_data: {})
@stock = stock
@shares = shares
@portfolio = portfolio
@change_amount = financial_data[:change_amount]
@total_return_amount = financial_data[:total_return_amount]
end
def current_value
shares * stock_current_price
end
def current_value_cents
shares * stock_price_cents
end
def self.for_portfolio(portfolio)
Stock
.joins(:portfolio_stocks)
.where(portfolio_stocks: { portfolio_id: portfolio.id })
.group("stocks.id")
.having("SUM(portfolio_stocks.shares) > 0")
.select(
<<~SQL.squish
stocks.*,
SUM(portfolio_stocks.shares) AS total_shares,
(stocks.price_cents / 100.0) * SUM(portfolio_stocks.shares) -
SUM(portfolio_stocks.purchase_price * portfolio_stocks.shares) AS aggregated_change_amount,
(stocks.price_cents / 100.0) * SUM(portfolio_stocks.shares) AS aggregated_total_return
SQL
)
.map { |result| build_position(result, portfolio) }
end
def self.build_position(result, portfolio)
new(
stock: result,
shares: result.total_shares,
portfolio: portfolio,
financial_data: {
change_amount: result.aggregated_change_amount,
total_return_amount: result.aggregated_total_return
}
)
end
private_class_method :build_position
end