Added rudimentary target checking to reconcile.

This commit is contained in:
Craig Earls 2013-02-13 15:53:16 -07:00
parent 15d838d1f8
commit d31913871f
4 changed files with 152 additions and 11 deletions

View file

@ -2542,7 +2542,7 @@ all of the uncleared transactions. The reconcile buffer has several functions:
@table @code
@item SPACE
toggles the cleared status of a transaction, and show cleared balance inthe minibuffer
toggles the cleared status of a transaction, and shows pending balance in the mini-buffer
@item RETURN
moves the cursor to that transaction in the ledger.
@item C-x C-s
@ -2555,6 +2555,8 @@ all of the uncleared transactions. The reconcile buffer has several functions:
add entry
@item D
delete entry
@item t
change target reconciliation amount
@item g
reconcile new account
@item b
@ -2570,6 +2572,14 @@ show all transaction meeting the regex, cleared or not. This behavior
can be disabled by setting @code{ledger-fold-on-reconcile} to nil in the
emacs customization menus.
When you reconcile an account you nromally know the final balance you
are aiming at. When you enter the reconciliation mode ledger will ask
for a target balance. Enter the amount you are aiming for (the default
commodity can be chaged in the customization window). Each time you
toggle a posting to pending, ledger will calculate the new balance of
the account and display the new balance and the difference to make the
target.
@node Generating Reports, , Reconciling accounts, Using EMACS
@subsection Generating Reports

93
lisp/ldg-commodities.el Normal file
View file

