--basis/-B flag, to show all priced amounts on cost basis. Also a --cost alias.

This commit is contained in:
Simon Michael 2008-11-22 20:35:17 +00:00
parent 2d49bc4100
commit 52ff46a326
6 changed files with 51 additions and 24 deletions

View File

@ -83,35 +83,39 @@ filterRawLedgerTransactionsByRealness True (RawLedger ms ps es f) =
-- | Give all a ledger's amounts their canonical display settings. That
-- is, in each commodity, amounts will use the display settings of the
-- first amount detected, and the greatest precision of the amounts
-- detected.
canonicaliseAmounts :: RawLedger -> RawLedger
canonicaliseAmounts l@(RawLedger ms ps es f) = RawLedger ms ps (map fixEntryAmounts es) f
-- detected. Also, amounts are converted to cost basis if that flag is
-- active.
canonicaliseAmounts :: Bool -> RawLedger -> RawLedger
canonicaliseAmounts costbasis l@(RawLedger ms ps es f) = RawLedger ms ps (map fixEntryAmounts es) f
where
fixEntryAmounts (Entry d s c de co ts pr) = Entry d s c de co (map fixRawTransactionAmounts ts) pr
fixRawTransactionAmounts (RawTransaction ac a c t) = RawTransaction ac (fixMixedAmount a) c t
fixMixedAmount (Mixed as) = Mixed $ map fixAmount as
fixAmount (Amount c q pri) = Amount (canonicalcommodity c) q pri
canonicalcommodity c@(Commodity {symbol=s}) =
(firstoccurrenceof c){precision=maximum $ map precision $ commoditieswithsymbol s}
firstoccurrenceof Commodity{symbol=s} = head $ commoditieswithsymbol s
-- Get ledger's amounts' commodities with a given symbol, in the order parsed.
-- Call with a good symbol or it will fail.
commoditieswithsymbol :: String -> [Commodity]
commoditieswithsymbol s = fromMaybe (error $ "no such commodity "++s) (Map.lookup s commoditiesmap)
fixAmount | costbasis = fixcommodity . costOfAmount
| otherwise = fixcommodity
fixcommodity a = a{commodity=canonicalcommodity $ commodity a}
canonicalcommodity c = (firstoccurrenceof c){precision=maxprecision c}
where
commoditiesmap :: Map.Map String [Commodity]
commoditiesmap = Map.fromList [(symbol $ head cs,cs) |
cs <- groupBy samesymbol $ rawLedgerCommodities l]
samesymbol c1 c2 = symbol c1 == symbol c2
firstoccurrenceof c = head $ rawLedgerCommoditiesWithSymbol l (symbol c)
maxprecision c = maximum $ map precision $ rawLedgerCommoditiesWithSymbol l (symbol c)
-- | Get just the amounts from a ledger, in the order parsed.
rawLedgerAmounts :: RawLedger -> [MixedAmount]
rawLedgerAmounts = map amount . rawLedgerTransactions
-- | Get all amount commodities with a given symbol, in the order parsed.
-- Must be called with a good symbol or it will fail.
rawLedgerCommoditiesWithSymbol :: RawLedger -> String -> [Commodity]
rawLedgerCommoditiesWithSymbol l s =
fromMaybe (error $ "no such commodity "++s) (Map.lookup s map)
where
map = Map.fromList [(symbol $ head cs,cs) | cs <- groupBy same $ rawLedgerCommodities l]
same c1 c2 = symbol c1 == symbol c2
-- | Get just the ammount commodities from a ledger, in the order parsed.
rawLedgerCommodities :: RawLedger -> [Commodity]
rawLedgerCommodities = map commodity . concatMap amounts . rawLedgerAmounts
-- | Get just the amounts from a ledger, in the order parsed.
rawLedgerAmounts :: RawLedger -> [MixedAmount]
rawLedgerAmounts = map amount . rawLedgerTransactions
-- | Get just the amount precisions from a ledger, in the order parsed.
rawLedgerPrecisions :: RawLedger -> [Int]
rawLedgerPrecisions = map precision . rawLedgerCommodities

1
NOTES
View File

@ -15,7 +15,6 @@ implementations were its consequences." --Niklaus Wirth
*** flexible date expressions, for easier time reports
**** more formats
**** periods
*** commodity @ rate, for tracking client hours in main ledger
*** actual/effective entry & txn dates, for ?
*** --display, for reconciling recent transactions with real balance
*** more ledger features from README

