Accounts (Master List of Accounts with link to their parent (same table) ) (Accounts table is maintained using nested_set plugin, so the left, right, depth are available in the table and are maintained while adding/editing accounts)
| id | name | parent_id |
|----|----------------|-----------|
| 1 | Assets | null |
| 2 | Current Assets | 1 |
| 3 | Fixed Assets | 1 |
| 4 | Bank | 2 |
| 5 | Bank One | 4 |
| 6 | Bank Two | 4 |
| 7 | Revenue | null |
| 8 | Sales | 7 |
| 9 | Expenses | null |
| 10 | Rent | 9 |
Entries (where the date and description of each transaction stored)
| entry_id | date | description |
|----------|------------|--------------------|
| 1 | Mar 3 2020 | Cash Sales |
| 2 | Mar 3 2020 | Cash Paid For Rent |
| 3 | Apr 1 2020 | Owner Withdrawal |
Amounts (where the double entry transactions are stored)
| entry_id | account_id | type | amount |
|----------|------------|--------|--------|
| 1 | 5 | debit | 10000 |
| 1 | 8 | credit | 10000 |
| 2 | 10 | debit | 1000 |
| 2 | 5 | credit | 1000 |
| | | | |
Given the above structure, here is my requirements
- Arrange the accounts in Tree(hierarchical) structure and calculate the individual account balances (balances can be debit_balance or credit_balance)
- Hierarchical account balances, rolling up child balances to the parent accounts
PS: I do have the solution for the req 1 above using a combination of WITH RECURSIVE sql function on the accounts table and arranging the rows hierarchially and then joining the result set with amounts table that is summed up on amount column (after grouping on type) for each accounts. I am keen to see how the folks over here will solve this. (lemme know if you would like to see what I got so far though)
here is the query that gets me the first result set. (i've omitted the details like normal_credit_blance flag etc for brevity in the original question)
select id, parent_id, name, newdepth as depth, debit_amount, credit_amount, type,
CASE WHEN normal_credit_balance = true THEN credit_amount - debit_amount END as credit_balance,
CASE WHEN normal_credit_balance = false THEN debit_amount - credit_amount END as debit_balance
from
(
WITH RECURSIVE children AS (
SELECT id, parent_id, display_name, lft, rgt, type, normal_credit_balance, 0 as newdepth
FROM accounts
WHERE parent_id is null
UNION
SELECT op.id, op.parent_id, op.display_name, op.lft, op.rgt, op.type, op.normal_credit_balance, newdepth + 1
FROM accounts op
JOIN children c ON op.parent_id = c.id
)
SELECT *
FROM children
) accounts_tbl
left join
( SELECT account_id,
SUM( CASE WHEN am.type = 'debit' THEN COALESCE( AMOUNT , 0.0 ) ELSE 0.0 END ) AS debit_amount ,
SUM( CASE WHEN am.type = 'credit' THEN COALESCE( AMOUNT , 0.0 ) ELSE 0.0 END ) AS credit_amount
FROM amounts am
join accounts ac on ac.id = am.account_id
group by account_id, ac.name, ac.type )
as amount_tbl
on accounts_tbl.id = amount_tbl.account_id order by lft
sample result based on the amounts table entries, the rollup should look like this:
| id | name | balance |
|----|----------------|-----------|
| 1 | Assets | 9000 |
| 2 | Current Assets | 9000 |
| 3 | Fixed Assets | 0 |
| 4 | Bank | 9000 |
| 5 | Bank One | 9000 |
| 6 | Bank Two | 0 |
| 7 | Revenue | 10000 |
| 8 | Sales | 10000 |
| 9 | Expenses | 1000 |
| 10 | Rent | 1000 |