Class: Generalis::Account

Inherits:
ActiveRecord::Base
  • Object
show all
Defined in:
lib/generalis/account.rb

Direct Known Subclasses

Asset, Expense, Liability, Revenue

Constant Summary collapse

CREDIT_NORMAL =
-1
DEBIT_NORMAL =
+1

Class Method Summary collapse

Instance Method Summary collapse

Class Method Details

.[](name, owner: nil) ⇒ Account

Parameters:

  • name (Symbol, String)
  • owner (ActiveRecord::Base, nil) (defaults to: nil)

Returns:



28
29
30
# File 'lib/generalis/account.rb', line 28

def self.[](name, owner: nil)
  find_by!(name: name, owner: owner)
end

.balance_type(balance_type) ⇒ void

This method returns an undefined value.

Parameters:

  • balance_type (Symbol)


41
42
43
44
45
46
47
48
49
50
51
# File 'lib/generalis/account.rb', line 41

def self.balance_type(balance_type)
  case balance_type
  when :credit_normal
    after_initialize(if: :new_record?) { self.coefficient = CREDIT_NORMAL }
  when :debit_normal
    after_initialize(if: :new_record?) { self.coefficient = DEBIT_NORMAL }
  else
    raise ArgumentError, "Unsupported balance type: #{balance_type.inspect}. " \
                         '(Expected on of :credit_normal or :debit_normal.)'
  end
end

.define(name, owner: nil) ⇒ Account

Parameters:

  • name (Symbol, String)
  • owner (ActiveRecord::Base, nil) (defaults to: nil)

Returns:



21
22
23
# File 'lib/generalis/account.rb', line 21

def self.define(name, owner: nil)
  create_or_find_by!(name: name, owner: owner)
end

.lock_for_balance_calculation(accounts) ⇒ Boolean

Acquires a database lock on one or more accounts for balance calculations. Locks are acquired in a deterministic sequence to prevent deadlocks.

Parameters:

Returns:

  • (Boolean)


58
59
60
# File 'lib/generalis/account.rb', line 58

def self.lock_for_balance_calculation(accounts)
  unscoped.where(id: accounts).order(:id).lock(true).ids.present?
end

.lookup(name, owner: nil) ⇒ Account

Parameters:

  • name (Symbol, String)
  • owner (ActiveRecord::Base, nil) (defaults to: nil)

Returns:



35
36
37
# File 'lib/generalis/account.rb', line 35

def self.lookup(name, owner: nil)
  find_by!(name: name, owner: owner)
end

Instance Method Details

#balance(currency, at: nil) ⇒ Money

Returns the balance for a given currency on this account. If no balance is present for the specified currency, 0 is returned.

Parameters:

  • currency (String)
  • at (Time, nil) (defaults to: nil)

Returns:

  • (Money)


78
79
80
81
82
83
# File 'lib/generalis/account.rb', line 78

def balance(currency, at: nil)
  scope = entries.where(currency: currency)
  scope = scope.at_or_before(at) if at

  scope.last&.balance_after || Money.from_amount(0, currency)
end

#balances(at: nil) ⇒ Hash{String => Money}

Returns the latest balances for all currencies on this account.

Parameters:

  • at (Time, nil) (defaults to: nil)

Returns:

  • (Hash{String => Money})


89
90
91
92
93
94
95
96
# File 'lib/generalis/account.rb', line 89

def balances(at: nil)
  scope = entries.group(:currency).select(Entry.arel_table[:id].maximum)
  scope = scope.at_or_before(at) if at

  entries.where(id: scope)
    .map { |entry| [entry.currency, entry.balance_after] }
    .to_h
end

#credit_normal?Boolean

Returns:

  • (Boolean)


63
64
65
# File 'lib/generalis/account.rb', line 63

def credit_normal?
  coefficient == CREDIT_NORMAL
end

#debit_normal?Boolean

Returns:

  • (Boolean)


68
69
70
# File 'lib/generalis/account.rb', line 68

def debit_normal?
  coefficient == DEBIT_NORMAL
end