Class: LedgerEntry
- Inherits:
-
ApplicationRecord
- Object
- ActiveRecord::Base
- ApplicationRecord
- LedgerEntry
- 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
- #business_unit ⇒ BusinessUnit
- #ledger_company_account ⇒ LedgerCompanyAccount
- #ledger_detail_project ⇒ LedgerDetailProject
- #ledger_transaction ⇒ LedgerTransaction
- #reconciled_by ⇒ Employee
Methods included from Models::Auditable
Class Method Summary collapse
-
.filter(params) ⇒ ActiveRecord::Relation<LedgerEntry>
Search scope for the GL entries report.
-
.get_materials_in_transit(company_id, start_date, end_date, po_number_ref, reconciled) ⇒ Array<Hash>
Materials-in-Transit reconciliation report.
-
.get_receipts_not_vouchered(company_id, start_date, end_date, po_number_ref, reconciled) ⇒ Array<Hash>
Receipts-Not-Vouchered reconciliation report.
-
.with_transaction_and_resource ⇒ ActiveRecord::Relation<LedgerEntry>
A relation of LedgerEntries that are with transaction and resource.
Instance Method Summary collapse
-
#bank_rec_date_not_closed ⇒ void
Validation: block changing BANK_REC_ATTRIBUTES when the new
bank_datefalls inside a closedBANK_RECperiod. -
#bank_rec_edit_allowed ⇒ void
Validation: prevent un-reconciling or moving the bank-rec date of an entry whose old
bank_dateis already inside a closedBANK_RECperiod — accountants can't retroactively re-open closed reconciliations. -
#business_unit_belongs_to_same_company ⇒ void
Validation: a BusinessUnit tag has to belong to the same Company as the entry's account, otherwise BU rollups would leak across companies.
-
#currency_symbol ⇒ String
ISO currency symbol (
$,€,C$) for the entry'scurrency. -
#edit_allowed ⇒ void
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).
-
#period_not_closed ⇒ void
Validation: block creating a new entry whose transaction date falls inside a LedgerClosingPeriod for the company / transaction type combination.
-
#requires_business_unit? ⇒ Boolean
Whether the linked LedgerDetailAccount flags entries as business-unit-tagged (P&L accounts) rather than free-form (balance-sheet accounts).
-
#set_company_amount ⇒ void
Compute
company_amountandcompany_exchange_rate, convertingamountfrom the entry currency into the owning Company's functional currency. -
#set_consolidated_amount ⇒ void
Compute
consolidated_amount— the entry projected intoCONSOLIDATED_CURRENCY(USD) for group reporting. -
#set_currency ⇒ void
Inherit currency from the parent LedgerTransaction on create (or when the transaction's currency is changed mid-edit).
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
Methods included from Models::AfterCommittable
Methods included from Models::EventPublishable
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.
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.
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_account_sql = 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 #{company_account_sql} #{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.
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_account_sql = 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 #{company_account_sql} #{dates_sql} #{description_sql} #{reconciled_sql} SQL receipts_not_vouchered = conn.execute(sql).to_a.map(&:symbolize_keys) end |
.with_transaction_and_resource ⇒ ActiveRecord::Relation<LedgerEntry>
A relation of LedgerEntries that are with transaction and resource. Active Record Scope
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_closed ⇒ void
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_allowed ⇒ void
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_unit ⇒ BusinessUnit
56 |
# File 'app/models/ledger_entry.rb', line 56 belongs_to :business_unit, optional: true |
#business_unit_belongs_to_same_company ⇒ void
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 ledger_company_account_id.present? and business_unit.company_id != ledger_company_account.company_id errors.add(:business_unit_id, "must belong to same company as the chosen account") end end |
#currency_symbol ⇒ String
ISO currency symbol ($, €, C$) for the entry's currency.
76 77 78 |
# File 'app/models/ledger_entry.rb', line 76 def currency_symbol Money::Currency.new(currency).symbol end |
#edit_allowed ⇒ void
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_account ⇒ LedgerCompanyAccount
53 |
# File 'app/models/ledger_entry.rb', line 53 belongs_to :ledger_company_account, :inverse_of => :ledger_entries, optional: true |
#ledger_detail_project ⇒ LedgerDetailProject
55 |
# File 'app/models/ledger_entry.rb', line 55 belongs_to :ledger_detail_project, :inverse_of => :ledger_entries, optional: true |
#ledger_transaction ⇒ LedgerTransaction
54 |
# File 'app/models/ledger_entry.rb', line 54 belongs_to :ledger_transaction, :inverse_of => :ledger_entries, optional: true |
#period_not_closed ⇒ void
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_by ⇒ Employee
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).
85 86 87 |
# File 'app/models/ledger_entry.rb', line 85 def requires_business_unit? ledger_company_account.present? && ledger_company_account.ledger_detail_account&.requires_business_unit? end |
#set_company_amount ⇒ void
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.ledger_company_account_id.nil? if self.new_record? or self.company_amount.nil? or self.ledger_company_account_id_changed? 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.ledger_company_account.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.ledger_company_account.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_amount ⇒ void
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.ledger_company_account_id_changed? or self.amount_changed? or (self.ledger_transaction and self.ledger_transaction.transaction_date_changed?) if self.currency != CONSOLIDATED_CURRENCY && self.ledger_company_account.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_currency ⇒ void
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 |