After more than two years of chewing over the design for this feature, it has
finally arrived. If you don't need it, you can ignore this post. But if
you've ever wanted to fine tune the results you get from either -V or -X $,
there are now several points of interception:
You can specify the valuation method:
1. on a commodity itself
2. on a posting, via metadata (affect is largely the same as #1)
3. on an xact, which then applies to all postings in that xact
4. on any posting via an automated transaction
5. on a per-account basis
6. on a per-commodity basis
7. by changing the journal default of "market"
Fixated pricing (such as {=$20}) still plays a role in this scheme. As far as
valuation goes, it's shorthand for writing ((s,d,t -> market($20,d,t))).
I'm including the test for this feature below, to give you an idea of how it
looks in practice.
Still one piece of this puzzle left, which is to disassociate -V and -X from
-B (so that you can apply -V to the basis cost) or the yet-to-be-written -H
(so you can see historical values in terms of another commodity with -X).
John
;; A valuation function receives three arguments:
;;
;; 'source' A string identifying the commodity whose price
;; is being asked for (example: "EUR")
;;
;; 'date' The reference date the price should be relative.
;;
;; 'target' A string identifying the "target" commodity, or
;; the commodity the returned price should be in.
;; This argument is null if -V was used instead of -X.
;;
;; The valuation function should return an amount. If you've written your
;; function in Python, you can return something like Amount("$100"). If the
;; function returns an explicit value, that value is always used, regardless
;; of the commodity, the date, or the desired target commodity.
define myfunc_seven(s, d, t) = 7 EUR
;; In order to specific a fixed price, but still valuate that price into the
;; target commodity, use something like this:
define myfunc_five(s, d, t) = market(5 EUR, d, t)
;; The 'value' directive sets the valuation used for all commodities used in
;; the rest of the daat stream. This is the fallback, if nothing more
;; specific is found.
value myfunc_seven
;; You can set a specific valuation function on a per-commodity basis.
;; Instead of defining a function, you can also pass a lambda.
commodity $
value s, d, t -> 6 EUR
;; Each account can also provide a default valuation function for any
;; commodities transferred to that account.
account Expenses:Food5
value myfunc_five
;; The metadata field "Value", if found, overrides the valuation function on a
;; transaction-wide or per-posting basis.
= @XACT and Food
; Value:: 8 EUR
(Equity) $1
= @POST and Dining
(Expenses:Food9) $1
; Value:: 9 EUR
;; Lastly, you can specify the valuation function/value for any specific
;; amount using the (( )) commodity annotation.
2012-03-02 KFC
Expenses:Food2 $1 ((2 EUR))
Assets:Cash2
2012-03-03 KFC
Expenses:Food3 $1
; Value:: 3 EUR
Assets:Cash3
2012-03-04 KFC
; Value:: 4 EUR
Expenses:Food4 $1
Assets:Cash4
2012-03-05 KFC
Expenses:Food5 $1
Assets:Cash5
2012-03-06 KFC
Expenses:Food6 $1
Assets:Cash6
2012-03-07 KFC
Expenses:Food7 1 CAD
Assets:Cas7
2012-03-08 XACT
Expenses:Food8 $1
Assets:Cash8
2012-03-09 POST
Expenses:Dining9 $1
Assets:Cash9
test reg -V food
12-Mar-02 KFC Expenses:Food2 2 EUR 2 EUR
12-Mar-03 KFC <Adjustment> -1 EUR 1 EUR
Expenses:Food3 3 EUR 4 EUR
12-Mar-04 KFC <Adjustment> -2 EUR 2 EUR
Expenses:Food4 4 EUR 6 EUR
12-Mar-05 KFC <Adjustment> -3 EUR 3 EUR
Expenses:Food5 5 EUR 8 EUR
12-Mar-06 KFC <Adjustment> -4 EUR 4 EUR
Expenses:Food6 6 EUR 10 EUR
12-Mar-07 KFC Expenses:Food7 7 EUR 17 EUR
12-Mar-08 XACT Expenses:Food8 8 EUR 25 EUR
12-Mar-09 POST (Expenses:Food9) 9 EUR 34 EUR
end test