emacs-orgmode
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[O] org-capture template to type in bills from shops in ledger format


From: Stefan Huchler
Subject: [O] org-capture template to type in bills from shops in ledger format
Date: Sun, 02 Jun 2019 02:05:04 +0200
User-agent: Gnus/5.13 (Gnus v5.13) Emacs/26.1 (gnu/linux)

I wrote this template to capture my bills from mostly one shop, but it
has support for multiple shops and the important feature is that it
suggests previous item names and remembers last prices, that gives you
lot's of autocompletion if you repetetivly buy often the same stuff over
and over again.

#+begin_src emacs-lisp
%(let* ((default-directory (file-name-directory "%F"))
        (map-file "shop-items.txt"))
   (load-file "helper.el")
   (require 'dash)
   (let* ((shops (if (file-exists-p map-file)
                     (read-from-file map-file) '()))
          (names (mapcar 'car shops))
          (shop-name (ido-completing-read "Shop: " names nil nil nil))
          (new-prices) (new-names) (new-amounts)
          (products (assoc-default shop-name shops)))
     (while (let* ((names (mapcar 'car products))
                   (name (ido-completing-read "Name: " names))
                   (amount (read-number "Amount: " 1))
                   (item (alist-get name products))
                   (item (if (stringp item) (string-to-number item) item))
                   (price (read-number "Price: " (or item 2.00))))
              (setq new-names (append new-names (list name)))
              (setq new-prices (append new-prices (list price)))           
              (setq new-amounts (append new-amounts (list amount)))
              (y-or-n-p "More items? ")))
     (let* ((-compare-fn (lambda (x y) (equal (car x) (car y))))
            (new-products (mapcar* 'cons new-names new-prices))
            (combined-products (-distinct (append new-products products)))
            (combined-shops (-distinct (append `((,shop-name . 
,combined-products)) shops)))
            (format-string "      expenses:food:%s \t\t%s St @ =€%s")
            (format-function (lambda (name amount price)
                               (format format-string name amount price)))
            (product-lines (mapcar* format-function new-names
                                             new-amounts new-prices))
            (shopping-items (s-join "\n" product-lines))
            (total (reduce '+ (mapcar* '* new-amounts new-prices))))
       (print-to-file map-file combined-shops)
       (concat (format "  %(org-read-date nil nil) * %s\n%s"
                       shop-name shopping-items)
               (format "\n      assets:bank:chequing\t\t€-%s"
                       (read-string "Total: " (format "%.2f" total)))))))
#+end_src

Any thoughts? It's supposed to output into a org file with a embeded
ledger src block so you would have to check the alignment if you would
want to output to a normal ledger file.

here are the 2 functions from helper.el:

#+begin_src emacs-lisp
(defun print-to-file (filename data)
  (with-temp-file filename
    (let* ((print-length 5000))
      (prin1 data (current-buffer)))))

(defun read-from-file (filename)
  (with-temp-buffer
    (insert-file-contents filename)
    (cl-assert (eq (point) (point-min)))
    (read (current-buffer))))
#+end_src

Maybe that's useful for somebody else or somebody wants to suggest other
features or something. The only thing I would maybe consider to switch
is to use a json format for the shop-items.txt for the prices for easier
manual editing.

that's how I set it up:

#+begin_src emacs-lisp
("s" "(S)hopping" plain
         (file+function "path/finances.org"
                        (lambda () ""
                          (progn (org-babel-goto-named-src-block "balance")   
                                 
(org-babel-goto-src-block-head)(forward-line))))
         "%[~/capture-templates/template-name]" 
         :jump-to-captured t
         :empty-lines-after 1
         :immediate-finish nil)
#+end_src         




reply via email to

[Prev in Thread] Current Thread [Next in Thread]