Changeset 25547 in project for gazette/src/issues/

11/21/11 21:48:09 (9 years ago)
Alaric Snell-Pym

gazette: Split the omelette (insert pun about breaking eggs) between issues 20 and 21, at a suitable point near half-way, with a bit of link text.

1 edited


  • gazette/src/issues/

    r25546 r25547  
    334334"financial book-keeping in scheme" series. If you missed the first part,
    335335check it out [[|here]].
    337 The dream of many Schemers is to write Scheme for a living. Due to the
    338 regrettable tendency of employers to frown upon good ideas, the best
    339 way to achieve this is to start your own company, so you can be your
    340 own boss, and frown upon the good ideas of others instead.
    342 However, running your own company comes at a price; and a big part of
    343 that price is the horror of "book keeping"; the requirement to track
    344 all flows of money and other, more abstract, forms of value in and out
    345 of your company.
    347 Some people will tell you book-keeping is simple. "Just keep all your
    348 receipts and bank statements and bills and invoices", they say. "Then
    349 send them to your accountant at the end of the year."
    351 "But what about value-added tax?", you ask (or "sales tax" in some
    352 countries). "And what about income tax paid at source for my employees
    353 (including myself)?". "And why do I need to pay an accountant so much
    354 to do a job that a computer can easily do in milliseconds?" And then
    355 the smug smile slowly drips from the face of the "Oh it's easy" crowd.
    357 Clearly, book-keeping is complicated. And yet also simple, in that it
    358 is determined by sets of rules.
    360 We know what to do, don't we? Let's get coding!
    362 The problem is that book-keeping involves several different kinds of
    363 inputs - bills (that people send you), invoices (that you send
    364 people), transfers of money (bills and invoices being paid), loans (to
    365 and from the company), employees being paid, interest payments from
    366 the bank, dividend payments, and so on; while it also involves several
    367 different outputs - tax reports for the various taxes involved (in the
    368 UK, I had to deal with VAT every three months, income tax and national
    369 insurance when paying myself and my wife as employees every month, an
    370 annual filing fee, and annual corporation tax and dividend payments),
    371 statutory filing of certain financial summaries (generally annually),
    372 and internal reporting: How much was I spending? How much did each
    373 client owe? How much should be in the bank by when? Plus, it's nice to
    374 be able to generate nice invoices to send to folks who owe you
    375 money. That's a form of specialised report, too, just reporting on a
    376 single invoice.
    378 Each of the output reports depend in complex ways on different
    379 information from the inputs. The VAT reports mainly have to add up how
    380 much VAT I've paid when being billed by others, and how much VAT I've
    381 charged when invoicing - meaning that VAT needs to be tracked on all
    382 bills and invoices so it can be extracted. They also want to know
    383 totals of actual money in and out of the company in the period (even
    384 stuff where VAT isn't an issue), presumably to check up on
    385 me. Meanwhile, end of year reports tend to need to know how much I've
    386 invoiced for various different kinds of work, and what I've spent on
    387 what kinds of things: buying equipment that will last me for several
    388 years is handled differently to expenses like travel, or buying stuff
    389 that I eventually resell to clients (so in our invoices, we need to
    390 keep track of money charged for services separately to money charged
    391 for things).
    393 Some reports care about virtual money moving hands. As soon as I
    394 invoice somebody, then the company now has a virtual asset - some
    395 money owed to it. That's worth as much as cash in the bank from some
    396 perspectives (generally, I have to pay tax on it as soon as it's
    397 invoiced, even if I've not been paid). And yet some care only about
    398 actual cash changing hands (working out my bank balance, for instance).
    400 Sometimes our clients invite us to incur expenses in doing work for
    401 them (such as extra travel) and then invoice them on for those
    402 expenses, so they pay us back - in which case, expenses need to be
    403 able to be tied to invoices, as well. Sometimes we decide to cancel an
    404 invoice, which can't be done by just pretending it never existed, for
    405 audit-trail reasons; we need to issue a "negative" invoice called a
    406 credit note.
    408 Just to complicate matters more, the actual movement of money isn't
    409 atomic. If I invoice somebody on date A, they might post me a cheque
    410 which arrives on date B, which I pay into the bank on date C, which
    411 actually clears into the account (and thereby appears on my bank
    412 statement, when I get it) on date D. So at date A the company now has
    413 a "we are owed" pretend-money asset, which goes through various stages
    414 until it finally turns into money in the bank on date D.
    416 I handled my book-keeping with some hacky scripts written in Chicken
    417 Scheme. What I'm going to document here is partly what I've done, and
    418 partly what I should have done - it was a very iterative process,
    419 refining the best way to handle stuff, and there's lots of
    420 improvements I've wanted to make but not had time to. So I'm going to
    421 describe the ideal case, not the hacky half-way house I actually have
    422 right now!
    424 The approach I took was to have a file called a "ledger" that I enter
    425 all my invoices and so on into. This is parsed to build up a bunch of
    426 data structures in memory, from which the various reports can easily
    427 be obtained. Firstly, for each kind of input object (invoices, bills,
    428 etc) there's a list of them, or more often a hashmap to make them easy
    429 to find by some identifier (I can give my invoices unique symbolic
    430 names, for instance). That contains the raw data as parsed from the
    431 ledger file. But then we also create summary structures, which are
    432 used by the more general reports to generate their output without
    433 having to special-case each and every different input object type, and
    434 to enable sharing of common functionality between reports.
    436 The main summary structure is the double-entry transaction list, which
    437 models the entire financial activity of the company as transfers
    438 between accounts.
    440 Imagine I invoice Widget Corp for setting up and installing a router:
    442   INVOICE INV005: Issued 2011-04-25
    443   Router setup and installation: GBP 800
    444   1 router from my stock: GBP 350
    445   1 train ticket for me to go to their site: GBP 35 (no VAT due)
    446   Subtotal: GBP 1,185
    447   VAT on the above: GBP 230
    448   Total due: GBP 1,415
    450 As part of the work, I lose a router (worth GBP 350) from my stock,
    451 and have to spend GBP 35 on a train fare.
    453 This might expand into the following transactions:
    455  * 2011-03-02: "Expense for Widget Corp (INV005)"
    456    * +35 "Travel to site"
    457    * cash -35
    459  * 2011-04-25 "Invoice Widget Corp (INV005)"
    460    * -800 (Router set up and installation)
    461    * stock.balances -350 (1 of LX300 router, serial number 0343248)
    462    * clients.widgetcorp.expenses -35 (Travel 2011-03-02)
    463    * taxes.vat -230
    464    * clients.widgetcorp.balance +1415
    466 And, eventually, they might pay me, which hits my bank account some
    467 time later:
    469  * 2011-05-07 "Payment from Widget Corp (INV005)"
    470    * clients.widgetcorp.balance -1415
    471    * bank.balance +1415
    473 And then one day I'll pay my VAT bill, which will look something like:
    475  * 2011-06-01 "VAT payment for period from 2011-03-01 to 2011-06-01"
    476    * taxes.vat 230
    477    * bank.balance -230
    479 Note a few tricky things. Each transactions "splits", as the lines
    480 within them are known, have to sum to zero for everything to balance
    481 correctly, which tells us that nothing has gone missing. So when we
    482 start being owed GBP 1,415 by Widget Corp, we need to account for
    483 where that asset has come from. Special accounts with names such as
    484 "" (for value generated by me working) and
    485 "clients.widgetcorp.expenses" (for previously-paid expenses that, as
    486 of this invoice, I can charge the client for) pop into
    487 existence. "taxes.vat" looks as if VAT is a form of income for me, as
    488 money comes "from" it in the transaction - which is sort of true; I'm
    489 charging Widget Corp for some VAT alongside for the actual work
    490 done. Figuring out what signs to put on all the items in the invoice
    491 is mind-bending and painful, but if you just concentrate on making it
    492 all add up to zero in the end and starting from things that are
    493 obvious (is money going into or out of the bank account, or the "owed
    494 to me by this customer" account?), you can figure it out.
    496 From the above, we can start to flesh out some data structures:
    498 <enscript>
    499 (define-record txn
    500                date customer code description splits)
    502 (define-record txn-split
    503                account amount notes)
    506 (define *txns* (make-hash-table))
    507 (define (register-txn! txn)
    508   (if (hash-table-exists? *txns* (txn-date txn))
    509       (begin
    510         (set! (hash-table-ref *txns* (txn-date txn))
    511               (cons txn
    512                     (hash-table-ref *txns* (txn-date txn)))))
    513       (begin
    514         (set! (hash-table-ref *txns* (txn-date txn))
    515               (list txn)))))
    516 </enscript>
    518 What is an "account"? There's a few kinds, and what kind of account it
    519 is matters in reporting. Accounts might be assets within the company -
    520 such as "clients.widgetcorp.balance" or "bank.balance" or
    521 "stock.balance". Or they may be places where money (be it real or
    522 virtual) is created from or destroyed by (from the perspective of the
    523 company), such as "" and "". The important
    524 difference is that balance-type accounts have a balance that is
    525 increased when money is sent to them and decreased when it's taken
    526 out, and that balance is part of the value of the company, while the
    527 income/expense type accounts don't. In my terminology, these are
    528 "balance" accounts and "delta" accounts. Each account also begins to a
    529 group, used to aggregate them in reports: there's income accounts,
    530 bank accounts, client accounts, and so on. And accounts may be tied to
    531 a third party - I've given an example of a client above, but also, the
    532 organisations that send me bills have balances (the money I owe
    533 them). In general, every third party (be they ones that bill me, or
    534 ones that I invoice, or both - I've interacted with other freelancers,
    535 sometimes working for them, sometimes vice versa) has a set of
    536 accounts attached to them for their balance, expenses I can claim from
    537 them, and so on. That implies another set of record types:
    539 <enscript>
    540 (define-record third-party
    541                name address balance-account expenses-account)
    543 (define-record account
    544                name type group third-party)
    547 (define *third-parties* (make-hash-table))
    548 (define *accounts* (make-hash-table))
    550 (define (find-account acct-name)
    551   (hash-table-ref *accounts* acct-name))
    553 (define (register-account! acct)
    554   (set! (hash-table-ref *accounts* (account-name acct)) acct))
    555 </enscript>
    557 An account's {{third-party}} slot may be {{#f}} if it's not part of a
    558 third party.
    560337Now, to make things easy, I parse the ledger by just defining a heap
Note: See TracChangeset for help on using the changeset viewer.