View File

@ -29,6 +29,7 @@ options = [
Option ['b'] ["begin"] (ReqArg Begin "YYYY/MM/DD") "report on entries on or after this date",
Option ['e'] ["end"] (ReqArg End "YYYY/MM/DD") "report on entries prior to this date",
Option ['C'] ["cleared"] (NoArg Cleared) "report only on cleared entries",
Option ['B'] ["cost","basis"] (NoArg CostBasis) "report cost basis of commodities",
Option [] ["depth"] (ReqArg Depth "N") "balance report: maximum account depth to show",
Option ['E'] ["empty"] (NoArg Empty) "balance report: show accounts with zero balance",
Option ['R'] ["real"] (NoArg Real) "report only on real (non-virtual) transactions",
@ -44,6 +45,7 @@ data Opt =
Begin String |
End String |
Cleared |
CostBasis |
Depth String |
Empty |
Real |

10
README
View File

@ -73,14 +73,18 @@ This version of hledger mimics a subset of ledger 2.6.1:
-E, --empty balance report: show accounts with zero balance
-n, --collapse balance report: no grand total
Commodity reporting:
-B, --basis, --cost report cost basis of commodities
Commands:
balance [REGEXP]... show balance totals for matching accounts
register [REGEXP]... show register of matching transactions
print [REGEXP]... print all matching entries
hledger-only features:
hledger-specific features:
- --depth=N balance report: maximum account depth to show
--depth=N balance report: maximum account depth to show
--cost alias for basis
ledger features not supported:
@ -146,7 +150,6 @@ ledger features not supported:
-L, --price-exp MINS download quotes only if newer than MINS (def: 1440)
-Q, --download download price information when needed
-O, --quantity report commodity totals (this is the default)
-B, --basis report cost basis of commodities
-V, --market report last known market value
-g, --performance report gain/loss for each displayed transaction
-G, --gain report net gain/loss
@ -162,3 +165,4 @@ Some other differences:
- hledger talks about the entry and transaction "description", which ledger calls "note"
- hledger always shows timelog balances in hours
- hledger doesn't require a space after flags like -f
- hledger keeps differently-priced amounts of the same commodity separate

View File

@ -88,7 +88,7 @@ misc_tests = TestList [
,
"canonicaliseAmounts" ~: do
-- all amounts use the greatest precision
assertequal [2,2] (rawLedgerPrecisions $ canonicaliseAmounts $ rawLedgerWithAmounts ["1","2.00"])
assertequal [2,2] (rawLedgerPrecisions $ canonicaliseAmounts False $ rawLedgerWithAmounts ["1","2.00"])
,
"timeLog" ~: do
assertparseequal timelog1 (parsewith timelog timelog1_str)
@ -239,6 +239,23 @@ balancecommand_tests = TestList [
" $-2 cash\n" ++
" $1 saving\n" ++
"")
,
"balance report with cost basis" ~: do
let l = cacheLedger [] $
filterRawLedger Nothing Nothing [] False False $
canonicaliseAmounts True $ -- enable cost basis adjustment
rawledgerfromstring
("" ++
"2008/1/1 test \n" ++
" a:b 10h @ $50\n" ++
" c:d \n" ++
"\n")
assertequal
(" $500 a\n" ++
" $-500 c\n" ++
""
)
(showBalanceReport [] [] l)
] where
gives (opts,pats) e = do
l <- ledgerfromfile pats "sample.ledger"

View File

@ -70,10 +70,11 @@ parseLedgerAndDo :: [Opt] -> [String] -> ([Opt] -> [String] -> Ledger -> IO ())
parseLedgerAndDo opts args cmd =
ledgerFilePathFromOpts opts >>= parseLedgerFile >>= either printParseError runcmd
where
runcmd = cmd opts args . cacheLedger apats . filterRawLedger b e dpats c r . canonicaliseAmounts
runcmd = cmd opts args . cacheLedger apats . filterRawLedger b e dpats c r . canonicaliseAmounts costbasis
b = beginDateFromOpts opts
e = endDateFromOpts opts
(apats,dpats) = parseAccountDescriptionArgs args
c = Cleared `elem` opts
r = Real `elem` opts
costbasis = CostBasis `elem` opts