Build An Accounting System Using SQLite
Build An Accounting System Using SQLite
In this post, I’m going to show you how to build a crude accounting
database using SQLite.
The good thing about Xero is that it has a nice clean interface and a lot of
apps to choose from to extend its functionality.
Disclaimer: I’m not an engineer nor developer at Xero and these observations
may not exactly correspond to how the system works as it is always updated.
Certainly, the SQL presented here is not the exact SQL design that Xero use as
their system needs to scale. But this is a very interesting project so let’s do it!
Accounting 101
Before you get excited too much, let’s have a crash course first on
accounting.
The right-hand side describes how the assets were financed — either thru
Liabilities or Equity.
Then there’s the concept of Debit and Credit. I could go on and discuss
these two in-depth but for this post, all you need to know is that in every
transaction:
Debit = Credit
Transaction Cycles
Sales Cycle
Purchases Cycle
Cash Cycle
The invoices can be printed directly from the software and they are
automatically numbered in increasing order.
Under the hood, invoices increase the Sales account and Accounts Receivable
(AR) account.
Purchases Cycle
Bills are entered into Xero using Bills. Again, imagine the business issuing
actual bills for purchases (cash purchases or on account). This is the usual
case for utilities and Inventory. This is also the thing that Xero wants to
replicate.
The bills can be printed directly from the software and can be used to
supplement any approval procedures done by the business.
Under the hood, bills increase the Purchases account and Accounts Payable
(AP) account.
Cash Cycle
This involves all transactions pertaining to Cash. There are 4 types
Internal Control
Accounts Receivable
Accounts Payable
Bank Accounts (linked to Bank Feeds)
These accounts cannot be used in Manual journals. This means that Xero
wants you to use Invoices, Bills, and Cash Transactions (Invoice Payments,
Bill Payments, Received Money, and Spent Money) to support the balance
of these accounts. This is Xero’s implementation of internal control if you
will.
Of course, you can use the non-system version of the AR, AP, and Bank
accounts by creating them in the Chart of Accounts (COA). However,
you cannot use the AR, AP, and Bank account types for them.
That’s it for our assumptions. After designing our database, the reader can
lift these assumptions and try mimicking Xero as much as possible.
SQL Basics
Meaning, you cannot edit data in a database by going over the directly to
the data and editing it. (Other DBMS programs have GUIs that allow you
to directly access data in a database and edit it like a spreadsheet. But
under the hood, that action issues an SQL command).
And as you might have guessed it, many-to-many means “a table row is
related to only one or more rows in another table and vice versa”. An
example would be a system that implements partial payments.
An invoice may be paid partially by different payment transactions and a
payment may pay different invoices partially.
Primary keys are necessary to distinguish one row from another. They
uniquely identify each row of data in a table.
Foreign keys, on the other hand, are primary keys from another table.
Hence, by relating the primary keys and foreign keys, the database
relationships are persisted.
For one-to-many, the “one” side contains the primary key and the “many”
contains this primary as its foreign key. In our above example, to get all the
lines belonging to an invoice, we query the InvoiceLines table where the
foreign key equals a particular invoice number.
For many to many, the relationship is broken down into two one-to-many
relationships through a use of a third table called the “joining” table. For
example, our partial payment system will have the Invoices table,
Payments table, and InvoicePayments table as the joining table. The
primary keys of the InvoicePayments table will be a composite key
consisting of the primary keys for the Invoices and Payments table as
follows
Tables for implementing partial Invoice payments
Take note that the joining table does not contain any other data as it does
not have any other purpose aside from joining the Invoices and Payments
tables.
That’s it for the basics of a database. We’re now ready to design our
database.
For the Sales Cycle, we’re going to have the following tables
Invoices
Customers — a customer can have many invoices but an invoice
can’t belong to many customers
Invoice_Payments — remember our assumption for now that there’s
a one-to-many relationship between Invoice_Payments and Invoices
respectively (no partial payments)
Invoice_Lines — this is the joining table between Invoices and COA.
An account may appear in multiple invoices and an invoice may have
multiple accounts.
Chart of Accounts (COA)
For the Purchases Cycle, we’re going to have the following tables
Bills
Suppliers — a supplier can have many bills but a bill can’t belong to
many suppliers
Bill_Payments — remember our assumption for now that there’s a
one-to-many relationship between Bill_Payments and Bills
respectively
Bill_Lines — this is the joining table between Bills and COA. An
account may appear in multiple bills and a bill may have multiple
accounts.
COA — same with the above in the Sales Cycle. Just putting here for
completeness.
For the Cash Cycle, we’re going to have the following tables (Payment
tables we’re already created above)
The joining tables are not shown in the above diagram as they are implicit
in the tables with many-to-many relationships.
Now it’s time to implement our model in SQL. Let’s start by defining
some conventions first.
The primary key will have field/column name of id, and the foreign key
will have the format table_id where table is the name of the table of the
“many” side in singular form. For example, in the Invoices table, the
foreign key will be customer_id.
Even though SQL is a bit relax with regards to syntax, you should strive
to maintain consistency in your SQL code.
Take note also of the relationships shown in the ERD above. Remember
also that the foreign key is on the many side.
To view it, you can use the free and open-sourced SQLite Browser.
Download it here!
Now that we have the sample database, let’s input data to it. Sample data
can be downloaded from here — just break it down to CSVs as needed.
Take note that credits are shown as positives and credits as negatives.
For this post, I just used DB Browser’s import feature to import CSVs
from the above Excel file. For example, to import Customers.csv
Go to File > Import > Table from CSV file and choose the
Customers.csv
Click Ok/Yes to all succeeding prompts to import the data.
If you issue the following SQL command, it should show all the
Customers in our database
In the first two statements, I’m using a CTE (with the keyword
recursive). CTEs are useful as I’m combining 4 tables to get a single view
for Invoice transactions and corresponding payments. You could learn
more above CTEs in SQLite here.
After executing the above command, your database should have the
following 4 views.
Transactions views
Finally, we create the code for the Trial Balance or TB for short. Note
that TB is just a collection of the balances of our transactions taking note
of the rules we laid down when we designed our database.
The above code contains multiple SQL queries joined by the command
union all. I’ve annotated each query to show what each is trying to
achieve.
For example, the first query tries to get all the credits for the Invoice
transactions (mostly Sales). The second one for the debits of the Bill
transactions (mostly Purchases) and so on.
You can put this in Excel to check that debits equal to credits (which I
did). Total debits and credits are 14115 and -14115 respectively.
Hooray! You’ve Made It
Take note that we deliberately limited our database to focus more on the
concepts. You can lift these and try to build another one without the
restrictions.
Every Thursday, the Variable delivers the very best of Towards Data
Science: from hands-on tutorials and cutting-edge research to original
features you don't want to miss. Take a look.
By signing up, you will create a Medium account if you don’t already have
one. Review our Privacy Policy for more information about our privacy
practices.