Hacker News new | ask | show | jobs
by shoover 2688 days ago
Interesting use of orgmode as a database. How does it work? Does that use a built in agenda functionality or are you calling lower level org functions to query your agenda files and enumerating the results to generate the table as text in another buffer?
1 comments

I use proper org-mode functions to query the built-in agenda and then group entries by org-mode tags. My code expects a configuration that maps tags to their line item names (as on invoice), hourly rates and applicable tax. I use this to output a dynamic[0] table like this:

   | Tag             | Invoice line name     | Hours |  Rate |    Net | VAT % | VAT amount |  Total |
   |-----------------+-----------------------+-------+-------+--------+-------+------------+--------|
   | meeting         | Meetings              |    10 | 12.00 | 120.00 | NP    |       0.00 | 120.00 |
   | procrastinating | Important tasks       |    20 | 13.00 | 260.00 | NP    |       0.00 | 260.00 |
   | hn              | Other important tasks |    40 | 14.00 | 560.00 | NP    |       0.00 | 560.00 |
   | coding          | Occasional code       |     3 | 15.00 |  45.00 | NP    |       0.00 |  45.00 |
   |-----------------+-----------------------+-------+-------+--------+-------+------------+--------|
   | Totals          | -                     |    73 |     - | 985.00 | -     |       0.00 | 985.00 |
   #+TBLFM: @>$3=vsum(@2..@-1)::@>$5=vsum(@2..@-1);%.2f::@>$7=vsum(@2..@-1);%.2f::@>$8=vsum(@2..@-1);%.2f::$5=$3*$4;%.2f::$7=if(typeof($6) < 10, $5*$6, 0);%.2f::$8=$7+$5;%.2f
The #+TBLFM: line at the bottom is org-mode spreadsheet functionality; it ensures I can modify the table text in-place, and just press C-c C-c to recalculate all values in it. I generate a similar table with data for invoices; some taken from my configuration, some computed (e.g. invoice number is generated by looking at filenames of previous invoices; sale date and service period are estimated from current date and the time range you specified when generating line items table, etc.).

The code for generating above table is hand-crafted. While org-mode provides you a generator for agenda tables based on TODO item name - see [1], I had to write similar feature that aggregated time by org-mode tags. I used [2] as a reference, but essentially wrote my own implementation. Surprisingly, it turned out to be almost trivial.

Then, it's simply a matter of turning those two org-mode tables into an elisp list of keys and values. This I accomplish using a simple elisp that uses built-in Emacs calls:

  (defun trc-invoicing--named-table-to-lisp (name)
    "Convert a named org mode table in the current buffer into a list.
  The function finds a table named `NAME', passes it through `ORG-TABLE-TO-LISP',
  and return the result. Refer to the documentation of `ORG-TABLE-TO-LISP'
  for info about result's shape."
    (save-excursion
      (goto-char (point-min))
      (search-forward (format "#+NAME: %s" name))
      (forward-line)
      (org-table-to-lisp)))
Then it's a matter of populating a LaTeX template with extracted values, invoking pdflatex, and copying the resulting PDF in an appropriate place. That last part I yet have to finish.

It's the biggest piece of elisp I wrote since Nyan Mode, but all in all, I find it surprisingly easy to code for Emacs. Availability of source code, extensive in-editor documentation and built-in source-level debugger make this process pretty pleasant.

--

[0] - Org Mode has a concept of "dynamic blocks". You type in #+BEGIN: blockname some params, and then using C-c C-c on it causes Org Mode to invoke an elisp function named org-dblock-write:blockname. The called function is then responsible for outputting contents of the dynamic block.

[1] - http://orgmode.org/manual/The-clock-table.html

[2] - https://gist.github.com/tsu-nera/d9ffa6a51a6e7bdb957b

Very nice, thanks for the tutorial. I see that TBLFM saves some coding vs. the gist in [2].
Thanks!

To be clear, the TBLFM there has a separate purpose. My implementation of [2] generates a table with appropriate shape and data items; TBLFM computes sums and products. This allows for manually modifying the table (e.g. adding a line item, rounding off hours, changing them to include tine you don't track in org mode) and having the sums and products recalculated.

(Also, for anyone scared by that TBLFM line noise, Emacs has a way to edit it in more readable form.)