summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--doc/ledger3.texi12
-rw-r--r--lisp/ldg-commodities.el93
-rw-r--r--lisp/ldg-new.el2
-rw-r--r--lisp/ldg-reconcile.el56
4 files changed, 152 insertions, 11 deletions
diff --git a/doc/ledger3.texi b/doc/ledger3.texi
index a8f1d4b1..55732ceb 100644
--- a/doc/ledger3.texi
+++ b/doc/ledger3.texi
@@ -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
diff --git a/lisp/ldg-commodities.el b/lisp/ldg-commodities.el
new file mode 100644
index 00000000..94d2ddf0
--- /dev/null
+++ b/lisp/ldg-commodities.el
@@ -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
diff --git a/lisp/ldg-new.el b/lisp/ldg-new.el
index ad21564a..3c56c108 100644
--- a/lisp/ldg-new.el
+++ b/lisp/ldg-new.el
@@ -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)
diff --git a/lisp/ldg-reconcile.el b/lisp/ldg-reconcile.el
index 63ea522b..bb8d97f2 100644
--- a/lisp/ldg-reconcile.el
+++ b/lisp/ldg-reconcile.el
@@ -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-display-balance ()
- "Calculate the cleared balance of the account being reconciled"
+
+(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))
+ (account ledger-acct)
+ (val nil))
(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))))))
+ (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* ((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] '("--"))