Accounting Transaction

Link two (or more) entries together so that the total of all entries in a transaction is zero

22 January 2005

This is part of the Further Enterprise Application Architecture development writing that I was doing in the mid 2000’s. Sadly too many other things have claimed my attention since, so I haven’t had time to work on them further, nor do I see much time in the foreseeable future. As such this material is very much in draft form and I won’t be doing any corrections or updates until I’m able to find time to work on it again.

Luca Pacioli may well be to accountants what Galleio is to physicists. He was a franciscan monk who first described one of the core ideas of accountancy: double entry bookeeping. The idea behind double entry bookeeping is quite simple, every withdrawel must be balanced with a deposit. Thus everything you do to books has two elements, the subtraction from one account, and the addition to another. In this way money is conserved much like physicists conserve energy. For an accountant you cannot create money, it is only ever moved around.

How it Works

When we use transactions there are actually two kinds that you run into. A two-legged transaction only ever has two entries, which are of opposite sign. This is very literally a single movement from one account to another. A multi-legged transaction allows any number of entries, but with still the overall rule that all the entries must sum to zero, thus conserving money.

Figure 1: An example of a two legged transaction

Figure 2: Class diagram for a multi-legged transaction, notice that the only difference is the multiplicity of the association: accounting transaction -> entry

Figure 3: An example of a multi-legged transaction. This might represent a situation where I have two checks which I pay into my bank account with one deposit slip.

Two-legged transactions are the easiest to work with, so if that's the way the business works, it's not worth trying to build multi-legged transactions even though you can support a two legged transaction with a multi-legged transaction.

With a two-legged transaction the entries are optional - you can choose to have all the data on the transaction. This works if the two entries really are only different in the sign of their amount. When I lived in Britain it was always the case that it took three days to do a transfer from one account to another. So even if I transferred money from my checking (current) to my savings (deposit) account at the same branch, the withdrawel from my checking account would occur three days before the deposit to my savings account. In this case we would need the entries so we could record the separate dates.

Figure 4: A class diagram for an accounting transaction without entries

With a multi-legged transaction often the difficulty lies in how to create the transaction. A two-legged transaction can be created in one operation quite easily. However a multi-legged transaction takes a bit more effort. So it's worth using Proposed Object to build up a transaction before you post it propertly to the appropriate accounts.

When to Use It

To answer this it's worth thinking about why double-entry bookeeping was seen as such a good idea in the first place. Basically it all rests on finding and preventing leaks, or in other words combatting fraud. Without double-entry bookeeping it's too easy to just allow money to appear and dissappear misteriously. Now, of course, double entry keeping doesn't eliminate all fraud, but it makes that little bit easier to find which is enough that people use it. Indeed it's grown to be so deep in the fabric of accounting that people use it without thinking of it.

This doesn't mean you should always use Accounting Transaction. In many ways your use of this pattern depends on whether the people in your domain use the pattern. For a start it really only makes sense to use Accounting Transaction if you're using Account. So if you find you don't use Account you won't use Accounting Transaction either.

Another reason not to use Accounting Transaction is when all the entries are made by the computer. The logging and traceability of this may well satisfy all leak chasing desires. Since you can examine the source code and the database logs, that gives you as plenty of leveridge - using Accounting Transaction would not provide much more.

So you should be driven by your domain experts as to when to use the pattern. In particular you shouln't use it as an extra feature if the domain experts don't feel it's necessary. Like many patterns Accounting Transaction adds complexity to a system, and complexity adds it's own price.

Two-Legged or Multi-Legged?

If you decide to use Accounting Transaction you then have to decide whether to use the two-legged or multi-legged versions. Multi-legged transactions give you the greater flexibility to support entries where a single deposit can be sum many withdrawels or vice-versa. However many applications don't want that because their domain only has two-legged transactions. Multi-legged transactions are also a good bit more complicated. So only use multi-legged transactions if you definitely need their functionality.

It's easy to make multi-legged transactions support two-legged transactions, so it's usually quite easy to refactor from one to the other later. So it's easy to start with two-legged and change to multi-legged later on. The reverse is also quite straightforward, but it's better to start with the simpler if you're not sure.

Example: Two Legged Example (Java)

I'll give you sample code for both the two-legged and multi-legged cases, starting with the simpler two-legged case.

Indeed the two legged case really just needs a simple accounting transaction object.

