Class: Booking

Inherits:
ActiveRecord::Base
  • Object
show all
Defined in:
app/models/booking.rb

Constant Summary collapse

SELECT_ACCOUNTED_AMOUNT =

Accounted bookings

'CASE WHEN credit_account_id = debit_account_id THEN 0.0 WHEN credit_account_id = %{account_id} THEN -bookings.amount WHEN debit_account_id = %{account_id} THEN bookings.amount ELSE 0 END'

Class Method Summary collapse

Instance Method Summary collapse

Class Method Details

.accountsObject

All involved accounts


100
101
102
# File 'app/models/booking.rb', line 100

def self.accounts
  .where(id: pluck(:debit_account_id).uniq + pluck(:credit_account_id).uniq)
end

.balance_by(account_or_id) ⇒ Object

Balance of bookings for the specified account


143
144
145
# File 'app/models/booking.rb', line 143

def self.balance_by()
  BigDecimal.new(sum(SELECT_ACCOUNTED_AMOUNT % { account_id: () }), 2)
end

.balance_by_grouped_reference(account_or_id) ⇒ Object

Balance of bookings for the specified account, grouped by reference


165
166
167
168
169
170
# File 'app/models/booking.rb', line 165

def self.balance_by_grouped_reference()
  grouped = group(:reference_type, :reference_id).sum(SELECT_ACCOUNTED_AMOUNT % { account_id: () })

  # Convert value to BigDecimal
  Hash[grouped.map { |reference, value| [reference, BigDecimal.new(value, 2)] }]
end

.balancesObject

Accounts with balances


107
108
109
110
111
112
113
# File 'app/models/booking.rb', line 107

def self.balances
   = accounts.map do ||
    [, balance_by()]
  end

  Hash[]
end

.fiscal_yearsObject

Returns array of all years we have bookings for


190
191
192
193
194
# File 'app/models/booking.rb', line 190

def self.fiscal_years
  with_exclusive_scope do
    select('DISTINCT year(value_date) AS year').all.map(&:year)
  end
end

.unbalanced_by_grouped_reference(account_or_id) ⇒ Object

Balance of bookings for the specified account with 0 balance, grouped by reference


150
151
152
153
154
155
156
157
158
159
160
# File 'app/models/booking.rb', line 150

def self.unbalanced_by_grouped_reference()
  # Do a manual sum using select() to be able to give it an alias we can use in having()
  balance_select = "sum(#{SELECT_ACCOUNTED_AMOUNT % { account_id: get_account_id(account_or_id) }})"
  summs = group(:reference_type, :reference_id).having("#{balance_select} != 0.0").select("reference_type, reference_id, #{balance_select} AS balance").reorder(nil)

  # Simulate Rails grouped summing result format
  grouped = Hash[summs.map { |group| [[group[:reference_type], group[:reference_id]], group[:balance]] }]

  # Convert value to BigDecimal
  Hash[grouped.map { |reference, value| [reference, BigDecimal.new(value, 2)] }]
end

Instance Method Details

#accounted_amount(account) ⇒ Object

Helpers


219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
# File 'app/models/booking.rb', line 219

def accounted_amount()
  if  == 
    balance = -(amount)
  elsif  == 
    balance = amount
  else
    return BigDecimal.new('0')
  end

  if .asset_account?
    return balance
  else
    return -(balance)
  end
end

#amount_as_stringObject


235
236
237
# File 'app/models/booking.rb', line 235

def amount_as_string
  '%0.2f' % amount
end

#amount_as_string=(value) ⇒ Object


239
240
241
# File 'app/models/booking.rb', line 239

def amount_as_string=(value)
  self.amount = value
end

#balance_accountObject


56
57
58
59
# File 'app/models/booking.rb', line 56

def 
  return  if .balance_account?
  return  if .balance_account?
end

#contra_account(account = nil) ⇒ Object


41
42
43
44
45
46
47
48
49
50
51
52
53
54
# File 'app/models/booking.rb', line 41

def ( = nil)
  # Derive from direct_account if available
   ||= 

  return unless 

  if  == 
    return 
  elsif  == 
    return 
  else
    return nil
  end
end

#credit_account_codeObject


27
28
29
# File 'app/models/booking.rb', line 27

def 
  .code
end

#credit_account_code=(value) ⇒ Object


31
32
33
# File 'app/models/booking.rb', line 31

def (value)
   = .find_by_code(value)
end

#debit_account_codeObject


19
20
21
# File 'app/models/booking.rb', line 19

def 
  .code
end

#debit_account_code=(value) ⇒ Object


23
24
25
# File 'app/models/booking.rb', line 23

def (value)
   = .find_by_code(value)
end

#direct_accountObject


35
36
37
38
39
# File 'app/models/booking.rb', line 35

def 
  return nil unless reference

  return reference. if reference.respond_to? :direct_account
end

#profit_accountObject


61
62
63
64
# File 'app/models/booking.rb', line 61

def 
  return  if .profit_account?
  return  if .profit_account?
end

#reference_type=(value) ⇒ Object

Safety net for form assignments


290
291
292
# File 'app/models/booking.rb', line 290

def reference_type=(value)
  write_attribute(:reference_type, value) unless value.blank?
end

#rounded_amountObject


243
244
245
246
247
248
249
# File 'app/models/booking.rb', line 243

def rounded_amount
  if amount.nil?
    return 0
  else
    return (amount * 20).round / 20.0
  end
end

#split(amount, params = {}) ⇒ Object

Helpers


252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
# File 'app/models/booking.rb', line 252

def split(amount, params = {})
  # Clone
  new_booking = clone

  # Set amount
  new_booking[:amount] = amount
  self.amount -= amount

  # Update attributes
  params.each do|key, value|
    new_booking[key] = value
  end

  [self, new_booking]
end

#to_s(format = :default) ⇒ Object

Standard methods


197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
# File 'app/models/booking.rb', line 197

def to_s(format = :default)
  case format
  when :long
    '%s: %s an %s CHF %s, %s (%s)' % [
      value_date ? value_date : '?',
       ? "#{debit_account.title} (#{debit_account.code})" : '?',
       ? "#{credit_account.title} (#{credit_account.code})" : '?',
      amount ? '%0.2f' % amount : '?',
      title.present? ? title : '?',
      comments.present? ? comments : '?'
    ]
  else
    '%s: %s / %s CHF %s' % [
      value_date ? value_date : '?',
       ? .code : '?',
       ? .code : '?',
      amount ? '%0.2f' % amount : '?'
    ]
  end
end

#touch_previous_referenceObject


273
274
275
276
277
278
279
280
281
282
283
284
# File 'app/models/booking.rb', line 273

def touch_previous_reference
  # TODO: support reference_type for polymorphic changes
  reference_id_changes = changes[:reference_id]
  if reference_id_changes && (previous_reference_id = reference_id_changes[0])
    # Guard against disappeared previous reference
    begin
      previous_reference = reference_type.constantize.find(previous_reference_id)
      previous_reference.touch if previous_reference != reference
    rescue
    end
  end
end