Class: LedgerEntry

Inherits:
ApplicationRecord show all
Includes:
Models::Auditable
Defined in:
app/models/ledger_entry.rb

Overview

== Schema Information

Table name: ledger_entries
Database name: primary

id :integer not null, primary key
amount :decimal(12, 2)
bank_date :date
company_amount :decimal(12, 2)
company_exchange_rate :float
consolidated_amount :decimal(12, 2)
consolidated_exchange_rate :float
currency :string(3) not null
description :string(255)
reconciled :boolean default(FALSE), not null
reconciled_at :datetime
created_at :datetime
updated_at :datetime
business_unit_id :integer
creator_id :integer
ledger_company_account_id :integer not null
ledger_detail_project_id :integer
ledger_transaction_id :integer not null
reconciled_by_id :integer
updater_id :integer

Indexes

by_buid_ltid (business_unit_id,ledger_transaction_id)
by_lcaid_buid_ltid (ledger_company_account_id,business_unit_id,ledger_transaction_id)
by_reconciled_and_account (reconciled,ledger_company_account_id)
idx_lt_id_lca_id (ledger_transaction_id,ledger_company_account_id)
index_ledger_entries_on_bank_date (bank_date)
lca_id_lt_id (ledger_company_account_id,ledger_transaction_id)
ldp_id_bu_id_lt_id (ledger_detail_project_id,business_unit_id,ledger_transaction_id)
lt_id_reconciled (ledger_transaction_id,reconciled)

Constant Summary collapse

LOCKED_ATTRIBUTES =

Columns that are immutable once a LedgerTransaction has been
posted — the Models::Auditable concern raises if any of these
change on a posted entry. Bank-rec fields are excluded so the
bank reconciliation flow can still flip #reconciled.

["ledger_transaction_id", "ledger_company_account_id", "currency", "amount", "company_exchange_rate", "company_amount",
"consolidated_exchange_rate", "consolidated_amount", "business_unit_id", "ledger_detail_project_id"]
BANK_REC_ATTRIBUTES =

Subset of attributes the bank-reconciliation UI is allowed to
mutate after a transaction is posted (see LOCKED_ATTRIBUTES).

["reconciled", "bank_date"]

Constants included from Models::Auditable

Models::Auditable::ALWAYS_IGNORED

Constants included from Schedulable

Schedulable::SIMPLE_FORM_OPTIONS

Belongs to collapse

Methods included from Models::Auditable

#creator, #updater

Class Method Summary collapse

Instance Method Summary collapse

Methods included from Models::Auditable

#all_skipped_columns, #audit_reference_data, #should_not_save_version, #stamp_record

Methods inherited from ApplicationRecord

ransackable_associations, ransackable_attributes, ransackable_scopes, ransortable_attributes, #to_relation

Methods included from Schedulable

config

Methods included from Models::AfterCommittable

#after_commit

Methods included from Models::EventPublishable

#publish_event

Class Method Details

.filter(params) ⇒ ActiveRecord::Relation<LedgerEntry>

Search scope for the GL entries report. Same shape as
LedgerTransaction.filter but joins-and-selects per-entry
columns so rows render straight from a single query.

Parameters:

  • params (Hash, ActionController::Parameters)

Returns:



176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
# File 'app/models/ledger_entry.rb', line 176

