Skip to main content

The world's most comprehensive python Double Entry Accounting Library

Project description

Python Accounting

Build Status

Python Accounting is the world's most comprehensive Double Entry Bookkeeping python library. Unlike other similar libraries, Python Accounting focuses on the generation of Financial Reports compatible with both IFRS and GAAP standards.

The library is designed to be fully customizable, supports multiple Entities (Companies), Account Categorization, Transaction assignment, Opening Balances and Taxation. Transactions are also protected against tampering via direct database changes ensuring the integrity of the Ledger. Apart from the standard set of Financial Reports, the Library also provides convenient Receivable (Client) and Payabale (Supplier) such as Account Statements and Schedules, as well as an Aging Schedule for all outstanding balances grouped by configurable time periods (Current, 31 - 90 days, 91 - 180 days etc).

This library is a community initiative of microbooks.io.

Installation

You can use pip to install. The library requires python 3.9+.

pip install python-accounting

Usage

Full documemntation for the library can be found on readthedocs.

To use the Library, we first need to configure it.

from python_accounting import config
from python_accounting.models import Base
from sqlalchemy import create_engine

database = config.database
engine = create_engine(database["url"])

Base.metadata.create_all(engine) # run migrations to create tables

Now we can create the reporting Entity and its reporting Currency.

from python_accounting.database.session import get_session
from python_accounting.models import Entity, Currency

with get_session(engine) as session:
    entity = Entity(name="Example Company")
    session.add(entity)
    session.commit() # This automatically sets up a Reporting Period for the Entity

    currency = Currency(name="US Dollars", code="USD", entity_id=entity.id)
    session.add(currency)
    session.commit()

Next we'll setup the chart of Accounts.

from python_accounting.models import Account

tax_account = Account(
    name="Tax Account",
    account_type=Account.AccountType.CONTROL,
    currency_id=currency.id,
    entity_id=entity.id,
)
bank_account = Account(
    name="Bank Account",
    account_type=Account.AccountType.BANK,
    currency_id=currency.id,
    entity_id=entity.id,
)
revenue_account = Account(
    name="Revenue Account",
    account_type=Account.AccountType.OPERATING_REVENUE,
    currency_id=currency.id,
    entity_id=entity.id,
)
client_account = Account(
    name="Client Account",
    account_type=Account.AccountType.RECEIVABLE,
    currency_id=currency.id,
    entity_id=entity.id,
)
supplier_account = Account(
    name="Supplier Account",
    account_type=Account.AccountType.PAYABLE,
    currency_id=currency.id,
    entity_id=entity.id,
)
opex_account = Account(
    name="Opex Account",
    account_type=Account.AccountType.OPERATING_EXPENSE,
    currency_id=currency.id,
    entity_id=entity.id,
)
expense_account = Account(
    name="Expense Account",
    account_type=Account.AccountType.DIRECT_EXPENSE,
    currency_id=currency.id,
    entity_id=entity.id,
)
asset_account = Account(
    name="Asset Account",
    account_type=Account.AccountType.NON_CURRENT_ASSET,
    currency_id=currency.id,
    entity_id=entity.id,
)    

session.add_all([
    tax_account, 
    bank_account, 
    revenue_account, 
    client_account, 
    supplier_account, 
    opex_account, 
    expense_account,  
    asset_account
])
session.commit()

Before we can start creating Transactions, we need some Taxes.

from python_accounting.models import Tax

output_tax = Tax(
    name="Output Vat",
    code="OTPT",
    account_id=tax_account.id, # This account was created earlier
    rate=20,
    entity_id=entity.id,
)
input_tax = Tax(
    name="Input Vat",
    code="INPT",
    account_id=tax_account.id,
    rate=10,
    entity_id=entity.id,
)
session.add_all([output_tax, input_tax])
session.commit()

With the Accounts and Taxes in place, we can now prepare some Transactions.

from datetime import datetime 
from python_accounting.transactions import CashSale

cash_sale = CashSale(
    narration="Cash Sale Transaction",
    transaction_date=datetime.now(),
    account_id=bank_account.id,
    entity_id=entity.id,
)
session.add(cash_sale)
session.flush() # Intermediate save does not record the transaction in the Ledger

So far the Transaction has only one side of the double entry, so we create a Line Item for the other side:

from python_accounting.models import LineItem

cash_sale_line_item = LineItem(
    narration="Cash Sale line item",
    account_id=revenue_account.id,
    amount=100,
    tax_id=output_tax.id,
    entity_id=entity.id,
)
session.add(cash_sale_line_item)
session.flush()

