simonmic 5 years ago

I'm hledger's lead developer, thanks for the mention. If you have any questions or hit any snags trying it out, I'm ready to help. Critique of product, docs etc. is welcome. Last time (2017) we got 2 out of 41 comments about hledger, so I'm hoping for a few more. :) https://hledger.org/release-notes has the (software) changes since then. Our chat is #hledger on Freenode: http://webchat.freenode.net/?channels=hledger

  • simonmic 5 years ago

    PS Thanks meruru for mentioning http://plaintextaccounting.org. I started it to knit and grow our community, give more visibility to the non-Ledger projects like hledger, beancount and the rest, help answer VFAQs on IRC and mail lists, collect best practices, etc.

    That site is also worth checking out for more hledger materials, such as comparisons, talks, slideshows, and blog posts. Eg Andreas Pauley's quick intro slides (https://pauley.org.za/functional-finance-hledger) or my slow "Hands-on with hedger" talk and FLOSS Weekly appearance.

  • OskarS 5 years ago

    I've been using ledger (the original one) for the last couple of months, and I'm loving it. I'm way into the whole plain text accounting thing.

    I guess it's the most obvious question in the world, but: what are the big reasons I should switch to hledger? What do you see as the primary advantages of hledger over ledger?

    • smichael 5 years ago

      As hledger's proud parent, having preferred it for my needs since the early releases, I can talk about this for a long time. :) The https://hledger.org/FAQ addresses it, as PhilippGille mentioned. I still find it hard to answer concisely. Let me give it another shot:

      Here are some things I've tried to do differently with hledger compared to Ledger. I feel we've had some success with all of these:

      Project:

      - be actively maintained and contributed to

      - build out Ledger's concepts a bit more selectively/thoroughly/to a higher level of polish, taking advantage of hindsight, a fresh codebase, a well-suited language

      Docs & design:

      - all behaviour fully specified and documented

      - all docs up to date and accurate

      - practice documentation-first design and development

      - more intuitive, learnable, consistent concepts and UX

      - be usable for less-technical users as well as techies

      - be easy to get started with as well as efficient for regular use

      - explicitly try to model accounting concepts and help meet real world accounting needs

      Software:

      - be robust and dependable, with few user-visible bugs

      - be easy to install and run well on all major platforms

      - provide APIs/libs enabling more plain text accounting hacking among Haskellers

      - be readable, clear, and a useful source of algorithm & architecture ideas for other implementors

      - remain maintainable and cost effective over the long term

      - achieve a long lifespan and provide a safe long term format for accounting data

      Technology:

      - clarify whether Haskell is good for real-world apps (yes!)

      - learn more Haskell by building a real-world app (yes!)

      - attract contributors by being a Haskell project (yes)

      Out of time for now, I hope it's not too hand-wavy..

      • benj111 5 years ago

        "be robust and dependable, with few user-visible bugs"

        Not wanting to come across as too argumentative :). I'd prefer if there had to be bugs that they were user visible.

        • smichael 5 years ago

          Good point. By "user-visible" I mean "any real problem a user could recognise if it was pointed out to them". Such as a wrong sign, wrong decimal digit, or behaviour not agreeing with the docs.

  • wtvanhest 5 years ago

    Just curious, do you guys have any power users? Like large companies? Also, what does the distant future look like for hledger?

    • jsmith99 5 years ago

      Large companies don't usually post everything manually. They journal adjustments, but the day to day entries will be made automatically by their ERP from systems like Purchase to Pay.

      • speleding 5 years ago

        There is no reason to post things manually with (h)ledger, it's a command line tool so it's perfectly scriptable.

        Our company uses a plethora of (mostly) ruby scripts to get data from banks and the billing system API and a few other sources like exchange rates websites and converts the output into ledger files. And then another bunch of scripts takes the output from ledger and sends it to the API for, for example, the government VAT payments. (Our company is by no means big, but multinational with business in 7 currencies).

        There are a number of test and assert statements along the line to do sanity checks with a manual review since sending out incorrect values could potentially be expensive / illegal. It works great. The whole thing is stored in git so any changes are auditable. We need some of the power features of ledger though, so I doubt ledger will work for us, but I'll give it a spin.

      • dragonsh 5 years ago

        Actually large companies are mostly manual compared to most small/medium size companies. Just too many processes to just generate correct journal entries in SAP from purchase, sales, operations, production and distribution. Moreover adjustments, inventory counting methods, purchase, sales require creative use of manual processes, excel and laborious job of account reconciliation at closing (which indeed is just a snapshot report at point in time). I have yet to see a multi-national SAP installation which automatically ingest banks, financial institutes reports and generate account reconciliation entries, government reports automatically.

        I feel combined with machine learning and storing hledger records in some large databse, it can become a powerful automated accounting system which SAP and large vendors can just dream of.

      • smichael 5 years ago

        hledger power users (AFAIK) import most entries from CSV downloaded from financial institutions. I have this scripted to run nightly from cron, so the new entries are there awaiting finalisation when I open the journal in the morning.

    • smichael 5 years ago

      wtvanhest, not that I know of. It's hard to collect good usage data without nagging people. I hear from small business owners, the occasional accountant, and I have the impression there are other business/institutional users that don't interact.

      Distant future is hard to predict but here I go: hledger or any good parts of its design are still around and still providing value. Any past data kept with hledger is still readable and easy to convert, with or without a working hledger. Highly polished and efficient UIs are available everywhere they're useful. Data import and multimachine syncing are routine and just work. Data hygiene/security and personal privacy are routine and just work. Performance is high, "big data" is no problem. Resource usage is low, these tools continue to work in the turbulent and resource-constrained future. There is a strong global community of financially literate, capable, empowered, prospering individuals and organisations using efficient high quality universally available accounting tools to promote, enforce and create widespread transparency and societal insight in finance, business, politics and every ecological issue.

  • spindle 5 years ago

    Thank you for your work. (Does that count as a question?)

  • drieddust 5 years ago

    Thanks for this. A few questions comes to mind:

    1. What was the motivation to create this instead of extending ledger?

    2. How to track time?

  • doomrobo 5 years ago

    Are there any iOS apps that interop with hledger? I've been using iQIF [0] for a bit, but it only exports things in QIF format.

    [0] http://www.iqif.info/iQIF/

