web: more account register fixes; heading shows "Balance" or "Total" appropriately
This commit is contained in:
parent
06331c71a8
commit
1a88879734
@ -4,7 +4,7 @@
|
|||||||
<th.description align=left>Description
|
<th.description align=left>Description
|
||||||
<th.account align=left>Account
|
<th.account align=left>Account
|
||||||
<th.amount align=right>Amount
|
<th.amount align=right>Amount
|
||||||
<th.balance align=right>Balance
|
<th.balance align=right>#{balancelabel}
|
||||||
|
|
||||||
$forall i <- numbered items
|
$forall i <- numbered items
|
||||||
^{itemAsHtml vd i}
|
^{itemAsHtml vd i}
|
||||||
|
|||||||
@ -61,9 +61,9 @@ postJournalR = handlePost
|
|||||||
-- | The main register view, with accounts sidebar.
|
-- | The main register view, with accounts sidebar.
|
||||||
getRegisterR :: Handler RepHtml
|
getRegisterR :: Handler RepHtml
|
||||||
getRegisterR = do
|
getRegisterR = do
|
||||||
vd@VD{opts=opts,m=m,j=j} <- getViewData
|
vd@VD{opts=opts,j=j} <- getViewData
|
||||||
let sidecontent = balanceReportAsHtml opts vd{q=""} $ balanceReport opts nullfilterspec j
|
let sidecontent = balanceReportAsHtml opts vd{q=""} $ balanceReport opts nullfilterspec j
|
||||||
maincontent = registerReportAsHtml opts vd $ accountOrJournalRegisterReport opts m j
|
maincontent = registerReportAsHtml opts vd $ accountOrJournalRegisterReport vd j
|
||||||
editform' = editform vd
|
editform' = editform vd
|
||||||
defaultLayout $ do
|
defaultLayout $ do
|
||||||
setTitle "hledger-web register"
|
setTitle "hledger-web register"
|
||||||
@ -86,19 +86,19 @@ postJournalOnlyR = handlePost
|
|||||||
-- | A simple postings view, like hledger register (with editing.)
|
-- | A simple postings view, like hledger register (with editing.)
|
||||||
getRegisterOnlyR :: Handler RepHtml
|
getRegisterOnlyR :: Handler RepHtml
|
||||||
getRegisterOnlyR = do
|
getRegisterOnlyR = do
|
||||||
vd@VD{opts=opts,m=m,j=j} <- getViewData
|
vd@VD{opts=opts,j=j} <- getViewData
|
||||||
defaultLayout $ do
|
defaultLayout $ do
|
||||||
setTitle "hledger-web register only"
|
setTitle "hledger-web register only"
|
||||||
addHamlet $ registerReportAsHtml opts vd $ accountOrJournalRegisterReport opts m j
|
addHamlet $ registerReportAsHtml opts vd $ accountOrJournalRegisterReport vd j
|
||||||
|
|
||||||
postRegisterOnlyR :: Handler RepPlain
|
postRegisterOnlyR :: Handler RepPlain
|
||||||
postRegisterOnlyR = handlePost
|
postRegisterOnlyR = handlePost
|
||||||
|
|
||||||
-- temporary helper - use the new account register report when in:ACCT is specified.
|
-- temporary helper - use the new account register report when in:ACCT is specified.
|
||||||
accountOrJournalRegisterReport :: [Opt] -> Matcher -> Journal -> RegisterReport
|
accountOrJournalRegisterReport :: ViewData -> Journal -> RegisterReport
|
||||||
accountOrJournalRegisterReport opts m j =
|
accountOrJournalRegisterReport VD{opts=opts,m=m,qopts=qopts} j =
|
||||||
case matcherInAccount m of Just a -> accountRegisterReport opts j m a
|
case inAccount qopts of Just a -> accountRegisterReport opts j m a
|
||||||
Nothing -> registerReport opts nullfilterspec $ filterJournalPostings2 m j
|
Nothing -> registerReport opts nullfilterspec $ filterJournalPostings2 m j
|
||||||
|
|
||||||
-- | A simple accounts view, like hledger balance. If the Accept header
|
-- | A simple accounts view, like hledger balance. If the Accept header
|
||||||
-- specifies json, returns the chart of accounts as json.
|
-- specifies json, returns the chart of accounts as json.
|
||||||
@ -126,10 +126,10 @@ accountUrl a = "inacct:" ++ quoteIfSpaced a -- (accountNameToAccountRegex a)
|
|||||||
|
|
||||||
-- | Render a balance report as HTML.
|
-- | Render a balance report as HTML.
|
||||||
balanceReportAsHtml :: [Opt] -> ViewData -> BalanceReport -> Hamlet AppRoute
|
balanceReportAsHtml :: [Opt] -> ViewData -> BalanceReport -> Hamlet AppRoute
|
||||||
balanceReportAsHtml _ vd@VD{here=here,q=q,m=m,j=j} (items,total) = $(Settings.hamletFile "balancereport")
|
balanceReportAsHtml _ vd@VD{here=here,q=q,m=m,qopts=qopts,j=j} (items,total) = $(Settings.hamletFile "balancereport")
|
||||||
where
|
where
|
||||||
filtering = not $ null q
|
filtering = not $ null q
|
||||||
inacct = matcherInAccount m -- headMay $ filter (m `matchesInAccount`) $ journalAccountNames j
|
inacct = inAccount qopts
|
||||||
itemAsHtml :: ViewData -> BalanceReportItem -> Hamlet AppRoute
|
itemAsHtml :: ViewData -> BalanceReportItem -> Hamlet AppRoute
|
||||||
itemAsHtml VD{here=here,q=q} (acct, adisplay, aindent, abal) = $(Settings.hamletFile "balancereportitem")
|
itemAsHtml VD{here=here,q=q} (acct, adisplay, aindent, abal) = $(Settings.hamletFile "balancereportitem")
|
||||||
where
|
where
|
||||||
@ -152,7 +152,7 @@ journalReportAsHtml _ vd items = $(Settings.hamletFile "journalreport")
|
|||||||
|
|
||||||
-- | Render a register report as HTML.
|
-- | Render a register report as HTML.
|
||||||
registerReportAsHtml :: [Opt] -> ViewData -> RegisterReport -> Hamlet AppRoute
|
registerReportAsHtml :: [Opt] -> ViewData -> RegisterReport -> Hamlet AppRoute
|
||||||
registerReportAsHtml _ vd items = $(Settings.hamletFile "registerreport")
|
registerReportAsHtml _ vd (balancelabel,items) = $(Settings.hamletFile "registerreport")
|
||||||
where
|
where
|
||||||
itemAsHtml :: ViewData -> (Int, RegisterReportItem) -> Hamlet AppRoute
|
itemAsHtml :: ViewData -> (Int, RegisterReportItem) -> Hamlet AppRoute
|
||||||
itemAsHtml VD{here=here} (n, (ds, posting, b)) = $(Settings.hamletFile "registerreportitem")
|
itemAsHtml VD{here=here} (n, (ds, posting, b)) = $(Settings.hamletFile "registerreportitem")
|
||||||
@ -385,13 +385,14 @@ nulltemplate = [$hamlet||]
|
|||||||
|
|
||||||
-- | A bundle of data useful for handlers and their templates.
|
-- | A bundle of data useful for handlers and their templates.
|
||||||
data ViewData = VD {
|
data ViewData = VD {
|
||||||
opts :: [Opt] -- ^ command-line options at startup
|
opts :: [Opt] -- ^ command-line options at startup
|
||||||
,q :: String -- ^ current q (query) parameter
|
,q :: String -- ^ current q parameter (the query expression for filtering transactions)
|
||||||
,m :: Matcher -- ^ a search/filter expression based on the above
|
,m :: Matcher -- ^ a matcher parsed from the query expr
|
||||||
,j :: Journal -- ^ the up-to-date parsed unfiltered journal
|
,qopts :: [QueryOpt] -- ^ query options parsed from the query expr
|
||||||
,today :: Day -- ^ the current day
|
,j :: Journal -- ^ the up-to-date parsed unfiltered journal
|
||||||
,here :: AppRoute -- ^ the current route
|
,today :: Day -- ^ the current day
|
||||||
,msg :: Maybe Html -- ^ the current UI message if any, possibly from the current request
|
,here :: AppRoute -- ^ the current route
|
||||||
|
,msg :: Maybe Html -- ^ the current UI message if any, possibly from the current request
|
||||||
}
|
}
|
||||||
|
|
||||||
mkvd :: ViewData
|
mkvd :: ViewData
|
||||||
@ -399,6 +400,7 @@ mkvd = VD {
|
|||||||
opts = []
|
opts = []
|
||||||
,q = ""
|
,q = ""
|
||||||
,m = MatchAny
|
,m = MatchAny
|
||||||
|
,qopts = []
|
||||||
,j = nulljournal
|
,j = nulljournal
|
||||||
,today = ModifiedJulianDay 0
|
,today = ModifiedJulianDay 0
|
||||||
,here = RootR
|
,here = RootR
|
||||||
@ -415,8 +417,8 @@ getViewData = do
|
|||||||
Just here' <- getCurrentRoute
|
Just here' <- getCurrentRoute
|
||||||
today <- liftIO getCurrentDay
|
today <- liftIO getCurrentDay
|
||||||
q <- getParameter "q"
|
q <- getParameter "q"
|
||||||
let m = parseMatcher today q
|
let (m,qopts) = parseQuery today q
|
||||||
return mkvd{opts=opts, q=q, m=m, j=j, today=today, here=here', msg=msg}
|
return mkvd{opts=opts, q=q, m=m, qopts=qopts, j=j, today=today, here=here', msg=msg}
|
||||||
where
|
where
|
||||||
-- | Update our copy of the journal if the file changed. If there is an
|
-- | Update our copy of the journal if the file changed. If there is an
|
||||||
-- error while reloading, keep the old one and return the error, and set a
|
-- error while reloading, keep the old one and return the error, and set a
|
||||||
|
|||||||
@ -37,7 +37,10 @@ import Hledger.Utils.UTF8 (putStr)
|
|||||||
-- | A register report is a list of postings to an account or set of
|
-- | A register report is a list of postings to an account or set of
|
||||||
-- accounts, with a running total. Postings may be actual postings, or
|
-- accounts, with a running total. Postings may be actual postings, or
|
||||||
-- virtual postings aggregated over a reporting interval.
|
-- virtual postings aggregated over a reporting interval.
|
||||||
type RegisterReport = [RegisterReportItem] -- line items, one per posting
|
-- And also some heading info.
|
||||||
|
type RegisterReport = (String -- a possibly null label for the running balance column
|
||||||
|
,[RegisterReportItem] -- line items, one per posting
|
||||||
|
)
|
||||||
|
|
||||||
-- | The data for a single register report line item, representing one posting.
|
-- | The data for a single register report line item, representing one posting.
|
||||||
type RegisterReportItem = (Maybe (Day, String) -- transaction date and description if this is the first posting
|
type RegisterReportItem = (Maybe (Day, String) -- transaction date and description if this is the first posting
|
||||||
@ -53,7 +56,7 @@ register opts args j = do
|
|||||||
|
|
||||||
-- | Render a register report as plain text suitable for console output.
|
-- | Render a register report as plain text suitable for console output.
|
||||||
registerReportAsText :: [Opt] -> RegisterReport -> String
|
registerReportAsText :: [Opt] -> RegisterReport -> String
|
||||||
registerReportAsText opts = unlines . map (registerReportItemAsText opts)
|
registerReportAsText opts = unlines . map (registerReportItemAsText opts) . snd
|
||||||
|
|
||||||
-- | Render one register report line item as plain text. Eg:
|
-- | Render one register report line item as plain text. Eg:
|
||||||
-- @
|
-- @
|
||||||
@ -84,7 +87,7 @@ showPostingWithBalanceForVty showtxninfo p b = registerReportItemAsText [] $ mki
|
|||||||
-- ledger's register command; for an account-specific register see
|
-- ledger's register command; for an account-specific register see
|
||||||
-- accountRegisterReport.
|
-- accountRegisterReport.
|
||||||
registerReport :: [Opt] -> FilterSpec -> Journal -> RegisterReport
|
registerReport :: [Opt] -> FilterSpec -> Journal -> RegisterReport
|
||||||
registerReport opts fspec j = postingsToRegisterReportItems ps nullposting startbal (+)
|
registerReport opts fspec j = (totallabel,postingsToRegisterReportItems ps nullposting startbal (+))
|
||||||
where
|
where
|
||||||
ps | interval == NoInterval = displayableps
|
ps | interval == NoInterval = displayableps
|
||||||
| otherwise = summarisePostingsByInterval interval depth empty filterspan displayableps
|
| otherwise = summarisePostingsByInterval interval depth empty filterspan displayableps
|
||||||
@ -100,30 +103,53 @@ registerReport opts fspec j = postingsToRegisterReportItems ps nullposting start
|
|||||||
(interval, depth, empty) = (intervalFromOpts opts, depthFromOpts opts, Empty `elem` opts)
|
(interval, depth, empty) = (intervalFromOpts opts, depthFromOpts opts, Empty `elem` opts)
|
||||||
|
|
||||||
-- | Get an account register report with the specified options for this
|
-- | Get an account register report with the specified options for this
|
||||||
-- journal. An account register report is like a postings register report
|
-- journal. An account register report is like the traditional account
|
||||||
-- except it is focussed on one account only, it shows the other postings
|
-- register seen in bank statements and personal finance programs. It is
|
||||||
-- in the transactions for this account, and it shows the accurate
|
-- focussed on one account only; it shows this account's transactions'
|
||||||
-- historic balance for this account.
|
-- postings to other accounts; and if there is no transaction filtering in
|
||||||
-- Does not yet handle reporting intervals.
|
-- effect other than a start date, it shows a historically-accurate
|
||||||
|
-- running balance for this account. Once additional filters are applied,
|
||||||
|
-- the running balance reverts to a running total starting at 0.
|
||||||
|
--
|
||||||
|
-- Does not handle reporting intervals.
|
||||||
|
--
|
||||||
accountRegisterReport :: [Opt] -> Journal -> Matcher -> AccountName -> RegisterReport
|
accountRegisterReport :: [Opt] -> Journal -> Matcher -> AccountName -> RegisterReport
|
||||||
accountRegisterReport _ j m a = postingsToRegisterReportItems ps nullposting startbal (-)
|
accountRegisterReport opts j m a = (label, postingsToRegisterReportItems displayps nullposting startbal (-))
|
||||||
where
|
where
|
||||||
ps = displayps
|
-- displayps' | interval == NoInterval = displayps
|
||||||
-- ps | interval == NoInterval = displayps
|
-- | otherwise = summarisePostingsByInterval interval depth empty filterspan displayps
|
||||||
-- | otherwise = summarisePostingsByInterval interval depth empty filterspan displayps
|
|
||||||
|
-- transactions affecting this account
|
||||||
a' = accountNameToAccountOnlyRegex a
|
a' = accountNameToAccountOnlyRegex a
|
||||||
-- XXX priorps and displayps not right due to inacct: still in matcher
|
thisacctmatcher = MatchAcct True a'
|
||||||
-- postings to display: this account's transactions' "other" postings, filtered
|
ts = filter (matchesTransaction thisacctmatcher) $ jtxns j
|
||||||
-- same matcher used on transactions then again on postings, ok I think
|
|
||||||
ts = filter (matchesTransaction (MatchInAcct True a')) $ jtxns j
|
-- all postings in these transactions
|
||||||
displaymatcher = (MatchAnd [MatchAcct False a', m])
|
ps = transactionsPostings ts
|
||||||
displayps = filter (matchesPosting displaymatcher) $ transactionsPostings ts
|
|
||||||
-- starting balance: sum of this account's unfiltered postings prior to the specified start date, if any
|
-- starting balance: if we are filtering by a start date and nothing else
|
||||||
priormatcher = case matcherStartDate m of
|
-- else, the sum of postings to this account before it; otherwise zero.
|
||||||
Nothing -> MatchNone
|
(startbal,label) | matcherIsNull m = (nullmixedamt,balancelabel)
|
||||||
d -> MatchAnd [MatchDate True (DateSpan Nothing d), MatchAcct True a']
|
| matcherIsStartDateOnly effective m = (sumPostings priorps,balancelabel)
|
||||||
priorps = filter (matchesPosting priormatcher) $ journalPostings j
|
| otherwise = (nullmixedamt,totallabel)
|
||||||
startbal = sumPostings priorps
|
where
|
||||||
|
priorps = -- ltrace "priorps" $
|
||||||
|
filter (matchesPosting
|
||||||
|
(-- ltrace "priormatcher" $
|
||||||
|
MatchAnd [thisacctmatcher, tostartdatematcher])) ps
|
||||||
|
tostartdatematcher = MatchDate True (DateSpan Nothing startdate)
|
||||||
|
startdate = matcherStartDate effective m
|
||||||
|
effective = Effective `elem` opts
|
||||||
|
|
||||||
|
-- postings to display: this account's transactions' "other" postings, with any additional filter applied
|
||||||
|
-- XXX would be better to collapse multiple postings from one txn into one (expandable) "split" item
|
||||||
|
displayps = -- ltrace "displayps" $
|
||||||
|
filter (matchesPosting $
|
||||||
|
-- ltrace "displaymatcher" $
|
||||||
|
(MatchAnd [negateMatcher thisacctmatcher, m])) ps
|
||||||
|
|
||||||
|
totallabel = "Total"
|
||||||
|
balancelabel = "Balance"
|
||||||
|
|
||||||
-- | Generate register report line items.
|
-- | Generate register report line items.
|
||||||
postingsToRegisterReportItems :: [Posting] -> Posting -> MixedAmount -> (MixedAmount -> MixedAmount -> MixedAmount) -> [RegisterReportItem]
|
postingsToRegisterReportItems :: [Posting] -> Posting -> MixedAmount -> (MixedAmount -> MixedAmount -> MixedAmount) -> [RegisterReportItem]
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user