def self.filter(params)
  # ledger_entries = LedgerEntry.select("distinct(ledger_entries.*)").with_transaction_and_resource.order("ledger_transactions.transaction_date desc, ledger_transactions.transaction_number desc, ledger_entries.id desc")
  params[:transaction_type] = params[:transaction_type].map(&:presence).compact if params[:transaction_type].present?
  # params[:reconciled] = params[:reconciled].to_b if params[:reconciled].present?
  params[:payment_type] = params[:payment_type].map(&:presence).compact if params[:payment_type].present?
  params[:company_account_id] = (params[:company_account_id].map(&:presence).compact).map!(&:to_i) if params[:company_account_id].present?
  ledger_entries = LedgerEntry.left_outer_joins(ledger_transaction: %i[receipt outgoing_payment])
                              .select("ledger_entries.*,ledger_transactions.transaction_number,ledger_transactions.transaction_type,ledger_transactions.company_id,ledger_transactions.transaction_date,ledger_transactions.description,ledger_transactions.currency,outgoing_payments.category,receipts.category")
                              .order("ledger_transactions.transaction_date desc, ledger_transactions.transaction_number desc, ledger_entries.id desc")
  ledger_entries = ledger_entries.where(ledger_transactions: { transaction_type: params[:transaction_type] }) if params[:transaction_type].present?
  # ledger_entries = ledger_entries.where("ledger_entries.reconciled = ?", params[:reconciled]) if params[:reconciled] == false || params[:reconciled] == true
  ledger_entries = ledger_entries.where(OutgoingPayment[:category].in(params[:payment_type].collect { |pt| pt.downcase.underscore }).or(Receipt[:category].in(params[:payment_type]))) if params[:payment_type].present?
  if params[:transaction_date_gteq].present? or params[:transaction_date_lteq].present?
    start_date = params[:transaction_date_gteq].present? ? params[:transaction_date_gteq] : '2000-01-01'
    end_date = params[:transaction_date_lteq].present? ? params[:transaction_date_lteq] : Time.current.utc.to_date.to_fs(:db)
    ledger_entries = ledger_entries.where(ledger_transactions: { transaction_date: start_date.to_date..end_date.to_date })
  end
  if params[:bank_date_gteq].present? or params[:bank_date_lteq].present?
    bank_start_date = params[:bank_date_gteq].present? ? params[:bank_date_gteq] : '2000-01-01'
    bank_end_date = params[:bank_date_lteq].present? ? params[:bank_date_lteq] : Time.current.utc.to_date.to_fs(:db)
    ledger_entries = ledger_entries.where(bank_date: bank_start_date.to_date..bank_end_date.to_date)
  end
  if params[:reconciled_date_gteq].present? or params[:reconciled_date_lteq].present?
    reconciled_start_date = params[:reconciled_date_gteq].present? ? params[:reconciled_date_gteq] : '2000-01-01'
    reconciled_end_date = params[:reconciled_date_lteq].present? ? params[:reconciled_date_lteq] : Time.current.utc.to_date.to_fs(:db)
    ledger_entries = ledger_entries.where(reconciled_at: reconciled_start_date.to_date..reconciled_end_date.to_date)
  end
  ledger_entries = ledger_entries.where(ledger_company_account_id: params[:company_account_id]) if params[:company_account_id].present?
  # ledger_entries = ledger_entries.where("ledger_transactions.transaction_number = ?", params[:transaction_number]) unless params[:transaction_number].blank?
  # ledger_entries = ledger_entries.where("ledger_transactions.company_id in (?)", params[:company_id]) unless params[:company_id].blank?
  # ledger_entries = ledger_entries.where("ledger_entries.reconciled = ?", params[:reconciled]) unless params[:reconciled].blank?
  # ledger_entries = ledger_entries.where(:receipts => {:card_type => params[:card_type]}) unless params[:card_type].blank?
  # unless params[:description].blank?
  #   description = "%#{params[:description]}%"
  #   ledger_entries = ledger_entries.where("ledger_transactions.description like ? or ledger_entries.description like ?", description, description)
  # end
  # ledger_entries = ledger_entries.where("ledger_entries.amount = ?", BigDecimal(params[:amount])) unless params[:amount].blank?
  # ledger_entries = ledger_entries.where("ledger_transactions.currency in (?)", params[:currency]) unless params[:currency].blank?
  # ledger_entries = ledger_entries.where("ledger_entries.ledger_detail_project_id in (?)", params[:project_id]) unless params[:project_id].blank?
  # ledger_entries = ledger_entries.where("ledger_entries.business_unit_id in (?)", params[:business_unit_id]) unless params[:business_unit_id].blank?
  return ledger_entries
