s-m-r-t
Open the s-m-r-t source on GitHub Switch to dark color scheme
← All packages
Business & operations v0.57.40

@happyvertical/smrt-ledgers

Double-entry accounting, journal lifecycle, balance enforcement, and traceable entries.

Source ↗

What it gives you

Double-entry accounting, journal lifecycle, balance enforcement, and traceable entries.

This package is one focused part of the s-m-r-t stack. Its decorated models participate in the same manifest, tenancy, persistence, and generated-interface conventions as the rest of the framework.

Journal entries must balance

Accounts have debit- or credit-normal types. A Journal moves from draft to posted or voided, and each JournalEntry is debit-XOR-credit. In the default tolerant mode BALANCE_EPSILON is 0.01. This catches arithmetic imbalance, but a mixed-unit journal can still balance numerically without being semantically valid; keep integer-minor-unit commerce values consistent.

Named ledgers with exact balancing

A named Ledger fixes its owner, currency, and balance mode when it is created. In exact-integer mode, amounts must be safe integer minor units and debits must equal credits exactly. Accounts assigned to a ledger keep their scope, owner, and type, and cannot be deleted. Posted journals and lines in a named ledger are immutable, so they cannot be voided or deleted; correct them with compensating postings. postReceivable, postPayable, and postSettlement need an exact ledger. Each claims one key per tenant and ledger in a transaction and checks a payload digest when the same key is replayed.

Commerce posts to the accounts each invoice recorded

smrt-commerce posts each invoice line net to the revenue account stored on that line, and each tax component to its own liability account. Integer minor units balance exactly. A canceled invoice gets a reversing journal; the original stays posted.

Posted movements for reporting

JournalEntryCollection.listPostedMovements returns the posted debits and credits for a tenant, a set of accounts, a date range, and a currency, leaving out drafts and voids. The commerce tax summary uses it to set the movement on each tax liability account beside the tax it expects.

Summaries keep sensitive prompt variables out

Journal.summarize() uses the smrtLedgers.journal.summarize prompt-registry entry and excludes PII-conscious variables before invoking a provider.