Class: WhittakerTech::Midas::Ledger::Account
- Inherits:
-
ApplicationRecord
- Object
- ApplicationRecord
- WhittakerTech::Midas::Ledger::Account
- Includes:
- Poly::Joins
- Defined in:
- app/models/whittaker_tech/midas/ledger/account.rb
Overview
Ledger::Account is a chart-of-accounts entry for Midas's double-entry ledger. An Account is either a system account (no owner — e.g. a per-currency suspense or platform-revenue account) or an owned account (belongs polymorphically to some domain resource, e.g. a Customer or Organization).
Accounts are additive to Coin/Bankable, not a replacement — most Midas
consumers should keep using has_coin/has_coins for simple stored
values. Ledger::Account exists for models that need a full double-entry
audit trail.
Class Method Summary collapse
-
.suspense_for(currency_code) ⇒ Account
Finds or creates the singleton suspense account for a given currency.
Instance Method Summary collapse
-
#balance ⇒ Integer
Raw debit-normal balance: sum(debits) - sum(credits), reading the denormalized
currency_minorcolumn on Posting directly (not joining Coin) so this stays cheap even before Phase 2 partitioning.
Class Method Details
.suspense_for(currency_code) ⇒ Account
Finds or creates the singleton suspense account for a given currency.
Wrapped in a bounded retry: concurrent callers (e.g. two webhooks
racing to post the first out-of-order event in a currency) can both
miss the find_by and attempt to create — the partial unique index
on (slug, currency_code) WHERE owner_id IS NULL makes the loser's
insert raise RecordNotUnique rather than silently duplicating, and
the retry then finds the winner's row.
63 64 65 66 67 68 69 70 71 72 73 |
# File 'app/models/whittaker_tech/midas/ledger/account.rb', line 63 def suspense_for(currency_code) iso = currency_code.to_s.strip.upcase attempts = 0 begin find_or_create_by!(kind: :suspense, slug: 'suspense', currency_code: iso) rescue ActiveRecord::RecordNotUnique attempts += 1 retry if attempts <= 1 raise end end |
Instance Method Details
#balance ⇒ Integer
Raw debit-normal balance: sum(debits) - sum(credits), reading the
denormalized currency_minor column on Posting directly (not joining
Coin) so this stays cheap even before Phase 2 partitioning. Only counts
postings on finalized entries — Entry.create! (bypassing record!) is
a live, if unsanctioned, path to an unfinalized entry with postings
attached, and those must never contribute to a real balance.
This is intentionally kind-agnostic. Presenting a liability/equity/ revenue account's balance as conventionally credit-positive is a display concern layered on top of this raw number, not baked in here.
88 89 90 91 92 |
# File 'app/models/whittaker_tech/midas/ledger/account.rb', line 88 def balance entry_class = WhittakerTech::Midas::Ledger::Entry finalized = postings.joins(:entry).merge(entry_class.where.not(finalized_at: nil)) finalized.debit.sum(:currency_minor) - finalized.credit.sum(:currency_minor) end |