From mboxrd@z Thu Jan 1 00:00:00 1970 From: Stefan Huchler Subject: org-capture template to type in bills from shops in ledger format Date: Sun, 02 Jun 2019 02:05:04 +0200 Message-ID: <87woi4rgwf.fsf@mail.de> Mime-Version: 1.0 Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: 8bit Return-path: Received: from eggs.gnu.org ([209.51.188.92]:57109) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1hXEBj-0002fO-Vd for emacs-orgmode@gnu.org; Sat, 01 Jun 2019 20:17:29 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1hXDzu-0007v6-GC for emacs-orgmode@gnu.org; Sat, 01 Jun 2019 20:05:15 -0400 Received: from [195.159.176.226] (port=35864 helo=blaine.gmane.org) by eggs.gnu.org with esmtps (TLS1.0:RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1hXDzu-0007ub-9u for emacs-orgmode@gnu.org; Sat, 01 Jun 2019 20:05:14 -0400 Received: from list by blaine.gmane.org with local (Exim 4.89) (envelope-from ) id 1hXDzr-0000GY-Ch for emacs-orgmode@gnu.org; Sun, 02 Jun 2019 02:05:11 +0200 List-Id: "General discussions about Org-mode." List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: emacs-orgmode-bounces+geo-emacs-orgmode=m.gmane.org@gnu.org Sender: "Emacs-orgmode" To: emacs-orgmode@gnu.org 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