accounting
Accounting models: T-accounts, journal entries, and ledger.
This package provides the core double-entry bookkeeping primitives.
Bank-specific accounts are in :mod:brms.core.models.accounting.bank_accounts.
Modules:
-
accounts–Generic T-account types and account classifications for double-entry bookkeeping.
-
bank_accounts–Pre-configured chart of accounts for a commercial bank.
-
chart_of_accounts–Chart of accounts: organizes all accounts by category.
-
journal–Journal entries and journal for recording accounting transactions.
-
ledger–General ledger: posts journal entries to accounts and closes the books at period end.
Classes:
-
AccountBalances–A dictionary-like class to hold account balances.
-
AccountNormalBalance–The normal balance of an account or the preferred type of net balance that it should have.
-
AccountType–Types of accounts in the accounting equation.
-
ChartOfAccounts–A chart of accounts organizes all accounts by category.
-
ChartOfAccountsBuilder–Builder for creating a ChartOfAccounts instance.
-
CompositeTAccount–Composite T-account that can hold multiple sub T-accounts.
-
CompoundEntry–A compound journal entry that can affect multiple accounts.
-
IncomeSummaryAccount–Represent the income summary account.
-
Journal–Class to record all journal entries.
-
JournalEntry–Abstract base class for a journal entry.
-
Ledger–The general ledger.
-
RetainedEarningsAccount–Represent the retained earnings account.
-
SimpleEntry–A simple journal entry affecting exactly two accounts.
-
TAccount–A T-account in double-entry bookkeeping.
AccountBalances
Bases: UserDict['TAccount', float]
A dictionary-like class to hold account balances.
Methods:
-
from_accounts–Create an AccountBalances instance from a list of accounts.
from_accounts
classmethod
from_accounts(accounts: list[TAccount]) -> AccountBalances
Create an AccountBalances instance from a list of accounts.
AccountNormalBalance
Bases: Enum
The normal balance of an account or the preferred type of net balance that it should have.
In double-entry bookkeeping, every account has a "normal" side:
- DEBIT_NORMAL: Asset and Expense accounts normally carry debit balances. Debits increase these accounts; credits decrease them.
- CREDIT_NORMAL: Liability, Equity, and Income accounts normally carry credit balances. Credits increase these accounts; debits decrease them.
AccountType
Bases: Enum
Types of accounts in the accounting equation.
The five fundamental account types:
- Asset -- resources owned (debit-normal)
- Liability -- obligations owed (credit-normal)
- Equity -- residual interest (credit-normal)
- Income -- revenue earned (credit-normal, temporary)
- Expense -- costs incurred (debit-normal, temporary)
Accounting equation: Assets = Liabilities + Equity
Methods:
-
get_normal_balance–Return the normal balance for a given account type.
get_normal_balance
staticmethod
get_normal_balance(
account_type: AccountType,
*,
contra_account: bool = False,
) -> AccountNormalBalance
Return the normal balance for a given account type.
A contra account has the opposite normal balance of its parent account type. For example, a contra-asset account has a credit-normal balance.
ChartOfAccounts
dataclass
ChartOfAccounts(
assets: list[TAccount] = list(),
equities: list[TAccount] = list(),
liabilities: list[TAccount] = list(),
income: list[TAccount] = list(),
expenses: list[TAccount] = list(),
income_summary_account: IncomeSummaryAccount = IncomeSummaryAccount(),
retained_earnings_account: RetainedEarningsAccount = RetainedEarningsAccount(),
)
A chart of accounts organizes all accounts by category.
::
+----------------------------------------------+
| Chart of Accounts |
+----------------------------------------------+
| Assets | What the entity owns |
| Liabilities | What the entity owes |
| Equity | Owner's residual interest |
| Income | Revenue earned (temporary) |
| Expenses | Costs incurred (temporary) |
+----------------------------------------------+
| Accounting equation: |
| Assets = Liabilities + Equity |
| |
| At period end, Income and Expenses close to |
| Retained Earnings (Equity) via Income Summary |
+----------------------------------------------+
Methods:
-
all_accounts–Yield every account including nested sub-accounts (depth-first).
all_accounts
all_accounts() -> Generator[TAccount, None, None]
Yield every account including nested sub-accounts (depth-first).
Unlike __iter__, this expands composite accounts so that both the
composite and all of its descendants are yielded. Useful for lookups
by name when the target may be a sub-account.
ChartOfAccountsBuilder
ChartOfAccountsBuilder()
Builder for creating a ChartOfAccounts instance.
Usage::
coa = (
ChartOfAccountsBuilder()
.add_asset_account(cash)
.add_liability_account(deposits)
.add_equity_account(equity)
.add_income_account(interest_income)
.add_expense_account(interest_expense)
.build()
)
Methods:
-
add_asset_account–Add an asset account to the builder.
-
add_equity_account–Add an equity account to the builder.
-
add_expense_account–Add an expense account to the builder.
-
add_income_account–Add an income account to the builder.
-
add_liability_account–Add a liability account to the builder.
-
build–Build and return a ChartOfAccounts instance.
add_asset_account
add_asset_account(
account: TAccount,
) -> ChartOfAccountsBuilder
Add an asset account to the builder.
add_equity_account
add_equity_account(
account: TAccount,
) -> ChartOfAccountsBuilder
Add an equity account to the builder.
add_expense_account
add_expense_account(
account: TAccount,
) -> ChartOfAccountsBuilder
Add an expense account to the builder.
add_income_account
add_income_account(
account: TAccount,
) -> ChartOfAccountsBuilder
Add an income account to the builder.
add_liability_account
add_liability_account(
account: TAccount,
) -> ChartOfAccountsBuilder
Add a liability account to the builder.
CompositeTAccount
CompositeTAccount(
name: str,
account_type: AccountType,
contra_accounts: list[TAccount] | None = None,
parent: TAccount | None = None,
debit: float = 0.0,
credit: float = 0.0,
*,
is_contra_account: bool = False,
)
Bases: TAccount
Composite T-account that can hold multiple sub T-accounts.
A composite account aggregates the balances of its children. Debiting or crediting a child automatically recalculates the parent's totals.
Example -- Investment Securities (composite)::
Investment Securities [composite, debit-normal]
+-- Investment HTM debit: 5,000
+-- Investment FVOCI debit: 3,000
= total debit: 8,000
Methods:
-
add_sub_account–Add a child account to this composite.
-
balance–Return the net balance of this account.
-
credit–Add credit amount to account.
-
debit–Add debit amount to account.
-
has_contra_account–Check if this account has any contra accounts attached.
-
posting_accounts–Recursively yield the lowest-level accounts that accept direct postings.
-
remove_sub_account–Remove a child account from this composite.
Attributes:
-
credit_value(float) –Return the credit value of the account.
-
debit_value(float) –Return the debit value of the account.
-
parent(TAccount | None) –Get the parent account.
-
sub_accounts(Generator[TAccount, None, None]) –Yield direct child accounts.
credit_value
property
writable
credit_value: float
Return the credit value of the account.
debit_value
property
writable
debit_value: float
Return the debit value of the account.
add_sub_account
add_sub_account(account: TAccount) -> None
Add a child account to this composite.
The child's parent is set to this account, and balances are recalculated.
balance
balance() -> float
Return the net balance of this account.
Debit-normal accounts: balance = debits - credits. Credit-normal accounts: balance = credits - debits.
credit
credit(amount: float) -> None
Add credit amount to account.
debit
debit(amount: float) -> None
Add debit amount to account.
has_contra_account
has_contra_account() -> bool
Check if this account has any contra accounts attached.
posting_accounts
posting_accounts() -> Generator[TAccount, None, None]
Recursively yield the lowest-level accounts that accept direct postings.
If this composite has no children, yields itself. Otherwise, recurses into each child's posting_accounts.
remove_sub_account
remove_sub_account(account: TAccount) -> None
Remove a child account from this composite.
CompoundEntry
dataclass
CompoundEntry(
debit_accounts: dict[TAccount, float],
credit_accounts: dict[TAccount, float],
date: date | None = None,
description: str = "",
)
Bases: JournalEntry
A compound journal entry that can affect multiple accounts.
Used when a transaction touches more than two accounts. The total debits must equal total credits (validated on creation).
Example: Closing a trading income account with sub-accounts::
+----------------------------------------------+
| Description: Closing Trading Income |
+----------------------------------------------+
| Debit: Unrealized Gain ......... $5,000 |
| Debit: Realized Gain ........... $3,000 |
| Credit: Income Summary .......... $6,000 |
| Credit: Unrealized Loss ......... $2,000 |
+----------------------------------------------+
Methods:
-
credit_account_value_pairs–Return an iterator over credit account and value pairs.
-
debit_account_value_pairs–Return an iterator over debit account and value pairs.
-
involves_account–Check if the journal entry involves a specific account.
-
is_balanced–Check if the compound entry is balanced.
-
reversed–Return a new CompoundEntry with debit and credit accounts swapped.
-
total_credits–Calculate the total credits for the compound entry.
-
total_debits–Calculate the total debits for the compound entry.
-
validate–Assert sum of debit entries equals sum of credit entries.
credit_account_value_pairs
credit_account_value_pairs() -> (
Iterator[tuple[TAccount, float]]
)
Return an iterator over credit account and value pairs.
debit_account_value_pairs
debit_account_value_pairs() -> (
Iterator[tuple[TAccount, float]]
)
Return an iterator over debit account and value pairs.
involves_account
involves_account(account: TAccount) -> bool
Check if the journal entry involves a specific account.
is_balanced
is_balanced() -> bool
Check if the compound entry is balanced.
Using 1e-6 as a tolerance level to account for floating-point inaccuracies.
reversed
reversed() -> CompoundEntry
Return a new CompoundEntry with debit and credit accounts swapped.
total_credits
total_credits() -> float
Calculate the total credits for the compound entry.
total_debits
total_debits() -> float
Calculate the total debits for the compound entry.
validate
validate() -> None
Assert sum of debit entries equals sum of credit entries.
IncomeSummaryAccount
IncomeSummaryAccount()
Bases: TAccount
Represent the income summary account.
A temporary account used during period-end closing. All income and expense account balances are transferred here, and the net result is then closed to Retained Earnings.
Methods:
-
balance–Return the net balance of this account.
-
credit–Add credit amount to account.
-
debit–Add debit amount to account.
-
has_contra_account–Check if this account has any contra accounts attached.
-
posting_accounts–Yield all accounts that can directly receive debit/credit postings.
Attributes:
-
credit_value(float) –Return the credit value of the account.
-
debit_value(float) –Return the debit value of the account.
-
parent(TAccount | None) –Get the parent account.
-
sub_accounts(Generator[TAccount, None, None]) –Yield direct child accounts. Empty for simple accounts.
credit_value
property
writable
credit_value: float
Return the credit value of the account.
debit_value
property
writable
debit_value: float
Return the debit value of the account.
sub_accounts
property
sub_accounts: Generator[TAccount, None, None]
Yield direct child accounts. Empty for simple accounts.
balance
balance() -> float
Return the net balance of this account.
Debit-normal accounts: balance = debits - credits. Credit-normal accounts: balance = credits - debits.
credit
credit(amount: float) -> None
Add credit amount to account.
debit
debit(amount: float) -> None
Add debit amount to account.
has_contra_account
has_contra_account() -> bool
Check if this account has any contra accounts attached.
posting_accounts
posting_accounts() -> Generator[TAccount, None, None]
Yield all accounts that can directly receive debit/credit postings.
For a simple account, yields itself. For a composite account, recursively yields the lowest-level accounts in the hierarchy that are not themselves composites with children.
The ledger uses this when building closing entries to ensure postings go to accounts that accept direct value changes.
Journal
dataclass
Journal(entries: list[JournalEntry] = list())
Class to record all journal entries.
Methods:
-
add_entry–Add a journal entry to the journal.
-
get_entries_by_account–Get all journal entries involving a specific account.
-
get_entries_by_date–Get all journal entries for a specific date.
-
get_entries_within_date_range–Get all journal entries within a specific date range.
get_entries_by_account
get_entries_by_account(
account: TAccount,
) -> list[JournalEntry]
Get all journal entries involving a specific account.
get_entries_by_date
get_entries_by_date(date: date) -> list[JournalEntry]
Get all journal entries for a specific date.
get_entries_within_date_range
get_entries_within_date_range(
start_date: date, end_date: date
) -> list[JournalEntry]
Get all journal entries within a specific date range.
JournalEntry
Bases: ABC
Abstract base class for a journal entry.
Methods:
-
credit_account_value_pairs–Return an iterator over credit account and value pairs.
-
debit_account_value_pairs–Return an iterator over debit account and value pairs.
-
involves_account–Check if the journal entry involves a specific account.
-
reversed–Return a new entry with debits and credits swapped (reversing entry).
credit_account_value_pairs
credit_account_value_pairs() -> (
Iterator[tuple[TAccount, float]]
)
Return an iterator over credit account and value pairs.
debit_account_value_pairs
debit_account_value_pairs() -> (
Iterator[tuple[TAccount, float]]
)
Return an iterator over debit account and value pairs.
involves_account
abstractmethod
involves_account(account: TAccount) -> bool
Check if the journal entry involves a specific account.
reversed
abstractmethod
reversed() -> JournalEntry
Return a new entry with debits and credits swapped (reversing entry).
Ledger
dataclass
Ledger(
chart_of_accounts: ChartOfAccounts,
journal: Journal = Journal(),
date_closed: date | None = None,
)
The general ledger.
Attributes:
-
chart_of_accounts(ChartOfAccounts) –The chart of accounts containing all T-accounts.
-
journal(Journal) –The journal recording every posted entry.
-
date_closed(date | None) –The date of the most recent period-end close, or
None.
Methods:
-
close_contra_accounts–Net contra account balances against their parent income/expense accounts.
-
close_income_and_expense_accounts–Transfer all income and expense balances to Income Summary.
-
close_income_summary_account–Transfer the Income Summary balance to Retained Earnings.
-
close_ledger–Run the full period-end closing sequence.
-
get_account_balances–Return a snapshot of all account balances.
-
get_accounts_by_type–Return all accounts matching the given type.
-
post–Post a journal entry: record it and update account balances.
-
set_account_balances–Set opening balances directly on accounts.
close_contra_accounts
close_contra_accounts(date: date) -> None
Net contra account balances against their parent income/expense accounts.
For an income account with contra expenses (e.g., Trading Income with Unrealized Trading Loss), this posts an entry that zeroes the contra balances and reduces the parent's balance by the same amount.
close_income_and_expense_accounts
close_income_and_expense_accounts(date: date) -> None
Transfer all income and expense balances to Income Summary.
Skips contra accounts (already closed) and the Income Summary account itself.
close_income_summary_account
close_income_summary_account(date: date) -> None
Transfer the Income Summary balance to Retained Earnings.
close_ledger
close_ledger(date: date) -> None
Run the full period-end closing sequence.
- Net contra accounts against their parents.
- Transfer income/expense balances to Income Summary.
- Transfer Income Summary to Retained Earnings.
get_account_balances
get_account_balances() -> AccountBalances
Return a snapshot of all account balances.
get_accounts_by_type
get_accounts_by_type(
account_type: AccountType,
) -> list[TAccount]
Return all accounts matching the given type.
post
post(entry: JournalEntry) -> None
Post a journal entry: record it and update account balances.
For each debit leg, the corresponding account's debit side increases. For each credit leg, the corresponding account's credit side increases. The entry is appended to the journal for audit purposes.
set_account_balances
set_account_balances(balances: AccountBalances) -> None
Set opening balances directly on accounts.
This bypasses the journal (no entry is recorded) and should only be used for initial setup, never during normal operation.
Each balance is applied to the account's normal side: debit-normal accounts get a debit, credit-normal accounts get a credit.
RetainedEarningsAccount
RetainedEarningsAccount()
Bases: TAccount
Represent the retained earnings account.
Accumulated net income that has not been distributed. During period-end closing, the Income Summary balance is transferred here.
Methods:
-
balance–Return the net balance of this account.
-
credit–Add credit amount to account.
-
debit–Add debit amount to account.
-
has_contra_account–Check if this account has any contra accounts attached.
-
posting_accounts–Yield all accounts that can directly receive debit/credit postings.
Attributes:
-
credit_value(float) –Return the credit value of the account.
-
debit_value(float) –Return the debit value of the account.
-
parent(TAccount | None) –Get the parent account.
-
sub_accounts(Generator[TAccount, None, None]) –Yield direct child accounts. Empty for simple accounts.
credit_value
property
writable
credit_value: float
Return the credit value of the account.
debit_value
property
writable
debit_value: float
Return the debit value of the account.
sub_accounts
property
sub_accounts: Generator[TAccount, None, None]
Yield direct child accounts. Empty for simple accounts.
balance
balance() -> float
Return the net balance of this account.
Debit-normal accounts: balance = debits - credits. Credit-normal accounts: balance = credits - debits.
credit
credit(amount: float) -> None
Add credit amount to account.
debit
debit(amount: float) -> None
Add debit amount to account.
has_contra_account
has_contra_account() -> bool
Check if this account has any contra accounts attached.
posting_accounts
posting_accounts() -> Generator[TAccount, None, None]
Yield all accounts that can directly receive debit/credit postings.
For a simple account, yields itself. For a composite account, recursively yields the lowest-level accounts in the hierarchy that are not themselves composites with children.
The ledger uses this when building closing entries to ensure postings go to accounts that accept direct value changes.
SimpleEntry
dataclass
SimpleEntry(
debit_account: TAccount,
credit_account: TAccount,
value: float,
date: date | None = None,
description: str = "",
)
Bases: JournalEntry
A simple journal entry affecting exactly two accounts.
Example: Receiving a $10,000 deposit::
+----------------------------------------------+
| Date: 2024-01-15 |
| Description: Customer deposit received |
+----------------------------------------------+
| Debit: Cash ..................... $10,000 |
| Credit: Deposits ................ $10,000 |
+----------------------------------------------+
Methods:
-
credit_account_value_pairs–Return an iterator over credit account and value pairs.
-
debit_account_value_pairs–Return an iterator over debit account and value pairs.
-
involves_account–Check if the journal entry involves a specific account.
-
reversed–Return a new SimpleEntry with debit and credit accounts swapped.
credit_account_value_pairs
credit_account_value_pairs() -> (
Iterator[tuple[TAccount, float]]
)
Return an iterator over credit account and value pairs.
debit_account_value_pairs
debit_account_value_pairs() -> (
Iterator[tuple[TAccount, float]]
)
Return an iterator over debit account and value pairs.
involves_account
involves_account(account: TAccount) -> bool
Check if the journal entry involves a specific account.
TAccount
TAccount(
name: str,
account_type: AccountType,
contra_accounts: list[TAccount] | None = None,
parent: TAccount | None = None,
debit: float = 0.0,
credit: float = 0.0,
description: str = "",
*,
is_contra_account: bool = False,
is_temporary_account: bool = False,
)
A T-account in double-entry bookkeeping.
A T-account has two sides: debit (left) and credit (right). The normal balance determines which side increases the account value.
Asset and Expense accounts have DEBIT normal balance::
+----------------------------------+
| Cash (Asset) |
+-----------------+----------------+
| Debit | Credit |
| (increase) | (decrease) |
+-----------------+----------------+
| 1,000 | 200 |
| 500 | |
+-----------------+----------------+
| Balance: 1,300 |
+----------------------------------+
Liability, Equity, and Income accounts have CREDIT normal balance::
+----------------------------------+
| Deposits (Liability) |
+-----------------+----------------+
| Debit | Credit |
| (decrease) | (increase) |
+-----------------+----------------+
| | 5,000 |
| 200 | 1,000 |
+-----------------+----------------+
| Balance: 5,800 |
+----------------------------------+
Double-entry principle: every transaction debits one account and credits another for the same amount, keeping the books balanced.
Example: Receiving a $10,000 deposit::
Cash.debit(10_000) -- Cash increases
Deposits.credit(10_000) -- Deposits increases
Methods:
-
balance–Return the net balance of this account.
-
credit–Add credit amount to account.
-
debit–Add debit amount to account.
-
has_contra_account–Check if this account has any contra accounts attached.
-
posting_accounts–Yield all accounts that can directly receive debit/credit postings.
Attributes:
-
credit_value(float) –Return the credit value of the account.
-
debit_value(float) –Return the debit value of the account.
-
parent(TAccount | None) –Get the parent account.
-
sub_accounts(Generator[TAccount, None, None]) –Yield direct child accounts. Empty for simple accounts.
credit_value
property
writable
credit_value: float
Return the credit value of the account.
debit_value
property
writable
debit_value: float
Return the debit value of the account.
sub_accounts
property
sub_accounts: Generator[TAccount, None, None]
Yield direct child accounts. Empty for simple accounts.
balance
balance() -> float
Return the net balance of this account.
Debit-normal accounts: balance = debits - credits. Credit-normal accounts: balance = credits - debits.
credit
credit(amount: float) -> None
Add credit amount to account.
debit
debit(amount: float) -> None
Add debit amount to account.
has_contra_account
has_contra_account() -> bool
Check if this account has any contra accounts attached.
posting_accounts
posting_accounts() -> Generator[TAccount, None, None]
Yield all accounts that can directly receive debit/credit postings.
For a simple account, yields itself. For a composite account, recursively yields the lowest-level accounts in the hierarchy that are not themselves composites with children.
The ledger uses this when building closing entries to ensure postings go to accounts that accept direct value changes.