cash_sale.line_items.add(cash_sale_line_item)
session.add(cash_sale)
cash_sale.post(session) # This posts the Transaction to the Ledger

Now the rest of the Transactions.

from python_accounting.transactions import (
    CashSale,
    ClientInvoice,
    CashPurchase,
    SupplierBill,
    ClientReceipt,
)

client_invoice = ClientInvoice(
    narration="Client Invoice Transaction",
    transaction_date=datetime.now(),
    account_id=client_account.id,
    entity_id=entity.id,
)
session.add(client_invoice)
session.flush()

client_invoice_line_item = LineItem(
    narration="Client Invoice line item",
    account_id=revenue_account.id,
    amount=50,
    quantity=3,
    tax_id=output_tax.id,
    entity_id=entity.id,
)
session.add(client_invoice_line_item)
session.flush()

client_invoice.line_items.add(client_invoice_line_item)
session.add(client_invoice)
client_invoice.post(session)

cash_purchase = CashPurchase(
    narration="Cash Purchase Transaction",
    transaction_date=datetime.now(),
    account_id=bank_account.id,
    entity_id=entity.id,
)
session.add(cash_purchase)
session.flush()

cash_purchase_line_item = LineItem(
    narration="Cash Purchase line item",
    account_id=opex_account.id,
    amount=25,
    quantity=4,
    tax_id=output_tax.id,
    entity_id=entity.id,
)
session.add(cash_purchase_line_item)
session.flush()

cash_purchase.line_items.add(cash_purchase_line_item)
session.add(cash_purchase)
cash_purchase.post(session)

supplier_bill = SupplierBill(
    narration="Credit Purchase Transaction",
    transaction_date=datetime.now(),
    account_id=supplier_account.id,
    entity_id=entity.id,
)
session.add(supplier_bill)
session.flush()

supplier_bill_line_item = LineItem(
    narration="Credit Purchase line item",
    account_id=asset_account.id,
    amount=25,
    quantity=4,
    tax_id=output_tax.id,
    entity_id=entity.id,
)
session.add(supplier_bill_line_item)
session.flush()

supplier_bill.line_items.add(supplier_bill_line_item)
session.add(supplier_bill)
supplier_bill.post(session)

journal_entry = JournalEntry(
    narration="Journal Entry Transaction",
    transaction_date=datetime.now(),
    account_id=bank_account.id,
    entity_id=entity.id,
)
session.add(journal_entry)
session.flush() 

journal_entry_line_item = LineItem(
    narration="Journal Entry line item",
    account_id=expense_account.id,
    amount=30,
    entity_id=entity.id,
)
session.add(journal_entry_line_item)
session.flush()

journal_entry.line_items.add(journal_entry_line_item)
session.add(journal_entry)
journal_entry.post(session)

client_receipt = ClientReceipt(
    narration="Client Receipt Transaction",
    transaction_date=datetime.now(),
    account_id=client_account.id,
    entity_id=entity.id,
)
session.add(client_receipt)
session.flush()

client_receipt_line_item = LineItem(
    narration="Client Receipt line item",
    account_id=bank_account.id,
    amount=50,
    quantity=1,
    entity_id=entity.id,
)
session.add(client_receipt_line_item)
session.flush()

client_receipt.line_items.add(client_receipt_line_item)
session.add(client_receipt)
client_receipt.post(session)

We can assign the Receipt to partially clear the Invoice above:

from python_accounting.models import Assignment


print(client_invoice.cleared(session)) # 0: The Invoice has not been cleared at all
print(client_receipt.balance(session)) # 60: The Receipt has not been assigned

assignment = Assignment(
    assignment_date=datetime.now(),
    transaction_id=client_receipt.id,
    assigned_id=client_invoice.id,
    assigned_type=client_invoice.__class__.__name__,
    entity_id=entity.id,
    amount=15,
)
session.add(assignment)
session.commit()

print(client_invoice.cleared(session)) # 15 
print(client_receipt.balance(session)) # 45

We are now ready to generate some reports, starting with the Income Statement (Profit and Loss).

from python_accounting.reports import IncomeStatement

income_statement = IncomeStatement(session) 

print(income_statement)

               Example Company
               Income Statement
 For the period: 01, Jan 2024 to 23, Feb 2024

Operating Revenues
    Operating Revenue                250.0000 (100 cash sales + 150 credit sales)

