2024-07-16 09:26:49 -04:00
|
|
|
class Security < ApplicationRecord
|
2024-08-01 19:43:23 -04:00
|
|
|
before_save :upcase_ticker
|
2024-07-16 09:26:49 -04:00
|
|
|
|
|
|
|
has_many :trades, dependent: :nullify, class_name: "Account::Trade"
|
2024-10-29 15:37:59 -04:00
|
|
|
has_many :prices, dependent: :destroy
|
2024-07-16 09:26:49 -04:00
|
|
|
|
2024-10-25 13:09:02 -05:00
|
|
|
validates :ticker, presence: true
|
|
|
|
validates :ticker, uniqueness: { scope: :exchange_mic, case_sensitive: false }
|
2024-07-16 09:26:49 -04:00
|
|
|
|
2024-10-28 15:49:19 -04:00
|
|
|
scope :search, ->(query) {
|
|
|
|
return none if query.blank? || query.length < 2
|
|
|
|
|
|
|
|
# Clean and normalize the search terms
|
|
|
|
sanitized_query = query.split.map do |term|
|
|
|
|
cleaned_term = term.gsub(/[^a-zA-Z0-9]/, " ").strip
|
|
|
|
next if cleaned_term.blank?
|
|
|
|
cleaned_term
|
|
|
|
end.compact.join(" | ")
|
|
|
|
|
|
|
|
return none if sanitized_query.blank?
|
|
|
|
|
|
|
|
sanitized_query = ActiveRecord::Base.connection.quote(sanitized_query)
|
|
|
|
|
|
|
|
where("search_vector @@ to_tsquery('simple', #{sanitized_query}) AND exchange_mic IS NOT NULL")
|
|
|
|
.select("securities.*, ts_rank_cd(search_vector, to_tsquery('simple', #{sanitized_query})) AS rank")
|
|
|
|
.reorder("rank DESC")
|
|
|
|
}
|
|
|
|
|
2024-10-09 14:59:18 -04:00
|
|
|
def current_price
|
2024-10-29 15:37:59 -04:00
|
|
|
@current_price ||= Security::Price.find_price(security: self, date: Date.current)
|
2024-10-09 14:59:18 -04:00
|
|
|
return nil if @current_price.nil?
|
|
|
|
Money.new(@current_price.price, @current_price.currency)
|
|
|
|
end
|
|
|
|
|
2024-10-28 15:49:19 -04:00
|
|
|
def to_combobox_display
|
|
|
|
"#{ticker} - #{name} (#{exchange_acronym})"
|
|
|
|
end
|
|
|
|
|
|
|
|
|
2024-07-16 09:26:49 -04:00
|
|
|
private
|
|
|
|
|
2024-08-01 19:43:23 -04:00
|
|
|
def upcase_ticker
|
|
|
|
self.ticker = ticker.upcase
|
2024-07-16 09:26:49 -04:00
|
|
|
end
|
|
|
|
end
|