""" abcFinance is an implementation of an double entry book keeping system
Initialize the accounting system with, the name of the residual_account::
accounts = AccountingSystem('equity')
Create stock and flow account:
accounts.make_stock_account(['cash', 'claims'])
accounts.make_flow_account(['expenditure'])
In order to book give a list of credit and debit tuples. Each tuple should be
an account and a value::
accounts.book(
debit=[('cash', 50), ('claims', 50)],
credit=[('equity', 100)])
get balance gives you the balance of an account:
assert accounts['cash'].get_balance() == (s.DEBIT, 50)
Balance sheet
accounts.book(debit=[('expenditure', 20)], credit=[('cash', 20)])
assert accounts.get_total_assets() == 80, accounts.get_total_assets()
accounts.print_profit_and_loss()
print('--')
accounts.make_end_of_period()
accounts.print_profit_and_loss()
accounts.print_balance_sheet()
assert accounts['equity'].get_balance() == (s.CREDIT, 80)
"""
from enum import Enum
[docs]class s(Enum):
DEBIT = 0
CREDIT = 1
def __repr__(self):
return self.name
[docs]class Account:
def __init__(self):
self.debit = []
self.credit = []
[docs] def get_balance(self):
debitsum = sum(self.debit)
creditsum = sum(self.credit)
if debitsum > creditsum:
return (s.DEBIT, debitsum - creditsum)
else:
return (s.CREDIT, creditsum - debitsum)
[docs] def print_balance(self):
print('debit', self.debit)
print('credit', self.credit)
[docs]class AccountingSystem:
""" The main class to be initialized """
def __init__(self, residual_account_name='equity'):
self.stock_accounts = {}
self.flow_accounts = {}
self.accounts = {}
self.residual_account = None
self.profit_history = []
self.booking_history = []
self.residual_account_name = residual_account_name
self._make_residual_account(residual_account_name)
def __getitem__(self, item):
return self.accounts[item]
[docs] def make_stock_account(self, names):
""" Create stock accounts.
Args:
names, list of names for the accounts
"""
for name in names:
account = Account()
self.stock_accounts[name] = account
self.accounts[name] = account
[docs] def make_flow_account(self, names):
""" Create flow accounts.
Args:
names, list of names for the accounts
"""
for name in names:
account = Account()
self.flow_accounts[name] = account
self.accounts[name] = account
def _make_residual_account(self, name):
account = Account()
self.stock_accounts[name] = account
self.accounts[name] = account
self.residual_account = account
[docs] def book(self, debit, credit, text=""):
""" Book a transaction.
Arguments:
debit, list of tuples ('account', amount)
credit, list of tuples ('account', amount)
text, for booking history
Example::
accounts.book(debit=[('inventory',20)], credit=[('cash',20)], text="Purchase of equipment")
"""
assert sum([value for _, value in debit]) == \
sum([value for _, value in credit])
for account, value in debit:
self.accounts[account].debit.append(value)
for account, value in credit:
self.accounts[account].credit.append(value)
self.booking_history.append((text, debit, credit))
[docs] def make_end_of_period(self):
""" Close flow accounts and credit/debit residual (equity) account """
profit = 0
debit_accounts = []
credit_accounts = []
for name, account in self.flow_accounts.items():
side, balance = account.get_balance()
if balance > 0:
if side == s.DEBIT:
profit -= balance
credit_accounts.append((name, balance))
else:
profit += balance
debit_accounts.append((name, balance))
self.profit_history.append((debit_accounts, credit_accounts))
if profit > 0:
credit_accounts.append((self.residual_account_name, profit))
else:
debit_accounts.append((self.residual_account_name, -profit))
self.book(debit=debit_accounts, credit=credit_accounts, text='Period close')
self.booking_history.append('end of period')
for account in self.flow_accounts:
account = Account()
[docs] def get_total_assets(self):
""" Return total assets. """
total_assets = 0
for account in self.stock_accounts.values():
side, balance = account.get_balance()
if side == s.DEBIT:
total_assets += balance
return total_assets
def _check_debit_eq_credit(self):
debitsum = 0
creditsum = 0
for account in self.accounts.values():
debitsum += sum(account.debit)
creditsum += sum(account.credit)
return debitsum == creditsum
[docs] def print_balance_sheet(self):
""" Print a balance sheets """
print('Stock accounts:')
for name, account in self.stock_accounts.items():
print (name, ":", account.get_balance())
print('--')
[docs] def print_profit_and_loss(self):
""" Print profit and loss statement """
profit = 0
print('Flow accounts:')
for name, account in self.flow_accounts.items():
side, balance = account.get_balance()
if balance != 0:
print (name, ":", side, balance)
if side == s.DEBIT:
profit -= balance
else:
profit += balance
print("Profit for period: ", profit)
print('--')
accounts = AccountingSystem('equity')
accounts.make_stock_account(['cash', 'claims', 'inventory'])
accounts.make_flow_account(['expenditure', 'revenue', 'cost of goods sold', 'depreciation'])
accounts.book(
debit=[('cash', 50), ('claims', 50)],
credit=[('equity', 100)],
text="Start with owners' equity, partially paid in")
assert accounts._check_debit_eq_credit()
assert accounts.get_total_assets() == 100
assert accounts['cash'].get_balance() == (s.DEBIT, 50)
assert accounts['claims'].get_balance() == (s.DEBIT, 50)
assert accounts['equity'].get_balance() == (s.CREDIT, 100)
print('Initial balance')
accounts.print_balance_sheet()
print('Some purchases and operating expenses')
accounts.book(debit=[('expenditure', 20)], credit=[('cash', 20)],text="General expenses")
assert accounts.get_total_assets() == 80, accounts.get_total_assets()
accounts.book(debit=[('inventory',20)],credit=[('cash',20)],text="Purchase of equipment")
accounts.book(debit=[('depreciation',2)],credit=[('inventory',2)],text="Depreciation")
accounts.print_profit_and_loss()
print('Balance sheet after first period')
accounts.make_end_of_period()
accounts.print_balance_sheet()
assert accounts['equity'].get_balance() == (s.CREDIT, 78)
assert accounts['cash'].get_balance() == (s.DEBIT, 10),accounts['cash'].get_balance()
print('Profitable sale')
accounts.book(debit=[('cash',40)],credit=[('revenue',40)],text="Sale of goods")
accounts.book(debit=[('cost of goods sold',10)],credit=[('inventory',10)],text="Sale of goods")
accounts.print_profit_and_loss()
assert accounts['inventory'].get_balance() == (s.DEBIT, 8)
print('Balance sheet after second period')
accounts.make_end_of_period()
accounts.print_balance_sheet()
assert accounts['equity'].get_balance() == (s.CREDIT, 108)