Skip to content
A web-based reporting system for the Ledger command line accounting program
Branch: master
Clone or download
Pull request Compare This branch is 1 commit ahead, 8 commits behind peterkeen:master.
peterkeen Merge pull request #1 from peterkeen/master
Bring up to date with upstream
Latest commit dc7802a May 17, 2016
Type Name Latest commit message Commit time
Failed to load latest commit information.
bin Refactor user config loading May 18, 2012
lib Strip quotes Nov 12, 2015
test make pivot actually work Apr 13, 2013
.gitignore Add gems to the gitignore file Jan 1, 2012
.repo.yml Add .repo.yml Apr 25, 2014
LICENSE Add license file Jan 1, 2012 Remove user lib directory May 18, 2012
ledger_web.gemspec Add PDF support Jun 13, 2015

Ledger Web

Ledger Web is a web-based, postgresql-backed reporting system for the Ledger command-line accounting system. It is intended to be completely flexible, allowing you to write whatever reports you want. Note that Ledger Web requires PostgreSQL version 9.0 or greater.

To install:

$ gem install ledger_web
$ createdb ledger

To run:

$ ledger_web

From there, open up http://localhost:9090 in your browser and poke around. You'll see a few example reports.


Configuring Ledger Web is pretty simple. Create a file at ~/.ledger_web/config.rb that looks something like this: do |config|
  config.set :database_url, "postgres://localhost/ledger"

:database_url should point at your database instance. It doesn't have to be local, but the configured user needs to be able to alter the schema. There are a bunch more settings that you can set:

  • :index_report is the report that Ledger Web will redirect your browser to when you open it up the first time. Defaults to :help
  • :port is the port that Ledger Web will run on. Defaults to 9090
  • :ledger_file is the file that Ledger Web will read. Defaults to the LEDGER_FILE environment variable
  • :ledger_bin_path is the path to the ledger binary. Defaults to finding it in the PATH

Writing Reports

Reports are just HTML ERB files that live in ~/.ledger_web/reports. Ledger Web provides a few useful helpers that let you easily define SQL queries. Here's an example report:

<% @query = query do %>
    (account ~ 'Income'
    or account ~ 'Expenses')
    and xtn_date between :from and :to
group by
<% end %>
<%= table @query %>

The query helper takes a block of SQL and returns a LedgerWeb::Report instance. It can take a few options:

  • :pivot is the name of a column to pivot the report on.
  • :pivot_sort_order says how to order the resulting pivoted columns. Can be asc or desc. Defaults to asc.

Ledger Web uses Twitter Bootstrap for formatting, so you can use whatever you want to format your reports from there.

The table helper takes a query produced by the query helper and some options and builds an HTML table. Also, it can take a :links option which will linkify values in the table. Here's an example:

:links => {"Account" => "/reports/register?account=:1"}

This says that every value in the Account column will be surrounded with an <a> tag pointing at /reports/register?account=:1, where :1 will be replaced by the value in column 1 of that particular row. You can also use :title in a link template. It will get replaced with the title of the column that is currently getting linked. In this case, :title would get replaced with Account.


You can put Sequel migrations in ~/.ledger_web/migrate and they'll get applied as necessary at startup.


Ledger Web provides several different hooks that get run during the data load process.

  • :before_insert_row gets the Sequel database and the current row immediatley before insertion. Row is to be modified in place.
  • :after_insert_row gets the Sequel database and the current row. Row modifications don't matter.
  • :before_load gets the Sequel database
  • :after_load gets the Sequel database

To define a hook, put something like this in your config file:

config.add_hook :before_insert_row do |db, row|
  # modify the row in place


The base table is named ledger. Here's the DDL:

create table ledger (
    xtn_id integer,  -- line number of the first line of the transaction
    xtn_date date,   -- date of the transaction
    xtn_month date,  -- month pre-extracted from the date
    xtn_year date,   -- year pre-extracted from the date
    checknum text,   -- check number (code)
    note text,       -- payee
    account text,    -- account name
    commodity text,  -- commodity
    amount number,   -- amount
    tags text,       -- any tags attached to the transaction
    virtual boolean, -- if the transaction is virutal or not
    cleared boolean  -- if the transaction is cleared or not

In addition, there's a few predefined views:

create view accounts_months as
    _a as (select account from ledger group by account),
    _m as (select xtn_month from ledger group by xtn_month)
    _a cross join _m

create view accounts_days as
    _a as (select account from ledger group by account),
    _d as (select xtn_date from ledger group by xtn_date)
    _a cross join _d

create view accounts_years as
    _a as (select account from ledger group by account),
    _y as (select xtn_year from ledger group by xtn_year)
    _a cross join _y
You can’t perform that action at this time.