Class: DoubleEntry::Line

Inherits:
ActiveRecord::Base
  • Object
show all
Defined in:
lib/double_entry/line.rb

Overview

This is the table to end all tables!

Every financial transaction gets two entries in here: one for the source account, and one for the destination account. Normal double-entry accounting principles are followed.

This is a log table, and should (ideally) never be updated.

## Indexes

The indexes on this table are carefully chosen, as it’s both big and heavily loaded.

### lines_scope_account_id_idx

“‘sql ADD INDEX `lines_scope_account_id_idx` (scope, account, id) “`

This is the important one. It’s used primarily for querying the current balance of an account. eg:

“‘sql SELECT * FROM `lines` WHERE scope = ? AND account = ? ORDER BY id DESC LIMIT 1 “`

### lines_scope_account_created_at_idx

“‘sql ADD INDEX `lines_scope_account_created_at_idx` (scope, account, created_at) “`

Used for querying historic balances:

“‘sql SELECT * FROM `lines` WHERE scope = ? AND account = ? AND created_at < ? ORDER BY id DESC LIMIT 1 “`

And for reporting on account changes over a time period:

“‘sql SELECT SUM(amount) FROM `lines` WHERE scope = ? AND account = ? AND created_at BETWEEN ? AND ? “`

### lines_account_created_at_idx and lines_account_code_created_at_idx

“‘sql ADD INDEX `lines_account_created_at_idx` (account, created_at); ADD INDEX `lines_account_code_created_at_idx` (account, code, created_at); “`

These two are used for generating reports, which need to sum things by account, or account and code, over a particular period.

Class Method Summary collapse

Instance Method Summary collapse

Class Method Details

.find_id_and_created_at(options) ⇒ Object

Query out just the id and created_at fields for lines, without instantiating any ActiveRecord objects.



147
148
149
150
151
152
# File 'lib/double_entry/line.rb', line 147

def self.find_id_and_created_at(options)
  connection.select_rows <<-SQL
    SELECT id, created_at FROM #{Line.quoted_table_name} #{options[:joins]}
     WHERE #{sanitize_sql_for_conditions(options[:conditions])}
  SQL
end

Instance Method Details

#accountObject



106
107
108
# File 'lib/double_entry/line.rb', line 106

def 
  DoubleEntry.(self[:account].to_sym, scope_identity: scope)
end

#account=(account) ⇒ Object



99
100
101
102
103
104
# File 'lib/double_entry/line.rb', line 99

def account=()
  self[:account] = .identifier.to_s
  self.scope = .scope_identity
  fail 'Missing Account' unless self.
  
end

#amountObject



64
65
66
# File 'lib/double_entry/line.rb', line 64

def amount
  self[:amount] && Money.new(self[:amount], currency)
end

#amount=(money) ⇒ Object



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

def amount=(money)
  self[:amount] = (money && money.fractional)
end

#balanceObject



72
73
74
# File 'lib/double_entry/line.rb', line 72

def balance
  self[:balance] && Money.new(self[:balance], currency)
end

#balance=(money) ⇒ Object



76
77
78
# File 'lib/double_entry/line.rb', line 76

def balance=(money)
  self[:balance] = (money && money.fractional)
end

#codeObject



95
96
97
# File 'lib/double_entry/line.rb', line 95

def code
  self[:code].try(:to_sym)
end

#code=(code) ⇒ Object



90
91
92
93
# File 'lib/double_entry/line.rb', line 90

def code=(code)
  self[:code] = code.try(:to_s)
  code
end

#currencyObject



110
111
112
# File 'lib/double_entry/line.rb', line 110

def currency
  .currency if self[:account]
end

#decrease?Boolean

Returns:

  • (Boolean)


137
138
139
# File 'lib/double_entry/line.rb', line 137

def decrease?
  amount.negative?
end

#increase?Boolean

Returns:

  • (Boolean)


141
142
143
# File 'lib/double_entry/line.rb', line 141

def increase?
  amount.positive?
end

#pairObject



129
130
131
132
133
134
135
# File 'lib/double_entry/line.rb', line 129

def pair
  if decrease?
    [self, partner]
  else
    [partner, self]
  end
end

#partnerObject



125
126
127
# File 'lib/double_entry/line.rb', line 125

def partner
  self.class.find(partner_id)
end

#partner_accountObject



121
122
123
# File 'lib/double_entry/line.rb', line 121

def 
  DoubleEntry.(self[:partner_account].to_sym, scope_identity: partner_scope)
end

#partner_account=(partner_account) ⇒ Object



114
115
116
117
118
119
# File 'lib/double_entry/line.rb', line 114

def partner_account=()
  self[:partner_account] = .identifier.to_s
  self.partner_scope = .scope_identity
  fail 'Missing Partner Account' unless self.
  
end

#saveObject



80
81
82
83
# File 'lib/double_entry/line.rb', line 80

def save(**)
  check_balance_will_remain_valid
  super
end

#save!Object



85
86
87
88
# File 'lib/double_entry/line.rb', line 85

def save!(**)
  check_balance_will_remain_valid
  super
end