stevesimmons 5 years ago

These ledger formats have what feels to me an overly verbose multi-line structure for each transaction.

For 20 years, I have been using a format that combines a diary and ledger. The 'to' and 'from' accounts are either bank/asset accounts (sav, cc, hl for home loan, ...) or spend categories (snack, shopping, clothes, ... ). Each year I finish 31 December with a `# Closing balances` section for each bank/investment/pension account, then start a new text file `2019.txt` with an `# Opening balances` section before 1 January's entry.

Here is a typical day's format:

  # 2019-05-27 Mon
  2.50    sav>lunch    Cafe Nero - Coffee
  100.00  sav>cc       Transfer - Credit card repayment
  amt     from>to      forex: shop - desc [txn #] 
  # Diary
  * <topic> - <what>
  * Times - Sleep 01:00-06:00 5h. Run 45m. Work 08:00-18:00 10h.
  * Work - Meeting with xxx on xxx. We agreed to xxx.
  * Friends - Lunch with xxx
  * Note - Running shoes are Asics GT-2000, size 48, model T500N.
  # Links
  * Hledger: Robust plain text accounting - https://news.ycombinator.com/item?id=20012499
For the first 5 years, I was single and reconciled everything down to the cent, using an AWK script to generate totals to match against my bank statements.

When I got married, all our accounts switched to joint ones. I didn't want to track my my partner's side of our spending. So these logs became more a personal diary than a fully reconciled ledger. Anything I want to remember long-term goes either there or secured in a password safe.

  • kd5bjo 5 years ago

    You reinvented the accounting daybook: Shops doing paper accounting never went through the hassle of double-entry accounts for each sale. Instead, each was a single line in the day’s journal, and closing for the day involved reconciling the till with the sales journal, and entering the entire day’s revenue as a single transaction in the master account book.

  • fiatjaf 5 years ago

    I agree. They are too verbose. One line is enough.

    I actually think personal logs are useful for all things, not only money. In my business we use a text-file with logs for all the events, money, business stuff that happens, and then there's a program that reads all the lines, parses them and turns them into a final "state" of the company with everything that is being done and so on.

    From that we generate dashboards, reports and stuff.

    This is the system we use: https://github.com/fiatjaf/journalstate (but really the power is in the concept, not the implementation).

    I've also turned that into a TodoMVC app: https://journalstate-todomvc.alhur.es/, so you can see it in action in a fancy, useless way.

  • smichael 5 years ago

    hledger has builtin support for four formats so far (journal, timeclock, timedot, csv). The current journal format can be quite light:

      1/1
       (food)  5
      1/2
       (car)  15
    
    But I'll sometimes use csv for quick one-line entries:

      1/1,food,5
      1/2,car,15
    
    Some hledger users have their own custom formats like you, and use a script to preprocess it. More format experiments are always welcome.

    An advantage of something like hledger over a home-grown script is more robust and versatile reporting.

meruru 5 years ago

See also https://plaintextaccounting.org for more on the broader ledger ecosystem.

  • wodenokoto 5 years ago

    Which is also a really good introduction to accounting. I based my spreadsheet accounting on this guide.

    • smichael 5 years ago

      wodenokoto, may I ask which guide ?

AdamGibbins 5 years ago

Personally I prefer beancount, incredibly pluggable in python (imo a friendlier language to haskell), additionally much stricter in multiple aspects. Been maintaining my ledger with ledger-cli and then beacount for 10 years now.

  • dragonsh 5 years ago

    I am a user of both ledger-cli with emacs lisp bindings and beancount, fava with bank PDF statement preprocessing for journal entries. Used statistical inference to generate journal entries automatcomatically with tools like reckon (now use another one, as it's not maintained) and self written algorithms in Python with sci-kit learn. Works very well so far for over 6 years.

edwintorok 5 years ago

I've recently come across two systems that use hledger for processing bank statements: https://pauley.org.za/hledger-flow/ https://github.com/adept/full-fledged-hledger/wiki

They treat the statements as the single source of truth, with preprocessing and rules that can be used to turn them into hledger journals.

enriquto 5 years ago

I would appreciate a small section on the README file that explains how to compile the program, what are the requirements (e.g., what debian packages to install), and a minimal cli use case.

Also, running "make" prints a daunting 96 lines of text of which the last 50 (the ones that you get to see) are mostly useless. If I run "make build" it starts to download stuff from the internet, which I find extremely impolite, as I already downloaded the source code. What is the point of not including all the neeedded source code in the source distribution?

  • smichael 5 years ago

    Thanks for the feedback, I'll take a look at the README. Does http://hledger.org/download, prominently linked on the front page, have the right info ? My intention was for you to find that, so I'm curious how you travelled from this HN post to the README.

    PS: "make" prints its help, a summary of all targets. I agree it's more than a screenful and will need to be viewed with a pager (I'm used to viewing things in an emacs shell). The Makefile is assumed to be used mainly by contributors and does a lot. What would you recommend "make" to do ?

  • TomK32 5 years ago

    Haskell is a bit rare and so are its libraries rarely installed on systems. I can't remember, as arch has a proper package and I built hledger only once on a different system, but those downloads might be just libraries.

    • enriquto 5 years ago

      Whatever. Either they are dependencies that are required to be installed beforehand (just like a haskel compiler is required), or they are included in the source code distribution. Downloading them at compile time is very strange, and in my eyes unacceptable.

      • owaty 5 years ago

        It's not different from what pip install or gem install do by default.

        A mature Haskell project such as hledger has probably a few hundred of transitive dependencies, so you won't be able to install them individually by hand. You might try to figure whether each of them is packaged by your distribution (unlikely, unless hledger itself is packaged), but that's not a typical path — just don't use make in that case.

        • enriquto 5 years ago

          > It's not different from what pip install or gem install do by default.

          Pip installing required packages is alright. But I expect setup.py to NOT call pip install by itself.

          > A mature Haskell project such as hledger has probably a few hundred of transitive dependencies

          That's horrifying!

          • smichael 5 years ago

            Maybe so. :) It's also code reuse, actually working, and quite common for non-trivial end-user apps, particularly in the Haskell world. I'm not sure what kind of software you're used to. It's interesting to imagine how hledger would be different if I wrote everything myself, but I have to think it would be far less further along.

            • enriquto 5 years ago

              Thanks for your answer! I'm used to mostly C, C++ and Python projects. In the worst cases, when I download and compile a program I have to install two or three dependencies, and it is OK if I do it by hand. For an eminently unix-friendly program like hledger I was expecting a similar ease of installation (i.e., I have an arbitrary haskell compiler and I can just compile the program running "make"). But I was surprised that this is not the case; obviously the traditions of the haskell community are different. Yet, it seems very difficult to install this program in a controlled environment without internet access.

              • smichael 5 years ago

                Thanks. Well if we assume "arbitrary haskell compiler" means GHC and stack (or just stack), "make install" will compile it. But yes, there will be much downloading, unless you just happen to have all those haskell libs cached locally from previous builds.

                "stack install hledger" would compile just the command line tool (not the curses & web tools), so less downloading.

                For end-users who want minimum downloading/building, we recommend one of the binary packages on the download page (nix, docker, homebrew, windows/wine), but that's not you I think.

      • x3ro 5 years ago

        While I do see that this might be valuable, I find the argument strange and it makes me wonder in which area you work that this is so alien to you.

        I've generally come to expect that any software I download and try to build might, through a package manager, pull in additional dependencies (rust, Haskell, scala/Java/closure,...). The only real outliers here seem to be C and C++, of the ones I've worked with.

      • allannienhuis 5 years ago

        Almost every widely used modern language has a package manager ecosystem that does exactly this. How is that very strange? There are well debated pros and cons with the use of package managers of course, but to call it strange is, well, strange. :)

        • enriquto 5 years ago

          I'm used to Python's "pip install", but I have never seen it called from inside the "setup.py" of a particular program.

