emacs-orgmode@gnu.org archives
 help / color / mirror / code / Atom feed
From: Ben Alexander <bva-y2PnNNZjvYes2hfZNXnO90B+6BGkLq7r@public.gmane.org>
To: ledger-cli-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org,
	emacs-orgmode Org-Mode
	<emacs-orgmode-mXXj517/zsQ@public.gmane.org>
Subject: org-mode and ledger cli accounting
Date: Wed, 17 Dec 2008 22:29:40 +0000	[thread overview]
Message-ID: <1E08E93A-0F48-49D6-A486-41D0E5444BE6@alexanderonline.org> (raw)


*** org-mode and ledger cli accounting - two great tastes that taste  
great together
     :PROPERTIES:
     :COLUMNS:  %16LEDGER_DATE %5LEDGER_REFERENCE %10ITEM  
%25LEDGER_ACCOUNT %10AMOUNT
     :END:

***** TODO Email the org-mode and ledger mailing lists

       I'm starting to use 'ledger' (http://www.newartisans.com/software/ledger.html 
).  There is an emacs mode for editing the native plain text file  
format, but I really like the org-mode UI. Date handling is great  
(imho) and column mode holds some promise (although I find it awkward  
to add a new headline while in column mode). And remember templates  
could ease data entry, too

I think it would be great to use 'ledger' backend computation and org- 
mode's UI together!

       After a quick exchange of emails where I asked about the future  
plans of 'ledger' I was told that a new file format for 'ledger' could  
be added, if the org-mode community decided on a common format.

       I'd like to suggest a format, get some feedback on it, and get  
a sense of how many others are interested.  I'm hoping to interest org- 
mode users in ledger, and ledger users in org-mode!

       As a temporary measure, I've used the org-map-entries API to  
iterate over entries looking for properties of the form "LEDGER_.*" to  
extract the appropriate details, format them like the current plain  
text 'ledger' file.

       Since there's a lot about 'ledger' I don't know (as well as  
elisp, org-mode, git, programming in general, accounting) I'd expect  
that my code will be ineffecient, inelegant, and dangerous.  It comes  
with no warrenty. If you have some programming skills, I'd appreciate  
feedback on style, design, tests and documentation.

       For example, I'd like to use a :LEDGER: drawer instead of  
polluting the :PROPERTIES: namespace, but then I'd miss out on the  
easy org-entry-get API.  Any suggestions?