public class AccountingTransaction {
  private Collection entries = new HashSet();
  public AccountingTransaction(Money amount, Account from, Account to, MfDate date) {
    Entry fromEntry = new Entry (amount.negate(), date);
    from.addEntry(fromEntry);
    entries.add(fromEntry);
    Entry toEntry = new Entry (amount, date);
    to.addEntry(toEntry);
    entries.add(toEntry);
  }

With this you just need to make the constructor for entry to be restricted so that you can't create entries other than in the process of transactions. In Java this is a combination of package access for the constructor and coding convention.

Rather than using accounting transaction constructor directly, it makes sense to provide a suitable method on the account object.

  void withdraw(Money amount, Account target, MfDate date) {
    new AccountingTransaction (amount, this, target, date);
  }

This makes the code for manipulations a lot easier to work with.

public void testBalanceUsingTransactions() {
  revenue = new Account(Currency.USD);
  deferred = new Account(Currency.USD);
  receivables = new Account(Currency.USD);
  revenue.withdraw(Money.dollars(500), receivables, new MfDate(1,4,99));
  revenue.withdraw(Money.dollars(200), deferred, new MfDate(1,4,99));
  assertEquals(Money.dollars(500), receivables.balance());
  assertEquals(Money.dollars(200), deferred.balance());
  assertEquals(Money.dollars(-700), revenue.balance());
}

Example: Multi-Legged Example (Java)

The multi-legged case is a good bit more awkward since a multi-legged transaction is more effort to create and needs validation. In this case I'm using Proposed Object so that I can put together the transaction gradually and then post it to the accounts once I have all the pieces together.

With this approach I need to be able to add entries to a transaction object through separate method calls. Once I have all the transactions, then I can post the transaction to the accounts. I need to check that all the entries balance to zero before I can post, and once I've posted I can't add any more entries to the transaction.

I'll reveal the code starting with the fields and constructor.

public class AccountingTransaction {
    private MfDate date;
    private Collection entries = new HashSet();
    private boolean wasPosted = false;
    public AccountingTransaction(MfDate date) {
    this.date = date;
    }

So with this example I have one date for the whole transaction. This wouldn't handle my old British bank, but it makes things a tad simpler to explain.

The add method adds entries to the transaction, providing the transaction hasn't already been posted.

class Transaction...
  public void add (Money amount, Account account) {
    if (wasPosted) throw new ImmutableTransactionException
          ("cannot add entry to a transaction that's already posted");
    entries.add(new Entry (amount, date, account, this));
  }

In this case I'm using a different entry class to preserve bi-directional associations between the entry and both the transaction and the account. (Entries are immutable, which makes it much easier to deal with maintaining the two-way links.)

class Entry...
    private Money amount;
    private MfDate date;
    private Account account;
    private AccountingTransaction transaction;
    Entry(Money amount, MfDate date, Account account, AccountingTransaction transaction) {
    // only used by AccountingTransaction
    this.amount = amount;
    this.date = date;
    this.account = account;
    this.transaction = transaction;
    }

Once I've added entries to the transaction, I can then post the transaction.

class AccountingTransaction...
  public void post() {
    if (!canPost())
      throw new UnableToPostException();
    Iterator it = entries.iterator();
    while (it.hasNext()) {
      Entry each = (Entry) it.next();
      each.post();
    }
    wasPosted = true;
    }
    public boolean canPost(){
    return balance().isZero();
    }
    private Money balance() {
    if (entries.isEmpty()) return Money.dollars(0);
    Iterator it = entries.iterator();
    Entry firstEntry = (Entry) it.next();
    Money result = firstEntry.amount();
    while (it.hasNext()) {
      Entry each = (Entry) it.next();
      result = result.add(each.amount());
    }
    return result;
    }
class Entry...
  void post() {
    // only used by AccountingTransaction
    account.addEntry(this);
    }

I can then use the transaction with code like this.

    AccountingTransaction multi = new AccountingTransaction(new MfDate(2000,1,4));
    multi.add(Money.dollars(-700), revenue);
    multi.add(Money.dollars(500), receivables);
    multi.add(Money.dollars(200), deferred);
    multi.post();
    assertEquals(Money.dollars(500), receivables.balance());
    assertEquals(Money.dollars(200), deferred.balance());
    assertEquals(Money.dollars(-700), revenue.balance());

All this set up and post business points to why it's so awkward to use a multi-legged transaction. The good news is that if you only need two-legged transactions some of the time, you can implement the two legged interface with a multi-legged transaction.

class Account...
  void withdraw(Money amount, Account target, MfDate date) {
    AccountingTransaction trans = new AccountingTransaction(date);
    trans.add(amount.negate(), this);
    trans.add(amount, target);
    trans.post();
    }