class Account::Entry < ApplicationRecord include Monetizable monetize :amount belongs_to :account belongs_to :transfer, optional: true belongs_to :import, optional: true delegated_type :entryable, types: Account::Entryable::TYPES, dependent: :destroy accepts_nested_attributes_for :entryable validates :date, :name, :amount, :currency, presence: true validates :date, uniqueness: { scope: [ :account_id, :entryable_type ] }, if: -> { account_valuation? } validates :date, comparison: { greater_than: -> { min_supported_date } } scope :active, -> { joins(:account).where(accounts: { is_active: true }) } scope :chronological, -> { order( date: :asc, Arel.sql("CASE WHEN account_entries.entryable_type = 'Account::Valuation' THEN 1 ELSE 0 END") => :asc, created_at: :asc ) } scope :reverse_chronological, -> { order( date: :desc, Arel.sql("CASE WHEN account_entries.entryable_type = 'Account::Valuation' THEN 1 ELSE 0 END") => :desc, created_at: :desc ) } def sync_account_later sync_start_date = [ date_previously_was, date ].compact.min unless destroyed? account.sync_later(start_date: sync_start_date) end def entryable_name_short entryable_type.demodulize.underscore end def balance_trend(entries, balances) Account::BalanceTrendCalculator.new(self, entries, balances).trend end def display_name enriched_name.presence || name end class << self def search(params) Account::EntrySearch.new(params).build_query(all) end # arbitrary cutoff date to avoid expensive sync operations def min_supported_date 30.years.ago.to_date end def bulk_update!(bulk_update_params) bulk_attributes = { date: bulk_update_params[:date], notes: bulk_update_params[:notes], entryable_attributes: { category_id: bulk_update_params[:category_id], merchant_id: bulk_update_params[:merchant_id] }.compact_blank }.compact_blank return 0 if bulk_attributes.blank? transaction do all.each do |entry| bulk_attributes[:entryable_attributes][:id] = entry.entryable_id if bulk_attributes[:entryable_attributes].present? entry.update! bulk_attributes end end all.size end end end