Here's an example tree, with a column-mode definition above, and a  
single minimal entry below.  Here's how to use it at the moment  
(caveat, I wrote this assuming you already have ledger (the shell  
program) downloaded and ledger.el in your loaded into emacs.

***** How to use the sample code and data
1. In the file bens-org-ledger.el, modify the variable bens-org-ledger- 
file-name to point to a file you don't mind overwriting without  
warning. (Did I mention that my code might be dangerous?)
2. Load bens-org-ledger.el
3. Run the defun (bens-org-ledger) while the current buffer contains  
this org-tree
4. Now (find-file bens-org-ledger-file-name). In my setup, the  
extension automaticaly loads ledger.el and the file is in ledger-mode.
5. C-c C-o C-r reg <RET> in a ledger-mode buffer (visting a native  
ledger file) will run a basic register report.  Try C-c C-o C-r bal  
<RET> for a basic balance report.


***** Wegman's
       :PROPERTIES:
       :LEDGER: entry
       :LEDGER_DATE: [2008-11-07 Fri]
       :LEDGER_REFERENCE: chq 1001
       :END:
*******
         :PROPERTIES:
         :LEDGER: transaction
         :LEDGER_ACCOUNT: Expenses:Food and Drink:Groceries
         :LEDGER_AMOUNT: -£10.00
         :END:
         Since all text except the headline and specific properties is
         ignored, I can comment my transactions with body text!
******* Assets:Checking
         :PROPERTIES:
         :LEDGER: transaction
         :LEDGER_DATE: [2008-11-13 Thu]
         :END:

         Instead of using the :LEDGER_ACCOUNT: property, I can use the
         headline.  Properties come with completion (big win!) but
         headlines are easier to see outside of column mode.

         Also, in this case, the :LEDGER_DATE: property is ignored.
         Maybe it should become the 'effective date' in the future?


*** This is my lisp code, from a file named bens-org-ledger.el
It starts from the comments below to the end of the message.  I'm  
sorry to be wordy but I thought having something that could be used  
(even awkwardly) would jump start the conversation

;; I'm naming every function I can with the bens-org-ledger prefix,
;; because these are temporary, pre-alpha attempts, intended to
;; elict comments from real programmers
;;
;; This code is copyright Ben Alexander
;; You have license to use, copy, and create derivative works
;; under the terms of the General Public License (version 2 or later).
;;
(defvar bens-org-ledger-file-name "bens-org-ledger-sample.ledger"
  "This variable is the name of a file that will be overwritten during  
the processing of an org-mode file.  OVERWRITTEN WITHOUT WARNING!") ;;  
except for this warning here


(defun bens-org-ledger-create-entry ()
    "this function retreives the LEDGER_DATE, LEDGER_REFERENCE (if it
    exists), and the LEDGER_DESCRIPTION properites of the current
    headline and formats them as the beginning of a new ledger entry"

    (concat
       "\n" ;; a blank line separates ledger entries
       (format-time-string "%Y/%m/%d"
          (org-time-string-to-time (org-entry-get (point)  
"LEDGER_DATE") ) t)
       ;; Wouldn't it be nice if the timestamps repeat intervals were  
converted
       ;; to appropriate ledger syntax here?  Does org-mode have some  
timestamp
       ;; property retrievals I could use?
       ;;
       ;; Also, I need to add support for "effective dates"

       (if (> (length (org-entry-get (point) "LEDGER_REFERENCE")) 0)
          (concat " (" (org-entry-get (point) "LEDGER_REFERENCE") ") ")
          " ")
       (or (org-entry-get (point) "LEDGER_DESCRIPTION") (org-get- 
heading))
       "\n" ;; I assume the cursor starts on a newline -- make it so!
    )
)

(defun bens-org-ledger-create-transaction ()
    "this function retreives the LEDGER_ACCOUNT (or headline),  
LEDGER_AMOUNT
    and formats them as a continuation of the existing ledger entry"

    (concat
       " "  ;; ledger transactions must begin with whitespace
       (or (org-entry-get (point) "LEDGER_ACCOUNT")
           (org-get-heading))
       "  "  ;; two spaces separate account name from amount
       (org-entry-get (point) "LEDGER_AMOUNT")
       "\n" ;; I assume the cursor starts on a newline -- make it so!
    )
)


(defun bens-org-ledger-map-entries-helper ()
   "this function passed to org-map-entries to format headlines to  
ledger style
    plain text.  It chooses bens-org-ledger-create-entry or
    bens-org-ledger-create-transation based on the LEDGER property.   
Those functions
    return the actual data that org-map-entries collects"
(cond ((string= (org-entry-get (point) "LEDGER") "entry") (bens-org- 
ledger-create-entry))
       ((string= (org-entry-get (point) "LEDGER") "transaction") (bens- 
org-ledger-create-transaction))
))


(defun bens-org-ledger ()
    "this function generates a properly formatted ledger file from the  
org-mode headlines based on properties stored in the org-mode property  
drawer.  The file refered to by bens-org-ledger-file-name is  
OVERWRITTEN WITHOUT WARNING. (you have been warned, again)

The properties used are of the form LEDGER_.*

:LEDGER: entry|transaction  => entries (headings) contain transactions  
(sub-headings)
For ledger entries, the following properties are used
:LEDGER: entry        => Means this is the beginning of a new ledger  
entry.
                          Entries (in the parlance of ledger) may  
contain
                          multiple transactions

:LEDGER_DATE: <2009-01-01 Thu> => An org-mode timestamp.

:LEDGER_REFERENCE: chq 101 => There's a place for this in the ledger  
syntax.
                               Any string is legal.

:LEDGER_DESCRIPTION:   => if this is missing, the org-mode headline is  
used

For ledger transactions, the follwoing properties are used

:LEDGER: transaction  => Means this headline is a transaction.
                          It should be a sub-heading of some 'entry'

:LEDGER_ACCOUNT:      => a colon:delimited:account:as:used:by:ledger
:LEDGER_AMOUNT: £10  => Any legal amount for ledger.
                          Any currency symbol or code is considered  
legal, e.g.
:LEDGER_AMOUNT: 10 GBP
:LEDGER_AMOUNT: $10
:LEDGER_AMOUNT: 10 STICKS_OR_STONES
"

   (interactive)
   (let ((ledger-text (org-map-entries 'bens-org-ledger-map-entries- 
helper "+LEDGER={transaction\\\|entry}")))
   (with-temp-file bens-org-ledger-file-name (dolist (str ledger-text)  
(insert str)))
   ))

                 reply	other threads:[~2008-12-17 22:29 UTC|newest]

Thread overview: [no followups] expand[flat|nested]  mbox.gz  Atom feed

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

  List information: https://www.orgmode.org/

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=1E08E93A-0F48-49D6-A486-41D0E5444BE6@alexanderonline.org \
    --to=bva-y2pnnnzjvyes2hfznxno90b+6bgklq7r@public.gmane.org \
    --cc=emacs-orgmode-mXXj517/zsQ@public.gmane.org \
    --cc=ledger-cli-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
Code repositories for project(s) associated with this public inbox

	https://git.savannah.gnu.org/cgit/emacs/org-mode.git

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).