Skip to content

eikek/org-expenses

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

9 Commits
 
 
 
 
 
 
 
 
 
 

Repository files navigation

org-expenses.el

Tracking expenses in org files works very well. The org capture mechanism can be used to quickly insert them. This library provides utility functions to generate basic statistics from expense lists.

It assumes the following conventions:

  • expense items are headings, to be able to apply tags and
  • properties where one is a currency code - price pair
  • a :date: property or a date string somewhere undere the headline (not really required, but used to search expenses by date)

An expense item is a headline that complies to those points. Expense items can have one category, which is by default the name of the parent headline. This can be overriden by the CATEGORY property.

The date of the expense item is either given by the :date: property or the first date that is found underneath the headline.

The following example shows two expense items that are organized below a “food” headline, which serves as their default category. The second item overrides this category to “restaurant”.

* food
** groceries
   :PROPERTIES:
   :usd:   25.49
   :date:  [2014-08-14 Do]
   :END:
** pizza
   :PROPERTIES:
   :usd:       18.99
   :date:      [2014-08-25 Mo]
   :CATEGORY:  restaurant
   :END:

All those items are gathered from some org files and tables are generated to show an overview of the data.

The standard overview for the last example would look like this:

#+TITLE: Expenses [2014-08-14 Do] - [2014-08-25 Mo]
#+STARTUP: showeverything

Search: ~(:date "2014-08")~
Showing *2* items

* Overview
** Summary
| Curr. |   sum |   max |   min | count |   avg |
|-------+-------+-------+-------+-------+-------|
| USD   | 44.48 | 25.49 | 18.99 |     2 | 22.24 |


** Categories
|                |   sum |   max |   min | count |   avg |
|----------------+-------+-------+-------+-------+-------|
| restaurant USD | 18.99 | 18.99 | 18.99 |     1 | 18.99 |
| food USD       | 25.49 | 25.49 | 25.49 |     1 | 25.49 |


** Monthly
|             |   sum |   max |   min | count |   avg |
|-------------+-------+-------+-------+-------+-------|
| 2014/08 USD | 44.48 | 25.49 | 18.99 |     2 | 22.24 |


* Items
| item      | category   | date            |   USD |
|-----------+------------+-----------------+-------|
| pizza     | restaurant | [2014-08-25 Mo] | 18.99 |
| groceries | food       | [2014-08-14 Do] | 25.49 |

Installation

Clone this repository and add it to emacs load path. Then require the file:

(require 'org-expenses)

Configuration

If you have files with expense items, you can set them in your init file. Either specify a list of files or just a string which then should be a directory containing org files. All of them are considered.

(setq org-expenses/files "~/org/expenses")

Then it might be convenient to assign a key to the org-expenses/expense-view function. It shows the summary to those files.

Since these files can grow quickly but usually don’t change often, there is a cache mechanism provided. It uses sqlite3 and stores expense items in a database file. If a file changes, it is simply re-added. You can set the sqlite3 executable if it differs from /usr/bin/sqlite3. Then you must provide a file location for the database file, otherwise the cache is disabled.

(setq org-expenses/sqlite-cmd "/usr/local/bin/sqlite3")
(setq org-expenses/sqlite-db-file "~/.expenses.db")

As described above, only headlines with a currency-price property are considered. The list org-expenses/currency-list names all known currencies.

Expense View Mode

The function org-expense/expense-view reads the org files and displays a buffer with summary information of the expenses. It is set to “epxense-view-mode” that is org mode but with a custom keymap that makes more sense for this buffer:

KeyBinding
RETorg-expenses/expense-view-jump-to-entry
C-norg-expenses/expense-view-move-next
C-porg-expenses/expense-view-move-prev
C-torg-expenses/expense-view-toggle-table
+org-expenses/expense-view-widen-date
-org-expenses/expense-view-narrow-date
.org-expenses/expense-view-goto-this-month
/org-expenses/expense-view-search-item
Corg-expenses/expense-view-search-remove-category
Forg-expenses/expense-view-toggle-follow-entries
Torg-expenses/expense-view-search-remove-tag
borg-expenses/expense-view-prev-date
corg-expenses/expense-view-search-add-category
dorg-expenses/expense-view-search-date
forg-expenses/expense-view-next-date
gorg-expenses/expense-view-update-view
lorg-expenses/expense-view-last-search
norg-expenses/expense-view-move-next
porg-expenses/expense-view-move-prev
qorg-expenses/expense-view-quit-window
torg-expenses/expense-view-search-add-tag
vorg-expenses/expense-view-focus-item
<down>org-expenses/expense-view-move-next
<up>org-expenses/expense-view-move-prev

If this function is invoked with one prefix argument, it will clear the sqlite db first (if it is used). With two prefix arguments the expense view is generated for the current buffer (which must be in org mode).

This buffer is divided in two parts: the first shows a list of tables with summary information, and the second is the item table. Both can be configured a little. The variable org-expenses/overview-table is bound to an alist with headline - function pairs. Each function is expected to take a result list and return a summary table to display. The headline and table is inserted into the buffer. And org-expenses/item-columns is a list containing property keys of an expense item that are used as columns. It defaults to (:item :category :date).

Selecting expense items in the view is done via a plist that contains 4 things: a date range (key :date), an item name (key :item), a tag list (key :tags) and a category list (key :category). A date range can be an org date range like [2014-05-10]--[2014-05-20] or an abbreviated one like 2014-05. The latter is the short version for [2014-05-01]--[2014-05-31]. And likewise, 2014 is short for [2014-01-01]--[2014-12-31]. Items must match to all given criteria. Tags and categories can be included by specifying them and execluded by prefixing the names with a -. Item names are substring matches. For example (:date 2014-08 :tags ("-train" "journey")) would find all items from august 2014 that are tagged with “journey” but not with “train”.

Other interactive things

There are two functions

  • org-expense/insert-item-table that asks for a search plist and inserts a table with all matching items
  • org-expense/insert-summary-table same as above but inserting a summary table of the result. If a grouping function is specified, the result is grouped first. There are some predefined org-expenses/group-by… functions that can be used.

License

This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version.

Releases

No releases published

Packages

No packages published