Nerada 5 years ago

Does Hledger support encrypting the ledger file? I don't mean placing the ledger in an encrypted container and mounting/unmounting as necessary, but I guess 'natively' as part of the file (think an encrypted Excel document).

I'm a GnuCash user, but my biggest gripe is not being able to encrypt my accounting file. I'd love to have it sync across my devices via x cloud platform, but I'm always paranoid about uploading anything that isn't password protected. If I was able to do that it'd be the push that gets me to switch from the GnuCash GUI to a plaintext account.

Maybe there's some other way I haven't thought of without a high barrier to entry like constantly mounting and unmounting an encrypted container to make changes.

  • Jtsummers 5 years ago

    Hledger just works on text files. You’d need some other system to keep them encrypted. I use KBFS which keeps things synced between my devices well enough.

  • icebraining 5 years ago

    You can use a syncing application that encrypts beforehand. The one I use is git-annex, which supports many cloud platforms (as well as plain SSH/FTP/SMB/etc), but there are others.

  • AdamGibbins 5 years ago

    beancount does, you can transparently encrypt your data.

    • dhruvkar 5 years ago

      is there any documentation for this?

  • YaxelPerez 5 years ago

    Just having the ledger in cryptomator works fine for me. Not sure how secure it is.

  • atmosx 5 years ago

    I use gitcrypt.

