A minimal, yet valid double-entry accounting system in Python.
Project description
abacus
A minimal, yet valid double-entry accounting system, provided as abacus-py
Python package and bx
command line tool.
Using abacus
you can define a chart of accounts, create a general ledger, post entries,
close accounts properly at accounting period end and produce trial balance, balance sheet and income statement.
The very minimal example of using abacus
at command line is the following:
pip install abacus-py
mkdir abacus_demo && cd abacus_demo
bx chart start -f
bx chart set --asset cash
bx chart set --capital equity
bx chart set --retained-earnings re
bx ledger start
bx post entry --title "Initial investment" --debit cash --credit equity --amount 5000
bx ledger close
bx report --balance-sheet
Documentation
https://epogrebnyak.github.io/abacus/
Quotes about abacus
I think it's a great idea to mock-up a mini GL ERP to really get a foundational understanding of how the accounting in ERP works!
I teach accounting information systems... I'd be tempted to use abacus as a way of simply showing the structure of a simple AIS.
Hey, what a cool job, thanks much. Do you plan to make a possibility for RAS accounting?
Install
pip install abacus-py
For latest version install from github:
pip install git+https://github.com/epogrebnyak/abacus.git
This will install both abacus-py
package and the bx
command line tool.
abacus-py
requires Python 3.10 or higher.
Minimal example
A freshly created trading Klondike Trading Company (KTC) has recorded the following transactions.
Transaction Title | Debit | Credit | Amount | |
---|---|---|---|---|
1 | Shareholders paid up capital contribution | Cash | Equity | 1000 |
2 | Purchased goods for resale | Inventory | Cash | 800 |
3 | Invoiced client on sales contract | Accounts Receivable | Revenue | 465 |
4 | Provided discount to client | Discounts | Accounts Receivable | 65 |
5 | Recorded cost of sales | COGS | Inventory | 200 |
6 | Paid salary to contract manager | SG&A Expenses | Cash | 100 |
7 | Accepted payment on sales contract | Cash | Accounts Receivable | 360 |
After closing accounts the company announced, but has not paid dividend.
Transaction Title | Debit | Credit | Amount | |
---|---|---|---|---|
* | Accrued dividend after announcement | Retained Earnings | Dividend Due | 50 |
1. Chart
Define a chart of accounts of five types (assets, equity, liabilities, income and expenses), specify retained earnings account name and, optionally, add contra accounts.
from abacus import Chart
chart = Chart(
assets=["cash", "ar", "goods"],
expenses=["cogs", "sga"],
equity=["equity"],
liabilities=["dividend_due"],
income=["sales"])
chart = chart.set_retained_earnings("re").offset("sales", ["discounts"])
2. Ledger
Create a general ledger based on the chart of accounts, post entries and close accounts at accounting period end.
book = (chart.book()
.post(debit="cash", credit="equity", amount=1000)
.post(debit="goods", credit="cash", amount=800)
.post(debit="ar", credit="sales", amount=465)
.post(debit="discounts", credit="ar", amount=65)
.post(debit="cogs", credit="goods", amount=200)
.post(debit="sga", credit="cash", amount=100)
.post(debit="cash", credit="ar", amount=360)
.close()
.after_close(debit="re", credit="dividend_due", amount=50)
)
3. Reports
Make trail balance, income statement and balance sheet and save or print them to screen with verbose account names and rich text formatting.
from abacus import RichViewer, PlainTextViewer
income_statement = book.income_statement()
balance_sheet = book.balance_sheet()
rename_dict = {
"re": "Retained earnings",
"ar": "Accounts receivable",
"goods": "Inventory (goods for sale)",
"cogs": "Cost of goods sold",
"sga": "Selling, general and adm. expenses",
}
tv = PlainTextViewer(rename_dict)
tv.print(balance_sheet)
tv.print(income_statement)
rv = RichViewer(rename_dict, width=80)
rv.print(balance_sheet)
rv.print(income_statement)
The output should look similar to text and a screenshot below.
Assets 1100 Capital 1050
- Cash 460 - Equity 1000
- Accounts receivable 40 - Retained earnings 50
- Inventory (goods for sale) 600 Liabilities 50
- Dividend due 50
Total 1100 Total 1100
Income 400
- Sales 400
Expenses 300
- Cost of goods sold 200
- Selling, general and adm. expenses 100
Profit 100
Screenshot (outdated).
Details about correctness checks and end balances.
Check values
As a reminder assert
statement in Python will raise exception if provided wrong comparison.
These checks will execute and this way we will know the code in README is up to date and correct.
from abacus import IncomeStatement, BalanceSheet
print(income_statement)
assert income_statement == IncomeStatement(
income={'sales': 400},
expenses={'cogs': 200, 'sga': 100}
)
print(balance_sheet)
assert balance_sheet == BalanceSheet(
assets={'cash': 460, 'ar': 40, 'goods': 600},
capital={'equity': 1000, 're': 50},
liabilities={'dividend_due': 50}
)
End balances
You can use end balances from current period to initialize ledger at the start of next accounting period.
end_balances = book.nonzero_balances()
print(end_balances)
next_book = chart.book(starting_balances=end_balances)
Command line
Similar operations with chart, ledger and reports can be performed on the command line.
Create chart of accounts
bx erase --chart
bx chart set --asset cash
bx chart set --asset ar --title "Accounts receivable"
bx chart set --asset goods --title "Inventory (good for sale)"
bx chart set --capital equity
bx chart set --retained-earnings re
bx chart set --liability dividend_due
bx chart set --income sales
bx chart set --expense cogs --title "Cost of sales"
bx chart set --expense sga --title "Selling expenses"
bx chart offset sales discounts
bx chart show
Post entries to ledger and close
bx erase --ledger
bx ledger start
bx post entry --debit cash --credit equity --amount 1000
bx post entry --debit goods --credit cash --amount 800
bx post entry --debit ar --credit sales --amount 465
bx post entry --debit discounts --credit ar --amount 65
bx post entry --debit cogs --credit goods --amount 200
bx post entry --debit sga --credit cash --amount 100
bx post entry --debit cash --credit ar --amount 360
bx ledger close
bx post entry --debit re --credit dividend_due --amount 50 --after-close
Report
bx report --balance-sheet
bx report --income-statement
Account information
bx account cash
bx account ar
bx account goods
bx account sales
bx accounts
You can save end balances to a file and initialize next period ledger.
bx accounts --json > end_balances.json
assert
command will complain if account balance is not equal to provided value.
This is useful for testing.
bx assert cash 460
Feedback
Anything missing in abacus
?
Got a good use case for abacus
or used abacus
for teaching?
Feel free to contact abacus
author
in issues,
on reddit
or via Telegram.
Your feedback is highly appreciated and helps steering development of abacus
.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Hashes for abacus_py-0.5.2-py3-none-any.whl
Algorithm | Hash digest | |
---|---|---|
SHA256 | 2abc362e207e36f7e157860c884a366ac542d5c627da869a12909f9ecacd839f |
|
MD5 | d1d05743db11e972d21450f7847a71c2 |
|
BLAKE2b-256 | 37e7b85a83e89a30f0890d598ff26dae288471f5964bcd5206d5888db361194c |