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 |