HorizonXP 5 years ago

I just spent the last week reconciling my books, using my scores of Excel files as a source, moving them to ledger.

I learned rudimentary double-entry accounting in high school, and I love that ledger enforces it so that I can be strict about my tracking. I still have to figure out how to produce balance sheets and income statements so that I can confirm that my accounts are balanced correctly. Honestly wish I had done this sooner.

Edit: Looking at beancount again, I should just use that instead of ledger. Ledger's simple, elegant, and nice, but I'm a Python guy, and I should just use what I know.

accrual 5 years ago

I've used the original ledger [0] for a few years to track my day-to-day cash flow and appreciate the simplicity. I create a new file every year and manage it with standard Unix tools, plus a few shell and Python wrappers to make entries and reports a little easier.

The hardest part is just getting started and getting into the habit of maintaining the ledger. Once you start tracking it's difficult to stop! Seeing all of your accounts line up is a reward in itself.

[0] https://www.ledger-cli.org

techntoke 5 years ago

hledger looks pretty amazing, but there are so many dependencies and updates with Haskell programs. Almost every other day I'm updating like 20 Haskell packages for hledger or pandoc when I run a system update. It isn't inherently bad, but never had this issue with a C or Go program.

  • smichael 5 years ago

    May I ask what system is that ?

    Maybe one of the other packaging methods will give you a more stable installation ? https://hledger.org/download

    • jeremyjh 5 years ago

      I'd bet money its Arch. I love `pacman` but the package spam for Haskell is a bit much as its automatically updating everytime a new package is hosted on hackage. I'd recommend skipping it all together, just use stack and build it from source, let stack manage GHC and you'll never update except when you want to.

      • Shoop 5 years ago

        To add some context to this, the reason why packages which depend on haskell in arch are such a mess is because "the arch way" is to dynamically link everything. This has its advantages (namely security), but is not super compatible with the haskell ecosystem which is designed with static linking in mind.

        Like my parent commenter, I recommend just doing everything through stack. stack-static from the AUR [0] is the convenient way to do this (rather than dragging in a few gigs of ghc dependencies for stack only to have stack create its own local ghc installation as well).

        [0] https://aur.archlinux.org/packages/stack-static/

        • bscphil 5 years ago

          If I'm not mistaken, Arch has some ornery maintainers in the Haskell department as well. Pandoc in particular used to have a static package, but now it can't be installed without pulling in a bunch of Haskell development packages. The maintainer in this case refused to fix the problem and closes all bug reports without comment.

          Fortunately there's https://aur.archlinux.org/packages/pandoc-bin/

      • maximente 5 years ago

        haskell is about the only thing on arch i'm not in love with. i also manually downloaded stack and am using it for xmonad/extensions/xmobar as well hledger now; it's been clean. highly recommended although it does use a lot of disk space - check out ~/.stack disk usage when time comes to pare down

      • techntoke 5 years ago

        Yes it is Arch. I'll check out the alternate way soon.

  • mark_l_watson 5 years ago

    I am just curious: why do you update so often? I will stick with a stack LTS version for many months, then update all my projects at once when I decide to update.

    Off topic, but as a student of Haskell for many years, I found reading (this morning) some of the code in the ‘tools’ directory of the github repo to be useful for picking up a few useful idioms.

  • baroffoos 5 years ago

    Why does this matter? Are you on a limited network where this is causing issues?

    • techntoke 5 years ago

      No one wants to upgrade 20+ libraries every couple of days just for a couple Haskell-specific packages. I am going to try some of the other solutions mentioned for now.

      • baroffoos 5 years ago

        You say that like its hard work to update. Just set up scheduled updates daily and you will never even know how many updates you get in a day.

        • dmos62 5 years ago

          In my experience automatic updates aren't great. If you're updating manually, you'll be in a much better position to handle problems when they arise, and more importantly these problems won't sneak up on you when you need your system the most, because you won't update unless you can afford the risk at that time.

