Class: WhittakerTech::Midas::Ledger::Entry

Inherits:
ApplicationRecord
  • Object
show all
Defined in:
app/models/whittaker_tech/midas/ledger/entry.rb

Overview

Ledger::Entry is a balanced double-entry transaction: a group of Postings (debits and credits) that must sum to zero within a single currency.

Ledger::Entry.record! is the only sanctioned way to create an Entry — see its documentation for why. Entries (and their Postings) are immutable once finalized.

Since:

  • 0.4.0

Class Method Summary collapse

Instance Method Summary collapse

Class Method Details

.record!(currency_code:, occurred_at:, lines:, source: nil, memo: nil) ⇒ Entry

The only sanctioned way to build a balanced Entry. Constructs the Entry, then each Posting, then each Posting's Coin, sequentially (required by Coin's own FK — see WhittakerTech::Midas::Coin::Converter for the identical Exchange precedent), all inside one transaction — then finalizes the Entry, which validates the fully-persisted result actually balances before stamping it immutable-and-closed. Any failure (unbalanced, mixed currency, invalid line) rolls the whole transaction back — nothing partial is ever left behind.

Parameters:

  • currency_code (String)

    ISO 4217 currency code for the entry

  • occurred_at (Time)

    business-meaningful time of the transaction

  • lines (Array<Hash>)

    each a {account:, direction:, amount:, currency_code: (optional, defaults to the entry's)} hash

  • source (ActiveRecord::Base, nil) (defaults to: nil)

    optional polymorphic source (an Invoice, a webhook event, a reclassification's original Entry)

  • memo (String, nil) (defaults to: nil)

Returns:

  • (Entry)

    the persisted, finalized Entry

Raises:

  • (ActiveRecord::RecordInvalid)

    if any line or the final balance check fails

Since:

  • 0.4.0



61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
# File 'app/models/whittaker_tech/midas/ledger/entry.rb', line 61

def record!(currency_code:, occurred_at:, lines:, source: nil, memo: nil)
  iso = currency_code.to_s.strip.upcase

  transaction do
    entry = create!(currency_code: iso, occurred_at:, source:, memo:)

    lines.each do |line|
      posting = entry.postings.create!(
        account: line.fetch(:account),
        direction: line.fetch(:direction),
        occurred_at: line[:occurred_at] || occurred_at
      )
      posting.set_amount(amount: line.fetch(:amount), currency_code: line[:currency_code] || iso)
    end

    entry.send(:finalize!)
    entry
  end
end

Instance Method Details

#finalized?Boolean

Returns whether this Entry has completed construction — Postings may only be added/removed while an Entry is not yet finalized (i.e. during record!'s own construction).

Returns:

  • (Boolean)

    whether this Entry has completed construction — Postings may only be added/removed while an Entry is not yet finalized (i.e. during record!'s own construction).

Since:

  • 0.4.0



85
86
87
# File 'app/models/whittaker_tech/midas/ledger/entry.rb', line 85

def finalized?
  finalized_at.present?
end