Hacker News new | ask | show | jobs
by sorbits 1900 days ago
I would base anything dealing with money on a double entry accounting system.

The issues that arise are then a question about how to translate them to journal entries, which will require accounting experience, and maybe your chart of accounts needs to be revised, but the core system should be fairly stable, and voiding an invoice by issuing a credit note comes automatically, as you’re working with an append-only ledger.

The issues about prepaid plans should also be handled, as payments for services not rendered yet should not be recognized as income, but instead kept as a liability: The OP mentions their system is used by 15,000 customers, so I would give each customer their own account (in the chart of accounts).

The main technical issue is what datatype to use for money, the rest are problems solved by following general accounting principles, though I fear that a lot of programmers out there are reinventing the wheel (in suboptimal ways).

4 comments

> payments for services not rendered yet should not be recognized as income, but instead kept as a liability

This entirely depends on whether you are operating on a cash or accrual basis. Both approach are valid (at least in the USA) and cash basis is often used by small businesses.

I use the word “should” as per RFC 2119, i.e. recommended (as opposed to “must” = required).

Though the IRS does limit the types of businesses that can do cash-basis accounting, it would be businesses without inventory, and who does not offer credit to their customers, e.g. a hairdresser would probably use cash-basis accounting, but more complicated businesses would not, certainly not a business that needs its own billing system :)

I would second this advice :)

I fumbled and bumbled my way to this realization while trying to build a billing system intended to tolerate all sorts of invoicing and reversal scenarios.

More precisely, it doesn't matter what the nature of the billing is, ie recurring (monthly, quarterly..etc) vs one-time; You want to build a system around invoicing for discrete items and resolving those invoices against various criteria (payment received, credits issued, cancelled plans...etc).

You may want to look into 'event sourcing' too. Which is an architectural pattern, very well suited to deal with most accounting problems you describe.

I've built a billing system for a hosting platform. Back when all I knew was MVC (and the then common index.php ballofmud). I wish I had known about eventsourcing then, because so many problems that I spent weeks on, would have never occurred, or been solved in hours.

Eventsourcing comes with its own downsides, requires your mindset to change (esp hard in a team that has been doing relational databases or MVC for years), and is convoluted. But it is a very good fit for a large swath of problems. Financial ones the most.

> 'event sourcing' […] is an architectural pattern, very well suited to deal with most accounting problems

I believe double entry accounting can be described as following this architectural pattern (despite predating it with hundreds of years).

Double entry accounting has both a ledger and a journal. The ledger describes the actual transactions, the journal groups multiple transactions and assigns a “why”, it can also link the journal entry to an invoice, receipt, credit note, or user who caused the journal entry to be created.

So the journal is your event log (not the ledger).

> Eventsourcing comes with its own downsides, requires your mindset to change

Similar to double entry accounting: The learning curve I would say is the “chart of accounts”, how to express everything as ledger transactions, be it tax, fees, discounts, credits, prepayments, etc.

But it can all be done, and once you understand the system, it becomes trivial and extremely flexible.

A rule of thumb is that any number in the interface should come from the ledger, e.g. if you issue an invoice and give your customer a discount, there must be a ledger entry corresponding to that discount.

> I fear that a lot of programmers out there are reinventing the wheel (in suboptimal ways).

How hard can it be???

<goes away and starts writing a new javascript framework from scratch that addresses precisely _one_ of the billing scenarios, and depends on 17,000+ npm libraries, including leftpad.js>