ryanobjc 5 years ago

Hledger is pretty good for basic accounting. I recently had to do some tracking of stocks and lots and forex and the developers decided not to implement lot-based tracking. Which made it impossible to accurately track money.

So back to plain ledger. If I was starting over I'd probably consider beancount. But there's only so much I can do a day.

  • smichael 5 years ago
    • ryanobjc 5 years ago

      I have but I couldn't make it work. The issue seemed to boil down to "when do you price commodities?". Hledger doesn't let you report the price at the actual sale. The history flag didn't work I forget the reasons at this moment but if I recall correctly it boiled down to "price at market" type of features.

      That works fine for asset type accounts. But when we are taking about as-was accounting it doesn't work well enough. Beancount has some interesting ideas about lot tracking but switching cost is too high - I have years and 35k lines.

      • smichael 5 years ago

        What I mean is:

        - "The developers decided not to implement lot-based tracking" seems a misunderstanding. Perhaps "the developers have dragged their heels on exactly replicating Ledger's handling of lots" is more accurate (and I could justify that!).

        - we have never had sophisticated valuation/investment features, but there's a bunch of work in progress on this area right now; more flexible valuation (https://github.com/simonmichael/hledger/issues/329) is a current focus and needs testers..

        And, right now it should be possible to manage lots manually, similar to http://rantsideasstuff.com/posts/2018/07/01-tracking-investm... . It's a manual process in Ledger too after all. Let's chat in #hledger if you'd like.

z3t4 5 years ago

A ledger should be a database with only select and insert privileges. eg. No update or delete queries should be allowed.

  • p1necone 5 years ago

    If you're writing a ledger for your own personal record keeping, and not for some third party to be able to audit you wouldn't it be helpful to be able to keep history tidy and clean up mistakes without having to add extra entries?

  • repiret 5 years ago

    Yes in the sense that data shouldn't be destroyed, but you still need to be able to correct mistakes - those corrections just need to leave an audit trail.

  • dmos62 5 years ago

    That's a solved problem: git.

    • tty2300 5 years ago

      Git allows rewriting history though.

      • jolmg 5 years ago

        If you're sharing the repo, then you'll have to convince everyone to discard their copy of the original history and accept your modified version. And if that's done and everyone accepts the new history, the original can still be kept in each copy of the repo on another branch and the rewrite seen in the reflog. If commits are being signed, you can keep undeniable record of who contributed what in the original history, and who rewrote it.

        If the point is to forbid you to modify even when you're the only person working on it, any common database will allow you to update and delete when you enter with administrative privileges, so I don't see the difference.

      • dmos62 5 years ago

        But not by mistake, and it facilitates remote backups. I took this to be the problem parent was talking about.

mongol 5 years ago

