2014-03-20 04:11:48 +04:00
|
|
|
{-|
|
|
|
|
|
|
|
|
Balance report, used by the balance command.
|
|
|
|
|
|
|
|
-}
|
|
|
|
|
2016-08-08 17:10:36 +03:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2016-08-09 01:56:50 +03:00
|
|
|
{-# LANGUAGE FlexibleInstances, ScopedTypeVariables, OverloadedStrings #-}
|
|
|
|
|
2014-03-20 04:11:48 +04:00
|
|
|
module Hledger.Reports.BalanceReport (
|
|
|
|
BalanceReport,
|
|
|
|
BalanceReportItem,
|
|
|
|
balanceReport,
|
2015-08-26 20:38:45 +03:00
|
|
|
balanceReportValue,
|
|
|
|
mixedAmountValue,
|
2014-03-26 06:27:18 +04:00
|
|
|
flatShowsExclusiveBalance,
|
2014-03-20 04:11:48 +04:00
|
|
|
|
|
|
|
-- * Tests
|
|
|
|
tests_Hledger_Reports_BalanceReport
|
|
|
|
)
|
|
|
|
where
|
|
|
|
|
2015-08-26 20:38:45 +03:00
|
|
|
import Data.List (sort)
|
2014-03-20 04:11:48 +04:00
|
|
|
import Data.Maybe
|
2015-08-26 20:38:45 +03:00
|
|
|
import Data.Time.Calendar
|
2014-03-20 04:11:48 +04:00
|
|
|
import Test.HUnit
|
2016-12-30 22:15:03 +03:00
|
|
|
import qualified Data.Text as T
|
2014-03-20 04:11:48 +04:00
|
|
|
|
|
|
|
import Hledger.Data
|
|
|
|
import Hledger.Read (mamountp')
|
|
|
|
import Hledger.Query
|
|
|
|
import Hledger.Utils
|
|
|
|
import Hledger.Reports.ReportOptions
|
|
|
|
|
|
|
|
|
2016-08-08 17:10:36 +03:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2014-03-20 04:11:48 +04:00
|
|
|
-- | A simple single-column balance report. It has:
|
|
|
|
--
|
2016-08-09 01:56:50 +03:00
|
|
|
-- 1. a list of items, one per account, each containing:
|
2014-03-20 04:11:48 +04:00
|
|
|
--
|
2016-08-09 01:56:50 +03:00
|
|
|
-- * the full account name
|
|
|
|
--
|
|
|
|
-- * the Ledger-style elided short account name
|
|
|
|
-- (the leaf account name, prefixed by any boring parents immediately above);
|
|
|
|
-- or with --flat, the full account name again
|
2014-03-20 04:11:48 +04:00
|
|
|
--
|
2016-08-09 01:56:50 +03:00
|
|
|
-- * the number of indentation steps for rendering a Ledger-style account tree,
|
|
|
|
-- taking into account elided boring parents, --no-elide and --flat
|
2014-09-11 00:07:53 +04:00
|
|
|
--
|
2016-08-09 01:56:50 +03:00
|
|
|
-- * an amount
|
2014-09-11 00:07:53 +04:00
|
|
|
--
|
2016-08-09 01:56:50 +03:00
|
|
|
-- 2. the total of all amounts
|
|
|
|
--
|
|
|
|
type BalanceReport = ([BalanceReportItem], MixedAmount)
|
|
|
|
type BalanceReportItem = (AccountName, AccountName, Int, MixedAmount)
|
2014-03-20 04:11:48 +04:00
|
|
|
|
2014-03-26 06:27:18 +04:00
|
|
|
-- | When true (the default), this makes balance --flat reports and their implementation clearer.
|
|
|
|
-- Single/multi-col balance reports currently aren't all correct if this is false.
|
|
|
|
flatShowsExclusiveBalance = True
|
|
|
|
|
|
|
|
-- | Enabling this makes balance --flat --empty also show parent accounts without postings,
|
|
|
|
-- in addition to those with postings and a zero balance. Disabling it shows only the latter.
|
|
|
|
-- No longer supported, but leave this here for a bit.
|
|
|
|
-- flatShowsPostinglessAccounts = True
|
|
|
|
|
2014-03-20 04:11:48 +04:00
|
|
|
-- | Generate a simple balance report, containing the matched accounts and
|
|
|
|
-- their balances (change of balance) during the specified period.
|
2016-08-12 19:44:31 +03:00
|
|
|
-- This is like PeriodChangeReport with a single column (but more mature,
|
2014-03-20 04:11:48 +04:00
|
|
|
-- eg this can do hierarchical display).
|
|
|
|
balanceReport :: ReportOpts -> Query -> Journal -> BalanceReport
|
|
|
|
balanceReport opts q j = (items, total)
|
|
|
|
where
|
2015-05-14 22:49:17 +03:00
|
|
|
-- dbg1 = const id -- exclude from debug output
|
|
|
|
dbg1 s = let p = "balanceReport" in Hledger.Utils.dbg1 (p++" "++s) -- add prefix in debug output
|
2014-03-26 06:27:18 +04:00
|
|
|
|
|
|
|
accts = ledgerRootAccount $ ledgerFromJournal q $ journalSelectingAmountFromOpts opts j
|
|
|
|
accts' :: [Account]
|
2014-10-20 04:53:20 +04:00
|
|
|
| queryDepth q == 0 =
|
2015-05-14 22:49:17 +03:00
|
|
|
dbg1 "accts" $
|
2014-10-20 04:53:20 +04:00
|
|
|
take 1 $ clipAccountsAndAggregate (queryDepth q) $ flattenAccounts accts
|
2015-05-14 22:49:17 +03:00
|
|
|
| flat_ opts = dbg1 "accts" $
|
2014-03-26 06:27:18 +04:00
|
|
|
filterzeros $
|
|
|
|
filterempty $
|
|
|
|
drop 1 $ clipAccountsAndAggregate (queryDepth q) $ flattenAccounts accts
|
2015-05-14 22:49:17 +03:00
|
|
|
| otherwise = dbg1 "accts" $
|
2014-03-26 06:27:18 +04:00
|
|
|
filter (not.aboring) $
|
|
|
|
drop 1 $ flattenAccounts $
|
2014-09-11 00:07:53 +04:00
|
|
|
markboring $
|
2014-10-20 04:53:20 +04:00
|
|
|
prunezeros $
|
|
|
|
clipAccounts (queryDepth q) accts
|
2014-03-20 04:11:48 +04:00
|
|
|
where
|
2014-03-26 06:27:18 +04:00
|
|
|
balance = if flat_ opts then aebalance else aibalance
|
|
|
|
filterzeros = if empty_ opts then id else filter (not . isZeroMixedAmount . balance)
|
|
|
|
filterempty = filter (\a -> anumpostings a > 0 || not (isZeroMixedAmount (balance a)))
|
|
|
|
prunezeros = if empty_ opts then id else fromMaybe nullacct . pruneAccounts (isZeroMixedAmount . balance)
|
|
|
|
markboring = if no_elide_ opts then id else markBoringParentAccounts
|
2015-05-14 22:49:17 +03:00
|
|
|
items = dbg1 "items" $ map (balanceReportItem opts q) accts'
|
2016-08-09 01:56:50 +03:00
|
|
|
total | not (flat_ opts) = dbg1 "total" $ sum [amt | (_,_,indent,amt) <- items, indent == 0]
|
2015-05-14 22:49:17 +03:00
|
|
|
| otherwise = dbg1 "total" $
|
2014-03-26 06:27:18 +04:00
|
|
|
if flatShowsExclusiveBalance
|
2016-08-09 01:56:50 +03:00
|
|
|
then sum $ map fourth4 items
|
2014-03-26 06:27:18 +04:00
|
|
|
else sum $ map aebalance $ clipAccountsAndAggregate 1 accts'
|
2014-03-20 04:11:48 +04:00
|
|
|
|
|
|
|
-- | In an account tree with zero-balance leaves removed, mark the
|
|
|
|
-- elidable parent accounts (those with one subaccount and no balance
|
|
|
|
-- of their own).
|
|
|
|
markBoringParentAccounts :: Account -> Account
|
|
|
|
markBoringParentAccounts = tieAccountParents . mapAccounts mark
|
|
|
|
where
|
|
|
|
mark a | length (asubs a) == 1 && isZeroMixedAmount (aebalance a) = a{aboring=True}
|
|
|
|
| otherwise = a
|
|
|
|
|
2014-03-26 06:27:18 +04:00
|
|
|
balanceReportItem :: ReportOpts -> Query -> Account -> BalanceReportItem
|
2014-10-20 04:53:20 +04:00
|
|
|
balanceReportItem opts q a
|
2016-08-09 01:56:50 +03:00
|
|
|
| flat_ opts = (name, name, 0, (if flatShowsExclusiveBalance then aebalance else aibalance) a)
|
|
|
|
| otherwise = (name, elidedname, indent, aibalance a)
|
2014-03-20 04:11:48 +04:00
|
|
|
where
|
2014-10-20 04:53:20 +04:00
|
|
|
name | queryDepth q > 0 = aname a
|
|
|
|
| otherwise = "..."
|
2014-03-20 04:11:48 +04:00
|
|
|
elidedname = accountNameFromComponents (adjacentboringparentnames ++ [accountLeafName name])
|
2016-08-08 18:31:01 +03:00
|
|
|
adjacentboringparentnames = reverse $ map (accountLeafName.aname) $ takeWhile aboring parents
|
2014-03-20 04:11:48 +04:00
|
|
|
indent = length $ filter (not.aboring) parents
|
2014-10-20 04:53:20 +04:00
|
|
|
-- parents exclude the tree's root node
|
|
|
|
parents = case parentAccounts a of [] -> []
|
|
|
|
as -> init as
|
2014-03-20 04:11:48 +04:00
|
|
|
|
|
|
|
-- -- the above using the newer multi balance report code:
|
|
|
|
-- balanceReport' opts q j = (items, total)
|
|
|
|
-- where
|
2016-08-12 19:44:31 +03:00
|
|
|
-- MultiBalanceReport (_,mbrrows,mbrtotals) = PeriodChangeReport opts q j
|
2014-03-20 04:11:48 +04:00
|
|
|
-- items = [(a,a',n, headDef 0 bs) | ((a,a',n), bs) <- mbrrows]
|
|
|
|
-- total = headDef 0 mbrtotals
|
|
|
|
|
2015-08-26 20:38:45 +03:00
|
|
|
-- | Convert all the amounts in a single-column balance report to
|
|
|
|
-- their value on the given date in their default valuation
|
|
|
|
-- commodities.
|
|
|
|
balanceReportValue :: Journal -> Day -> BalanceReport -> BalanceReport
|
|
|
|
balanceReportValue j d r = r'
|
|
|
|
where
|
|
|
|
(items,total) = r
|
2016-12-30 22:15:03 +03:00
|
|
|
r' =
|
|
|
|
dbg9 "known market prices" (jmarketprices j) `seq`
|
|
|
|
dbg8 "balanceReportValue"
|
|
|
|
([(n, n', i, mixedAmountValue j d a) |(n,n',i,a) <- items], mixedAmountValue j d total)
|
2015-08-26 20:38:45 +03:00
|
|
|
|
|
|
|
mixedAmountValue :: Journal -> Day -> MixedAmount -> MixedAmount
|
|
|
|
mixedAmountValue j d (Mixed as) = Mixed $ map (amountValue j d) as
|
|
|
|
|
|
|
|
-- | Find the market value of this amount on the given date, in it's
|
2016-08-08 17:10:36 +03:00
|
|
|
-- default valuation commodity, based on recorded market prices.
|
|
|
|
-- If no default valuation commodity can be found, the amount is left
|
2015-08-26 20:38:45 +03:00
|
|
|
-- unchanged.
|
|
|
|
amountValue :: Journal -> Day -> Amount -> Amount
|
|
|
|
amountValue j d a =
|
|
|
|
case commodityValue j d (acommodity a) of
|
|
|
|
Just v -> v{aquantity=aquantity v * aquantity a
|
|
|
|
,aprice=aprice a
|
|
|
|
}
|
|
|
|
Nothing -> a
|
|
|
|
|
|
|
|
-- | Find the market value, if known, of one unit of this commodity on
|
|
|
|
-- the given date, in the commodity in which it has most recently been
|
|
|
|
-- market-priced (ie the commodity mentioned in the most recent
|
2016-08-08 17:10:36 +03:00
|
|
|
-- applicable market price directive before this date).
|
2016-05-08 02:18:04 +03:00
|
|
|
commodityValue :: Journal -> Day -> CommoditySymbol -> Maybe Amount
|
2015-08-26 20:38:45 +03:00
|
|
|
commodityValue j d c
|
2016-12-30 22:15:03 +03:00
|
|
|
| null applicableprices = dbg Nothing
|
|
|
|
| otherwise = dbg $ Just $ mpamount $ last applicableprices
|
2015-08-26 20:38:45 +03:00
|
|
|
where
|
|
|
|
applicableprices = [p | p <- sort $ jmarketprices j, mpcommodity p == c, mpdate p <= d]
|
2016-12-30 22:15:03 +03:00
|
|
|
dbg = dbg8 ("using market price for "++T.unpack c)
|
2016-08-08 17:10:36 +03:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2014-03-20 04:11:48 +04:00
|
|
|
tests_balanceReport =
|
2014-07-28 17:32:09 +04:00
|
|
|
let
|
|
|
|
(opts,journal) `gives` r = do
|
|
|
|
let (eitems, etotal) = r
|
|
|
|
(aitems, atotal) = balanceReport opts (queryFromOpts nulldate opts) journal
|
2016-08-09 01:56:50 +03:00
|
|
|
showw (acct,acct',indent,amt) = (acct, acct', indent, showMixedAmountDebug amt)
|
2014-07-28 17:32:09 +04:00
|
|
|
assertEqual "items" (map showw eitems) (map showw aitems)
|
|
|
|
assertEqual "total" (showMixedAmountDebug etotal) (showMixedAmountDebug atotal)
|
2015-09-03 02:38:45 +03:00
|
|
|
usd0 = usd 0
|
2014-03-20 04:11:48 +04:00
|
|
|
in [
|
|
|
|
|
|
|
|
"balanceReport with no args on null journal" ~: do
|
|
|
|
(defreportopts, nulljournal) `gives` ([], Mixed [nullamt])
|
|
|
|
|
|
|
|
,"balanceReport with no args on sample journal" ~: do
|
|
|
|
(defreportopts, samplejournal) `gives`
|
|
|
|
([
|
2016-08-09 01:56:50 +03:00
|
|
|
("assets","assets",0, mamountp' "$-1.00")
|
|
|
|
,("assets:bank:saving","bank:saving",1, mamountp' "$1.00")
|
|
|
|
,("assets:cash","cash",1, mamountp' "$-2.00")
|
|
|
|
,("expenses","expenses",0, mamountp' "$2.00")
|
|
|
|
,("expenses:food","food",1, mamountp' "$1.00")
|
|
|
|
,("expenses:supplies","supplies",1, mamountp' "$1.00")
|
|
|
|
,("income","income",0, mamountp' "$-2.00")
|
|
|
|
,("income:gifts","gifts",1, mamountp' "$-1.00")
|
|
|
|
,("income:salary","salary",1, mamountp' "$-1.00")
|
|
|
|
,("liabilities:debts","liabilities:debts",0, mamountp' "$1.00")
|
2014-03-20 04:11:48 +04:00
|
|
|
],
|
2014-07-28 17:32:09 +04:00
|
|
|
Mixed [usd0])
|
2014-03-20 04:11:48 +04:00
|
|
|
|
|
|
|
,"balanceReport with --depth=N" ~: do
|
|
|
|
(defreportopts{depth_=Just 1}, samplejournal) `gives`
|
|
|
|
([
|
2016-08-09 01:56:50 +03:00
|
|
|
("assets", "assets", 0, mamountp' "$-1.00")
|
|
|
|
,("expenses", "expenses", 0, mamountp' "$2.00")
|
|
|
|
,("income", "income", 0, mamountp' "$-2.00")
|
|
|
|
,("liabilities", "liabilities", 0, mamountp' "$1.00")
|
2014-03-20 04:11:48 +04:00
|
|
|
],
|
2014-07-28 17:32:09 +04:00
|
|
|
Mixed [usd0])
|
2014-03-20 04:11:48 +04:00
|
|
|
|
|
|
|
,"balanceReport with depth:N" ~: do
|
|
|
|
(defreportopts{query_="depth:1"}, samplejournal) `gives`
|
|
|
|
([
|
2016-08-09 01:56:50 +03:00
|
|
|
("assets", "assets", 0, mamountp' "$-1.00")
|
|
|
|
,("expenses", "expenses", 0, mamountp' "$2.00")
|
|
|
|
,("income", "income", 0, mamountp' "$-2.00")
|
|
|
|
,("liabilities", "liabilities", 0, mamountp' "$1.00")
|
2014-03-20 04:11:48 +04:00
|
|
|
],
|
2014-07-28 17:32:09 +04:00
|
|
|
Mixed [usd0])
|
2014-03-20 04:11:48 +04:00
|
|
|
|
|
|
|
,"balanceReport with a date or secondary date span" ~: do
|
|
|
|
(defreportopts{query_="date:'in 2009'"}, samplejournal2) `gives`
|
|
|
|
([],
|
|
|
|
Mixed [nullamt])
|
2014-12-16 22:06:21 +03:00
|
|
|
(defreportopts{query_="date2:'in 2009'"}, samplejournal2) `gives`
|
2014-03-20 04:11:48 +04:00
|
|
|
([
|
2016-08-09 01:56:50 +03:00
|
|
|
("assets:bank:checking","assets:bank:checking",0,mamountp' "$1.00")
|
|
|
|
,("income:salary","income:salary",0,mamountp' "$-1.00")
|
2014-03-20 04:11:48 +04:00
|
|
|
],
|
2014-07-28 17:32:09 +04:00
|
|
|
Mixed [usd0])
|
2014-03-20 04:11:48 +04:00
|
|
|
|
|
|
|
,"balanceReport with desc:" ~: do
|
|
|
|
(defreportopts{query_="desc:income"}, samplejournal) `gives`
|
|
|
|
([
|
2016-08-09 01:56:50 +03:00
|
|
|
("assets:bank:checking","assets:bank:checking",0,mamountp' "$1.00")
|
|
|
|
,("income:salary","income:salary",0, mamountp' "$-1.00")
|
2014-03-20 04:11:48 +04:00
|
|
|
],
|
2014-07-28 17:32:09 +04:00
|
|
|
Mixed [usd0])
|
2014-03-20 04:11:48 +04:00
|
|
|
|
|
|
|
,"balanceReport with not:desc:" ~: do
|
|
|
|
(defreportopts{query_="not:desc:income"}, samplejournal) `gives`
|
|
|
|
([
|
2016-08-09 01:56:50 +03:00
|
|
|
("assets","assets",0, mamountp' "$-2.00")
|
|
|
|
,("assets:bank","bank",1, Mixed [usd0])
|
|
|
|
,("assets:bank:checking","checking",2,mamountp' "$-1.00")
|
|
|
|
,("assets:bank:saving","saving",2, mamountp' "$1.00")
|
|
|
|
,("assets:cash","cash",1, mamountp' "$-2.00")
|
|
|
|
,("expenses","expenses",0, mamountp' "$2.00")
|
|
|
|
,("expenses:food","food",1, mamountp' "$1.00")
|
|
|
|
,("expenses:supplies","supplies",1, mamountp' "$1.00")
|
|
|
|
,("income:gifts","income:gifts",0, mamountp' "$-1.00")
|
|
|
|
,("liabilities:debts","liabilities:debts",0, mamountp' "$1.00")
|
2014-03-20 04:11:48 +04:00
|
|
|
],
|
2014-07-28 17:32:09 +04:00
|
|
|
Mixed [usd0])
|
2014-03-20 04:11:48 +04:00
|
|
|
|
|
|
|
|
|
|
|
{-
|
|
|
|
,"accounts report with account pattern o" ~:
|
|
|
|
defreportopts{patterns_=["o"]} `gives`
|
|
|
|
[" $1 expenses:food"
|
|
|
|
," $-2 income"
|
|
|
|
," $-1 gifts"
|
|
|
|
," $-1 salary"
|
|
|
|
,"--------------------"
|
|
|
|
," $-1"
|
|
|
|
]
|
|
|
|
|
|
|
|
,"accounts report with account pattern o and --depth 1" ~:
|
|
|
|
defreportopts{patterns_=["o"],depth_=Just 1} `gives`
|
|
|
|
[" $1 expenses"
|
|
|
|
," $-2 income"
|
|
|
|
,"--------------------"
|
|
|
|
," $-1"
|
|
|
|
]
|
|
|
|
|
|
|
|
,"accounts report with account pattern a" ~:
|
|
|
|
defreportopts{patterns_=["a"]} `gives`
|
|
|
|
[" $-1 assets"
|
|
|
|
," $1 bank:saving"
|
|
|
|
," $-2 cash"
|
|
|
|
," $-1 income:salary"
|
|
|
|
," $1 liabilities:debts"
|
|
|
|
,"--------------------"
|
|
|
|
," $-1"
|
|
|
|
]
|
|
|
|
|
|
|
|
,"accounts report with account pattern e" ~:
|
|
|
|
defreportopts{patterns_=["e"]} `gives`
|
|
|
|
[" $-1 assets"
|
|
|
|
," $1 bank:saving"
|
|
|
|
," $-2 cash"
|
|
|
|
," $2 expenses"
|
|
|
|
," $1 food"
|
|
|
|
," $1 supplies"
|
|
|
|
," $-2 income"
|
|
|
|
," $-1 gifts"
|
|
|
|
," $-1 salary"
|
|
|
|
," $1 liabilities:debts"
|
|
|
|
,"--------------------"
|
|
|
|
," 0"
|
|
|
|
]
|
|
|
|
|
2014-09-11 00:07:53 +04:00
|
|
|
,"accounts report with unmatched parent of two matched subaccounts" ~:
|
2014-03-20 04:11:48 +04:00
|
|
|
defreportopts{patterns_=["cash","saving"]} `gives`
|
|
|
|
[" $-1 assets"
|
|
|
|
," $1 bank:saving"
|
|
|
|
," $-2 cash"
|
|
|
|
,"--------------------"
|
|
|
|
," $-1"
|
|
|
|
]
|
|
|
|
|
2014-09-11 00:07:53 +04:00
|
|
|
,"accounts report with multi-part account name" ~:
|
2014-03-20 04:11:48 +04:00
|
|
|
defreportopts{patterns_=["expenses:food"]} `gives`
|
|
|
|
[" $1 expenses:food"
|
|
|
|
,"--------------------"
|
|
|
|
," $1"
|
|
|
|
]
|
|
|
|
|
|
|
|
,"accounts report with negative account pattern" ~:
|
|
|
|
defreportopts{patterns_=["not:assets"]} `gives`
|
|
|
|
[" $2 expenses"
|
|
|
|
," $1 food"
|
|
|
|
," $1 supplies"
|
|
|
|
," $-2 income"
|
|
|
|
," $-1 gifts"
|
|
|
|
," $-1 salary"
|
|
|
|
," $1 liabilities:debts"
|
|
|
|
,"--------------------"
|
|
|
|
," $1"
|
|
|
|
]
|
|
|
|
|
2014-09-11 00:07:53 +04:00
|
|
|
,"accounts report negative account pattern always matches full name" ~:
|
2014-03-20 04:11:48 +04:00
|
|
|
defreportopts{patterns_=["not:e"]} `gives`
|
|
|
|
["--------------------"
|
|
|
|
," 0"
|
|
|
|
]
|
|
|
|
|
2014-09-11 00:07:53 +04:00
|
|
|
,"accounts report negative patterns affect totals" ~:
|
2014-03-20 04:11:48 +04:00
|
|
|
defreportopts{patterns_=["expenses","not:food"]} `gives`
|
|
|
|
[" $1 expenses:supplies"
|
|
|
|
,"--------------------"
|
|
|
|
," $1"
|
|
|
|
]
|
|
|
|
|
|
|
|
,"accounts report with -E shows zero-balance accounts" ~:
|
|
|
|
defreportopts{patterns_=["assets"],empty_=True} `gives`
|
|
|
|
[" $-1 assets"
|
|
|
|
," $1 bank"
|
|
|
|
," 0 checking"
|
|
|
|
," $1 saving"
|
|
|
|
," $-2 cash"
|
|
|
|
,"--------------------"
|
|
|
|
," $-1"
|
|
|
|
]
|
|
|
|
|
|
|
|
,"accounts report with cost basis" ~: do
|
|
|
|
j <- (readJournal Nothing Nothing Nothing $ unlines
|
|
|
|
[""
|
|
|
|
,"2008/1/1 test "
|
|
|
|
," a:b 10h @ $50"
|
|
|
|
," c:d "
|
|
|
|
]) >>= either error' return
|
|
|
|
let j' = journalCanonicaliseAmounts $ journalConvertAmountsToCost j -- enable cost basis adjustment
|
|
|
|
balanceReportAsText defreportopts (balanceReport defreportopts Any j') `is`
|
|
|
|
[" $500 a:b"
|
|
|
|
," $-500 c:d"
|
|
|
|
,"--------------------"
|
|
|
|
," 0"
|
|
|
|
]
|
|
|
|
-}
|
|
|
|
]
|
|
|
|
|
2016-08-08 18:31:01 +03:00
|
|
|
Right samplejournal2 =
|
2016-12-10 18:04:48 +03:00
|
|
|
journalBalanceTransactions False
|
2016-08-08 18:31:01 +03:00
|
|
|
nulljournal{
|
|
|
|
jtxns = [
|
|
|
|
txnTieKnot Transaction{
|
|
|
|
tindex=0,
|
|
|
|
tsourcepos=nullsourcepos,
|
|
|
|
tdate=parsedate "2008/01/01",
|
|
|
|
tdate2=Just $ parsedate "2009/01/01",
|
|
|
|
tstatus=Uncleared,
|
|
|
|
tcode="",
|
|
|
|
tdescription="income",
|
|
|
|
tcomment="",
|
|
|
|
ttags=[],
|
|
|
|
tpostings=
|
|
|
|
[posting {paccount="assets:bank:checking", pamount=Mixed [usd 1]}
|
|
|
|
,posting {paccount="income:salary", pamount=missingmixedamt}
|
|
|
|
],
|
|
|
|
tpreceding_comment_lines=""
|
|
|
|
}
|
|
|
|
]
|
|
|
|
}
|
2014-09-11 00:07:53 +04:00
|
|
|
|
2014-03-20 04:11:48 +04:00
|
|
|
-- tests_isInterestingIndented = [
|
2014-09-11 00:07:53 +04:00
|
|
|
-- "isInterestingIndented" ~: do
|
2014-03-20 04:11:48 +04:00
|
|
|
-- let (opts, journal, acctname) `gives` r = isInterestingIndented opts l acctname `is` r
|
|
|
|
-- where l = ledgerFromJournal (queryFromOpts nulldate opts) journal
|
2014-09-11 00:07:53 +04:00
|
|
|
|
2014-03-20 04:11:48 +04:00
|
|
|
-- (defreportopts, samplejournal, "expenses") `gives` True
|
|
|
|
-- ]
|
|
|
|
|
|
|
|
tests_Hledger_Reports_BalanceReport :: Test
|
2016-08-08 18:31:01 +03:00
|
|
|
tests_Hledger_Reports_BalanceReport = TestList
|
|
|
|
tests_balanceReport
|