end

.get_materials_in_transit(company_id, start_date, end_date, po_number_ref, reconciled) ⇒ Array<Hash>

Materials-in-Transit reconciliation report. Returns one row
per entry posted to the "Materials in Transit" account, with
filters for date range, company, optional PO number(s), and
reconciliation flag.

Parameters:

  • company_id (Array<Integer>, String)
  • start_date (String, Date)
  • end_date (String, Date)
  • po_number_ref (String)

    whitespace/comma-separated PO numbers

  • reconciled (String, Boolean, nil)

Returns:

  • (Array<Hash>)


291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
# File 'app/models/ledger_entry.rb', line 291

def self.get_materials_in_transit(company_id, start_date, end_date, po_number_ref, reconciled)
  conn = ActiveRecord::Base.lease_connection
  accounts = company_id.empty? ? LedgerCompanyAccount.where(name: 'Materials in Transit').pluck(:id).join(',') : LedgerCompanyAccount.where(name: 'Materials in Transit').where(company_id: company_id).first.id
   = company_id.empty? ? " where ledger_company_account_id in (#{accounts}) " : " where ledger_company_account_id = #{accounts} "
  if start_date.present? && end_date.present?
    dates_sql = " and ltr.transaction_date between #{conn.quote(start_date)} and #{conn.quote(end_date)} "
  elsif start_date.present? && end_date.empty?
    dates_sql = " and ltr.transaction_date >= #{conn.quote(start_date)} "
  end
  po_numbers = po_number_ref.strip.split(/[\s,]+/).map(&:strip).reject(&:blank?)
  description_sql = po_numbers.present? ? " and le.description similar to #{conn.quote("%(#{po_numbers.join('|')})%")} " : " "
  reconciled_sql = reconciled.present? ?  (reconciled.to_bool == true ? ' and reconciled = true ' : ' and reconciled = false ') : ' '
  sql = <<-SQL
    select ltr.id as ledger_transaction_id,ltr.transaction_number,lca.company_id,c.short_name,le.id as ledger_entry_id,le.ledger_company_account_id,acc.number as account,
    ltr.transaction_type as type,ltr.transaction_date as gl_date,le.currency,le.amount,le.company_amount,le.company_exchange_rate as exchange_rate,le.description,le.reconciled as vcr_reconciled
    from ledger_accounts acc
    inner join ledger_company_accounts lca on acc.id = lca.ledger_detail_account_id
    inner join ledger_entries le on le.ledger_company_account_id = lca.id
    inner join ledger_transactions ltr on le.ledger_transaction_id = ltr.id
    inner join companies c on lca.company_id = c.id
    #{}
    #{dates_sql}
    #{description_sql}
    #{reconciled_sql}
  SQL

  materials_in_transit = conn.execute(sql).to_a.map(&:symbolize_keys)
end

.get_receipts_not_vouchered(company_id, start_date, end_date, po_number_ref, reconciled) ⇒ Array<Hash>

Receipts-Not-Vouchered reconciliation report. Walks
shipment-receipt and landed-cost rows, joins them back to GL
entries on the "Receipts Not Vouchered" account, and tries to
pair them by amount + PO. The eight hard-coded lt.id → po_id
mappings handle a backfill of historical mis-postings.

Parameters:

  • company_id (Array<Integer>, String)
  • start_date (String, Date)
  • end_date (String, Date)
  • po_number_ref (String)
  • reconciled (String, Boolean, nil)

Returns:

  • (Array<Hash>)


332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
# File 'app/models/ledger_entry.rb', line 332

def self.get_receipts_not_vouchered(company_id, start_date, end_date, po_number_ref, reconciled)
  conn = ActiveRecord::Base.lease_connection
  accounts = company_id.empty? ? LedgerCompanyAccount.where(name: 'Receipts Not Vouchered').pluck(:id).join(',') : LedgerCompanyAccount.where(name: 'Receipts Not Vouchered').where(company_id: company_id).first.id
   = company_id.empty? ? " where ledger_company_account_id in (#{accounts}) " : " where ledger_company_account_id = #{accounts} "
  if start_date.present? && end_date.present?
    dates_sql = " and ltr.transaction_date between #{conn.quote(start_date)} and #{conn.quote(end_date)} "
  elsif start_date.present? && end_date.empty?
    dates_sql = " and ltr.transaction_date >= #{conn.quote(start_date)} "
  end
  po_numbers = po_number_ref.strip.split(/[\s,]+/).map(&:strip).reject(&:blank?)
  description_sql = po_numbers.present? ? " and (po.po_numbers similar to #{conn.quote("%(#{po_numbers.join('|')})%")} or le.description similar to #{conn.quote("%(#{po_numbers.join('|')})%")}) " : " "
  reconciled_sql = if reconciled.present?
                     reconciled.to_bool == true ? ' and reconciled = true ' : ' and reconciled = false '
                   else
                     ' '
                   end
  lca_ids = LedgerCompanyAccount.where(name: 'Receipts Not Vouchered').pluck(:id)

  sql = <<-SQL
    with receipts_tb as (
        select shipment_receipt_id,purchase_order_id,array_agg(distinct po.reference_number)::varchar as po_numbers,abs(sum(sri.total_cost)) as total_cost
        from shipment_receipt_items sri
        inner join purchase_orders po on sri.purchase_order_id = po.id
        group by shipment_receipt_id,purchase_order_id
    ), r_transactions_tb as (
        select lt.id as ledger_transaction_id,shipment_receipt_id,abs(sum(amount)) as amount
        from ledger_transactions lt
        inner join ledger_entries le on lt.id = le.ledger_transaction_id and ledger_company_account_id in (#{lca_ids.join(',')})
        where shipment_receipt_id is not null
        group by lt.id,shipment_receipt_id
    ), landed_cost_tb as (
        select lc.id as landed_cost_id,purchase_order_id,array_agg(distinct po.reference_number)::varchar as po_numbers,abs(round(sum(lc.total_landed_cost),2)) as total_cost
        from landed_costs lc
        inner join purchase_orders po on lc.purchase_order_id = po.id
        group by lc.id,purchase_order_id
    ), lc_transactions_tb as (
        select lt.id as ledger_transaction_id,landed_cost_id,abs(sum(amount)) as amount
        from ledger_transactions lt
        inner join ledger_entries le on lt.id = le.ledger_transaction_id and ledger_company_account_id in (#{lca_ids.join(',')})
        where landed_cost_id is not null
        group by lt.id,landed_cost_id
    ), pot_same_amount as (
        select ledger_transaction_id,count(*)
        from receipts_tb rt
        inner join r_transactions_tb tt on rt.shipment_receipt_id = tt.shipment_receipt_id and rt.total_cost = tt.amount
        group by ledger_transaction_id
        having count(*) > 1
    ), lt_same_amount as (
        select lt.id as ledger_transaction_id,shipment_receipt_id,abs(sum(amount)) as amount,
                case when lt.id = 44932 then 522
                when lt.id = 44933 then 527
                when lt.id = 513103 then 5686
                when lt.id = 513104 then 5687
                when lt.id = 618809 then 6513
                when lt.id = 618810 then 6779
                when lt.id = 619478 then 6642
                when lt.id = 619479 then 6685 else null end as purchase_order_id
        from ledger_transactions lt
        inner join ledger_entries le on lt.id = le.ledger_transaction_id and ledger_company_account_id in (#{lca_ids.join(',')})
        where lt.id in (select ledger_transaction_id from pot_same_amount)
        group by lt.id,shipment_receipt_id
    ), purchase_orders_transactions as (
        select ledger_transaction_id,po_numbers
        from receipts_tb rt
        inner join r_transactions_tb tt on rt.shipment_receipt_id = tt.shipment_receipt_id and rt.total_cost = tt.amount
        where ledger_transaction_id not in (select ledger_transaction_id from pot_same_amount)
        union all
        select ledger_transaction_id,po_numbers
        from lt_same_amount lsa
        inner join receipts_tb rt on lsa.shipment_receipt_id = rt.shipment_receipt_id and lsa.purchase_order_id = rt.purchase_order_id
        union all
        select ledger_transaction_id,po_numbers
        from landed_cost_tb lct
        left join lc_transactions_tb ltt on lct.landed_cost_id = ltt.landed_cost_id and lct.total_cost = ltt.amount
    )
    select ltr.id as ledger_transaction_id,ltr.transaction_number,lca.company_id,c.short_name,le.id as ledger_entry_id,le.ledger_company_account_id,acc.number as account,
    ltr.transaction_type as type,ltr.transaction_date as gl_date,le.currency,ltr.exchange_rate,le.amount,le.company_amount,po.po_numbers,le.description,le.reconciled as po_reconciled
    from ledger_accounts acc
    inner join ledger_company_accounts lca on acc.id = lca.ledger_detail_account_id
    inner join ledger_entries le on le.ledger_company_account_id = lca.id
    inner join ledger_transactions ltr on le.ledger_transaction_id = ltr.id
    inner join companies c on lca.company_id = c.id
    left join purchase_orders_transactions po on po.ledger_transaction_id = ltr.id
    #{}
    #{dates_sql}
    #{description_sql}
    #{reconciled_sql}
  SQL

  receipts_not_vouchered = conn.execute(sql).to_a.map(&:symbolize_keys)
end

.with_transaction_and_resourceActiveRecord::Relation<LedgerEntry>

A relation of LedgerEntries that are with transaction and resource. Active Record Scope

Returns:

See Also:



72
# File 'app/models/ledger_entry.rb', line 72

scope :with_transaction_and_resource, -> { includes([{:ledger_transaction => [:item_ledger_entries, :company, {:invoice => :customer}, {:receipt => :customer}, :shipment_receipt, :landed_cost, {:voucher => :supplier}, {:credit_memo => :customer}, {:outgoing_payment => [:supplier, :checks]}], :ledger_company_account => [:ledger_detail_account, :company]}, :ledger_detail_project, :business_unit]) }

Instance Method Details

#bank_rec_date_not_closedvoid

This method returns an undefined value.

Validation: block changing BANK_REC_ATTRIBUTES when the new
bank_date falls inside a closed BANK_REC period. Catches
the inverse case of #bank_rec_edit_allowed (newly setting a
closed date rather than touching a previously-closed one).



270
271
272
273
274
275
276
277
278
# File 'app/models/ledger_entry.rb', line 270

def bank_rec_date_not_closed
  lt = self.ledger_transaction
  unless lt.nil? or lt.company_id.nil? or self.bank_date.nil?
    if self.changed? and self.changes.keys.any? {|attr| BANK_REC_ATTRIBUTES.include?(attr)}
      lcls = LedgerClosingPeriod.company_in_all_or(lt.company_id).transaction_type_in("BANK_REC").where(close_to: self.bank_date..)
      errors.add :base, "Bank reconciliation is closed up to #{lcls.first.close_to.to_fs(:crm_default)} for #{lt.company.short_name}." if lcls.any?
    end
  end
end

#bank_rec_edit_allowedvoid

This method returns an undefined value.

Validation: prevent un-reconciling or moving the bank-rec date
of an entry whose old bank_date is already inside a closed
BANK_REC period — accountants can't retroactively re-open
closed reconciliations.



253
254
255
256
257
258
259
260
261
262
# File 'app/models/ledger_entry.rb', line 253

def bank_rec_edit_allowed
  lt = self.ledger_transaction
  unless lt.nil? or lt.company_id.nil? or self.bank_date_was.nil?
    if (self.reconciled_changed? and self.reconciled_was == true) or self.bank_date_changed?
      # it had previously been reconciled, so check the books are not closed for bank recs on the old date
      lcls = LedgerClosingPeriod.company_in_all_or(lt.company_id).transaction_type_in("BANK_REC").where(close_to: (self.bank_date_was || self.bank_date)..)
      errors.add :base, "Bank reconciliation details cannot be changed as they have already been closed up to #{lcls.first.close_to.to_fs(:crm_default)} for #{lt.company.short_name}." if lcls.any?
    end
  end
end

#business_unitBusinessUnit



56
# File 'app/models/ledger_entry.rb', line 56

belongs_to :business_unit, optional: true

#business_unit_belongs_to_same_companyvoid

This method returns an undefined value.

Validation: a BusinessUnit tag has to belong to the same
Company as the entry's account, otherwise BU rollups would
leak across companies.



164
165
166
167
168
# File 'app/models/ledger_entry.rb', line 164

def business_unit_belongs_to_same_company
  if business_unit_id.present? and .present? and business_unit.company_id != .company_id
    errors.add(:business_unit_id, "must belong to same company as the chosen account")
  end
end

#currency_symbolString

ISO currency symbol ($, , C$) for the entry's currency.

Returns:

  • (String)


76
77
78
# File 'app/models/ledger_entry.rb', line 76

def currency_symbol
  Money::Currency.new(currency).symbol
end

#edit_allowedvoid

This method returns an undefined value.

Validation: same closing-period check as #period_not_closed
but only fires when one of LOCKED_ATTRIBUTES is being
changed (so untouched re-saves still pass).



237
238
239
240
241
242
243
244
245
# File 'app/models/ledger_entry.rb', line 237

def edit_allowed
  lt = self.ledger_transaction
  unless lt.nil? or lt.company_id.nil? or lt.transaction_type.nil? or lt.transaction_date.nil?
    if self.changed? and self.changes.keys.any? {|attr| LOCKED_ATTRIBUTES.include?(attr)}
      lcls = LedgerClosingPeriod.company_in_all_or(lt.company_id).transaction_type_in_all_or(lt.transaction_type).where(close_to: lt.transaction_date..)
      errors.add :base, "Period is closed for #{lt.transaction_type} for #{lt.company.short_name} on #{lcls.first.close_to.to_fs(:crm_default)}." if lcls.any?
    end
  end
end

#ledger_company_accountLedgerCompanyAccount



53
# File 'app/models/ledger_entry.rb', line 53

belongs_to :ledger_company_account, :inverse_of => :ledger_entries, optional: true

#ledger_detail_projectLedgerDetailProject



55
# File 'app/models/ledger_entry.rb', line 55

belongs_to :ledger_detail_project, :inverse_of => :ledger_entries, optional: true

#ledger_transactionLedgerTransaction



54
# File 'app/models/ledger_entry.rb', line 54

belongs_to :ledger_transaction, :inverse_of => :ledger_entries, optional: true

#period_not_closedvoid

This method returns an undefined value.

Validation: block creating a new entry whose transaction date
falls inside a LedgerClosingPeriod for the company /
transaction type combination.



224
225
226
227
228
229
230
# File 'app/models/ledger_entry.rb', line 224

def period_not_closed
  lt = self.ledger_transaction
  unless lt.nil? or lt.company_id.nil? or lt.transaction_type.nil? or lt.transaction_date.nil?
    lcls = LedgerClosingPeriod.company_in_all_or(lt.company_id).transaction_type_in_all_or(lt.transaction_type).where(close_to: lt.transaction_date..)
    errors.add :base, "Period is closed for #{lt.transaction_type} for #{lt.company.short_name} up to #{lcls.first.close_to.to_fs(:crm_default)}." if lcls.any?
  end
end

#reconciled_byEmployee

Returns:

See Also:



57
# File 'app/models/ledger_entry.rb', line 57

belongs_to :reconciled_by, :class_name => "Employee", optional: true

#requires_business_unit?Boolean

Whether the linked LedgerDetailAccount flags entries as
business-unit-tagged (P&L accounts) rather than free-form
(balance-sheet accounts).

Returns:

  • (Boolean)


85
86
87
# File 'app/models/ledger_entry.rb', line 85

def requires_business_unit?
  .present? && .&.requires_business_unit?
end

#set_company_amountvoid

This method returns an undefined value.

Compute company_amount and company_exchange_rate, converting
amount from the entry currency into the owning Company's
functional currency. Re-runs whenever amount, account, or
transaction date / rate changes; otherwise just patches drift
if amount × rate no longer equals the stored amount.



107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
# File 'app/models/ledger_entry.rb', line 107

def set_company_amount
  unless self.currency.nil? or self.amount.nil? or self..nil?
    if self.new_record? or self.company_amount.nil? or self. or self.amount_changed? or (self.ledger_transaction and (self.ledger_transaction.transaction_date_changed? or self.ledger_transaction.exchange_rate_changed?))
      if self.currency != self..company.currency
        # the currency of the entry is different to the owning company's currency
        # need to set the exchange rate and record the company amount
        exchange_rate = self.ledger_transaction.exchange_rate || ExchangeRate.get_exchange_rate(self.currency, self..company.currency, self.ledger_transaction.transaction_date)
        self.company_exchange_rate = exchange_rate
        self.company_amount = (self.amount * self.company_exchange_rate).round(2)
      else
        # it's the same so we just copy the amounts and set the exchange rate as 1
        self.company_exchange_rate = 1.0
        self.company_amount = self.amount
      end
    elsif self.amount.present? and self.company_exchange_rate.present? and self.company_amount != self.amount * self.company_exchange_rate
      self.company_amount = (self.amount * self.company_exchange_rate).round(2)
    end
  end
end

#set_consolidated_amountvoid

This method returns an undefined value.

Compute consolidated_amount — the entry projected into
CONSOLIDATED_CURRENCY (USD) for group reporting. Reuses the
company-amount conversion when the owning company is already
in USD; otherwise pulls a fresh ExchangeRate for the
transaction date.



134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
# File 'app/models/ledger_entry.rb', line 134

def set_consolidated_amount
  unless self.currency.nil? or self.amount.nil?
    if self.new_record? or self.consolidated_amount.nil? or self. or self.amount_changed? or (self.ledger_transaction and self.ledger_transaction.transaction_date_changed?)
      if self.currency != CONSOLIDATED_CURRENCY && self..company.currency == CONSOLIDATED_CURRENCY && self.company_amount != nil
        # the currency of the entry is different to the consolidated currency, but the linked account is the same currency
        # so we can just copy the company amount if it's already
        self.consolidated_exchange_rate = self.company_exchange_rate
        self.consolidated_amount = self.company_amount
      elsif self.currency != CONSOLIDATED_CURRENCY
        # the currency of the entry is different to the owning company's currency
        # need to set the exchange rate and record the company amount
        exchange_rate = ExchangeRate.get_exchange_rate(self.currency, CONSOLIDATED_CURRENCY, self.ledger_transaction.transaction_date)
        self.consolidated_exchange_rate = exchange_rate
        self.consolidated_amount = (self.amount * self.consolidated_exchange_rate).round(2)
      else
        # it's the same so we just copy the amounts and set the exchange rate as 1
        self.consolidated_exchange_rate = 1.0
        self.consolidated_amount = self.amount
      end
    elsif self.amount.present? and self.consolidated_exchange_rate.present? and self.consolidated_amount != self.amount * self.consolidated_exchange_rate
      self.consolidated_amount = (self.amount * self.consolidated_exchange_rate).round(2)
    end
  end
end

#set_currencyvoid

This method returns an undefined value.

Inherit currency from the parent LedgerTransaction on create
(or when the transaction's currency is changed mid-edit).
Suppresses NoMethodError when the entry has no transaction yet.



94
95
96
97
98
# File 'app/models/ledger_entry.rb', line 94

def set_currency
  if self.new_record? or (self.ledger_transaction and self.ledger_transaction.currency_changed?)
    self.currency = self.ledger_transaction.currency rescue nil
  end
end