I looked into plain text accounting but Swedish bookkeeping/accounting practises forbid practises where past records can be modified. It needs to be append-only. I started developing a command line accounting tool using SQLite and Go but it is only half-finished.

  • Someone 5 years ago

    Binary files can be rewritten, too.

    To check that the first N transactions in a file weren’t tampered with, you have to either compare each transaction with a backup, or hash them and compare the result with the hash you got earlier.

    If, as I suspect, this ledger is append-only, both are fairly simple. If the ledger, say, had 42 lines earlier, do either

        head -42 ledger | diff ledger.copy 
    
    (I’m not sure that’s valid shell, but you get the idea) or

        head -42 ledger | my-super-hash
    
    and compare the hash with one you got earlier.

    Also, some OS-es (e.g. Mac OS. See https://developer.apple.com/library/archive/documentation/Sy...) have the notion of append-only files. These, too do not safeguard against somebody rewriting the entire ledger, but they can make it harder to do that tampering.

    Finally, I haven’t thought it through, but possibly, you can create a user on your system for your accountant, set the owner of the ledger to that user, and make it impossible for anybody but that user to delete or replace the file.

    If that’s possible, it even would protect against reinstalling the system. You could recreate your accountant’s user ID, but not with the same password, so your accountant would still notice.

  • estsauver 5 years ago

    Git + Open Timestamps maybe?

    • magnamerc 5 years ago

      Or maybe gasp a blockchain.

kazinator 5 years ago

This is exactly how I do my accounting: record transactions in a plain text file, which is processed by the system, resulting in various ledger and account type objects being in a certain state, which can then be subject to queries and reports.

Mine is written in TXR Lisp. It is not released to the public.

All input is recorded via function call expressions, which are of course S-exps. There is only one single macro in the whole thing: def-date-var defines a variable that exhibits different values depending on a effective date context (established by a dynamically scoped date variable). With this we can do things like different tax rates for different periods, without having to introduce such things as parameters appearing in every input item.

> The amounts within a transaction must always sum up to zero. As a convenience, one amount may be left blank; it will be inferred so as to balance the transaction.

I also have transactions that sum to zero. There can be three or more account deltas in a transaction, not only two.

This is not how accounting is taught in North America, though; I came up with it myself.

Inferring one amount is a bad idea. My system throws an exception if the transaction amounts do not add to zero.

However, the entry of items is done via various convenience functions, most of which generate the necessary transactions against all the right accounts. For instance, recording a new asset:

  (record-asset 1 "Discombobulator" :cca-50 ;; ID, description, capital-cost-allowance class
                (date 2017 1 23) ($ 79.99) ($ 4.00) ($ 5.60)) ;; base price, GST, PST taxes.
From the looks of the journal format of hledger, it's too generic. I wouldn't want to use anything of the sort.

Different items need their own syntax. I don't want to record a simple purchase of a recurring expense in the same way that I record an invoice.

I bind a new variable when recording an invoice:

  (defparml %inv-0042%
    (new invoice
         number 42
         provider %my-addr%
         client %foo-client-addr%
         remit-to "Kazinator"
         remit-days 25
         date (date 2017 6 30)
         items (list (new time-unit
                          start (date 2017 6 1)
                          end (date 2017 6 2)
                          hours 16
                          rate %rate-foo-client-2017%)
                     (new time-unit
                          start (date 2017 6 5)
                          end (date 2017 6 9)
                          hours 40
                          rate %rate-foo-client-2017%)
                     (new time-unit
                          start (date 2017 6 12)
                          end (date 2017 6 16)
                          hours 40
                          rate %rate-foo-client-2017%)
                     (new time-unit
                          start (date 2017 6 19)
                          end (date 2017 6 23)
                          hours 40
                          rate %rate-foo-client-2017%)
                     (new time-unit
                          start (date 2017 6 26)
                          end (date 2017 6 30)
                          hours 40
                          rate %rate-foo-client-2017%))))
There is no custom DSL here at all; just the new macro of the object system.

This is then recorded using a plain function call to the convenience function record-invoice:

  (record-invoice %inv-0042% "Invoice 0042 issued to Foo, Inc.")
This function will digest the invoice and post the right amounts into various accounts. The GST tax has to be charged, and such,

When the invoice is paid:

  (record-paid-invoice %inv-0042% "Invoice 0042 paid by Foo, Inc."
                       (date 2017 7 31))
this function will also update multiple accounts, including the automatic withholding of income tax, based on the withholding rate configured for the date into which the invoice lands.

To generate a nice HTML invoice, at the REPL, I just call the .(html ...) method of the invoice object, which takes a stream argument.

  1> (with-stream (s (open-file "invoice.html" "w"))
       %inv-0042%.(html s))