@ -0,0 +1,93 @@
;;; ldg-commodities.el --- Helper code for use with the "ledger" command-line tool
;; Copyright (C) 2003-2013 John Wiegley (johnw AT gnu DOT org)
;; This file is not part of GNU Emacs.
;; This 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 2, or (at your option) any later
;; version.
;;
;; This is distributed in the hope that it will be useful, but WITHOUT
;; ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
;; FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
;; for more details.
;;
;; You should have received a copy of the GNU General Public License
;; along with GNU Emacs; see the file COPYING. If not, write to the
;; Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
;; MA 02111-1307, USA.
;; A sample entry sorting function, which works if entry dates are of
;; the form YYYY/mm/dd.
;;; Commentary:
;; Helper functions to deal with commoditized numbers. A commoditized
;; number will be a cons of value and string where the string contains
;; the commodity
;;; Code:
(defcustom ledger-reconcile-default-commodity "$"
"the default commodity for use in target calculations in ledger reconcile"
:type 'string
:group 'ledger)
(defun ledger-string-balance-to-commoditized-amount (str)
(let ((fields (split-string str "[\n\r]"))) ; break any balances
; with multi commodities
; into a list
(mapcar '(lambda (str)
(let* ((parts (split-string str)) ;break into number and commodity string
(first (car parts))
(second (cadr parts)))
;"^-*[1-9][0-9]*[.,][0-9]*"
(if (string-match "^-*[1-9]+" first)
(list (string-to-number first) second)
(list (string-to-number second) first))))
fields)))
(defun -commodity (c1 c2)
(if (string= (cadr c1) (cadr c2))
(list (- (car c1) (car c2)) (cadr c1))
(error "Can't subtract different commodities %S from %S" c2 c1)))
(defun +commodity (c1 c2)
(if (string= (cadr c1) (cadr c2))
(list (+ (car c1) (car c2)) (cadr c1))
(error "Can't add different commodities, %S to %S" c1 c2)))
(defun ledger-commodity-to-string (c1)
(let ((val (number-to-string (car c1)))
(commodity (cadr c1)))
(if (> (length commodity) 1)
(concat val " " commodity)
(concat commodity " " val))))
(defun ledger-read-commodity-string (comm)
(interactive (list (read-from-minibuffer
(concat "Enter commoditized amount (" ledger-reconcile-default-commodity "): "))))
(let ((parts (split-string comm)))
(if parts
(if (/= (length parts) 2) ;;assume a number was entered and use default commodity
(list (string-to-number (car parts))
ledger-reconcile-default-commodity)
(let ((valp1 (string-to-number (car parts)))
(valp2 (string-to-number (cadr parts))))
(cond ((and (= valp1 valp2) (= 0 valp1));; means neither contained a valid number (both = 0)
(list 0 ""))
((and (/= 0 valp1) (= valp2 0))
(list valp1 (cadr parts)))
((and (/= 0 valp2) (= valp1 0))
(list valp2 (car parts)))
(t
(error "cannot understand commodity"))))))))
(provide 'ldg-commodities)
;;; ldg-commodities.el ends here

View file

@ -46,6 +46,8 @@
(require 'ldg-sort)
(require 'ldg-fonts)
(require 'ldg-occur)
(require 'ldg-commodities)
(autoload #'ledger-texi-update-test "ldg-texi" nil t)
(autoload #'ledger-texi-update-examples "ldg-texi" nil t)

View file

@ -24,6 +24,7 @@
(defvar ledger-buf nil)
(defvar ledger-bufs nil)
(defvar ledger-acct nil)
(defvar ledger-target nil)
(defcustom ledger-recon-buffer-name "*Reconcile*"
"Name to use for reconciliation window"
@ -54,19 +55,42 @@
:type 'boolean
:group 'ledger)
(defun ledger-reconcile-get-balances ()
"Calculate the cleared and uncleared balance of the account being reconciled,
return a list with the account, uncleared and cleared balances as numbers"
(interactive)
(let ((buffer ledger-buf)
(account ledger-acct)
(val nil))
(with-temp-buffer
(ledger-exec-ledger buffer (current-buffer)
; note that in the line below, the --format option is
; separated from the actual format string. emacs does not
; split arguments like the shell does, so you need to
; specify the individual fields in the command line.
"balance" "--limit" "cleared or pending"
"--format" "(\"%(amount)\")" account)
(setq val (read (buffer-substring-no-properties (point-min) (point-max)))))))
(defun ledger-display-balance ()
"Calculate the cleared balance of the account being reconciled"
(interactive)
(let ((buffer ledger-buf)
(account ledger-acct))
(with-temp-buffer
(ledger-exec-ledger buffer (current-buffer) "balance" "--limit" "cleared or pending" account)
(goto-char (1- (point-max)))
(goto-char (line-beginning-position))
(delete-horizontal-space)
(message "Current pending balance = %s"
(buffer-substring-no-properties (point)
(line-end-position))))))
(let* ((pending (car (ledger-string-balance-to-commoditized-amount
(car (ledger-reconcile-get-balances)))))
(target-delta (if ledger-target
(-commodity ledger-target pending)
nil)))
(if target-delta
(message "Pending balance: %s, Difference from target: %s"
(ledger-commodity-to-string pending)
(ledger-commodity-to-string target-delta))
(message "Pending balance: %s"
(ledger-commodity-to-string pending)))))
(defun is-stdin (file)
"True if ledger file is standard input"
@ -323,6 +347,8 @@ Spliting the windows of BUF if needed"
(if ledger-fold-on-reconcile
(ledger-occur-change-regex account ledger-buf))
(set-buffer (get-buffer ledger-recon-buffer-name))
(setq ledger-target
(call-interactively #'ledger-read-commodity-string))
(unless (get-buffer-window rbuf)
(ledger-reconcile-open-windows buf rbuf))
(ledger-reconcile-refresh))
@ -337,10 +363,18 @@ Spliting the windows of BUF if needed"
(ledger-reconcile-mode)
(set (make-local-variable 'ledger-buf) buf)
(set (make-local-variable 'ledger-acct) account)
(set (make-local-variable 'ledger-target)
(call-interactively #'ledger-read-commodity-string))
(ledger-do-reconcile))))))
(defvar ledger-reconcile-mode-abbrev-table)
(defun ledger-reconcile-change-target ()
(setq ledger-target (call-interactively #'ledger-read-commodity-string)))
; (setq ledger-target
; (if (and target (> (length target) 0))
; (ledger-string-balance-to-commoditized-amount target))))
(defun ledger-reconcile-display-internals ()
(interactive)
(message "%S %S" ledger-acct ledger-buf))
@ -358,6 +392,7 @@ Spliting the windows of BUF if needed"
(define-key map [?g] 'ledger-reconcile);
(define-key map [?n] 'next-line)
(define-key map [?p] 'previous-line)
(define-key map [?t] 'ledger-reconcile-change-target)
(define-key map [?s] 'ledger-reconcile-save)
(define-key map [?q] 'ledger-reconcile-quit)
(define-key map [?b] 'ledger-display-balance)
@ -376,6 +411,7 @@ Spliting the windows of BUF if needed"
(define-key map [menu-bar ldg-recon-menu tog] '("Toggle Entry" . ledger-reconcile-toggle))
(define-key map [menu-bar ldg-recon-menu sep3] '("--"))
(define-key map [menu-bar ldg-recon-menu bal] '("Show Cleared Balance" . ledger-display-balance))
(define-key map [menu-bar ldg-recon-menu tgt] '("Change Target Balance" . ledger-reconcile-change-target))
(define-key map [menu-bar ldg-recon-menu sep4] '("--"))
(define-key map [menu-bar ldg-recon-menu rna] '("Reconcile New Account" . ledger-reconcile))
(define-key map [menu-bar ldg-recon-menu sep5] '("--"))