Operating Expenses
    Operating Expense                100.0000 (cash purchase)
                              _______________
Gross Profit                         150.0000


Non Operating Revenues
    Non Operating Revenue              0.0000
                              _______________
Total Revenue                        150.0000


Non Operating Expenses
    Direct Expense                    30.0000
                              _______________
Total Expenses                        30.0000

                              _______________
Net Profit                           120.0000
                              ===============

The Balance Sheet.

from python_accounting.reports import BalanceSheet

balance_sheet = BalanceSheet(session) 

print(balance_sheet)

               Example Company
                Balance Sheet
 For the period: 01, Jan 2024 to 23, Feb 2024

Assets
    Non Current Asset                100.0000 (asset purchase)
    Bank                              30.0000 (120 cash sale - 110 cash purchase + 50 
                                              client receipt - 30 journal entry)
    Receivable                       130.0000 (150 credit sale + 30 Tax - 50 client receipt)
                              _______________
Total Assets                         260.0000


Liabilities
    Control                           30.0000 (Taxes: 20 cash sale + 30 credit sale - 10 cash 
                                              purchase - 10 credit purchase)
    Payable                          110.0000 (100 credit purchase + 10 Tax)
                              _______________
Total Liabilities                    140.0000

                              _______________
Net Assets                           120.0000
                              ===============

Equity
    Income Statement                 120.0000
                              _______________
Total Equity                         120.0000
                              ===============

And finally The Cashflow Statement.

from python_accounting.reports import CashflowStatement

cashflow_statememt = CashflowStatement(session) 

print(cashflow_statememt)

                 Test Entity
              Cashflow Statement
 For the period: 01, Jan 2024 to 23, Feb 2024

Operating Cash Flow
    Net Profit                       120.0000
    Receivables                     -130.0000
    Payables                         110.0000
    Taxation                          30.0000
                              _______________
 Total Operating Cash Flow           130.0000


Investment Cash Flow
    Non Current Assets              -100.0000 (Asset Purchase)
                              _______________
 Total Investment Cash Flow         -100.0000


Financing Cash Flow
    Equity                             0.0000
                              _______________
 Total Financing Cash Flow             0.0000


Net Cash Flow
    Beginning Cash Balance             0.0000
    Net Cash Flow                     30.0000
                              _______________
Ending Cash Balance                   30.0000
                              ===============
                              _______________
Cashbook Balance                      30.0000
                              ===============

Supported Databases (Fully tested)

  • MySql/MariaDb
  • Postgres
  • Sqlite (testing)

Changelog

Please see CHANGELOG for more information about recent changes.

Contributing

Please see CONTRIBUTING for more information about how to get involved.

License

This software is distributed for free under the MIT License. Please see LICENCE for more information.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

python_accounting-1.0.1.tar.gz (39.8 kB view details)

Uploaded Source

Built Distribution

python_accounting-1.0.1-py3-none-any.whl (70.8 kB view details)

Uploaded Python 3

File details

Details for the file python_accounting-1.0.1.tar.gz.

File metadata

  • Download URL: python_accounting-1.0.1.tar.gz
  • Upload date:
  • Size: 39.8 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: poetry/1.7.1 CPython/3.12.1 Windows/10

File hashes

Hashes for python_accounting-1.0.1.tar.gz
Algorithm Hash digest
SHA256 6a0a54e1e3a1516a1dfe2521ffac28a3a7da015224834539169ff09cf058a655
MD5 92225d667e1b5e88c1ab0122299c2643
BLAKE2b-256 5ebfc5617e8d24eb5a42e2bfb001bcb069465355966c49b7d8dc0da1e2159d4b

See more details on using hashes here.

File details

Details for the file python_accounting-1.0.1-py3-none-any.whl.

File metadata

File hashes

Hashes for python_accounting-1.0.1-py3-none-any.whl
Algorithm Hash digest
SHA256 6ee9907e07a1139e5db3b71cc669690b8ff3351ab7e79ba77178662323267fb0
MD5 0e554bcc0baae3a15ec8adedd8f76907
BLAKE2b-256 d610dc65d77d49f4fd03ec87e4367de70cb4cb6a04eb4f085768c644d4ffea9c

See more details on using hashes here.

Supported by

AWS AWS Cloud computing and Security Sponsor Datadog Datadog Monitoring Fastly Fastly CDN Google Google Download Analytics Microsoft Microsoft PSF Sponsor Pingdom Pingdom Monitoring Sentry Sentry Error logging StatusPage StatusPage Status page