We now do data filtering/massage as late as possible, not just once at startup. This should work better for multiple commands, as with web or ui. The basic benchmark seems at least as good as before thanks to laziness.
89 lines
3.3 KiB
Haskell
89 lines
3.3 KiB
Haskell
{-|
|
|
|
|
A 'Posting' represents a 'MixedAmount' being added to or subtracted from a
|
|
single 'Account'. Each 'Transaction' contains two or more postings which
|
|
should add up to 0. Postings also reference their parent transaction, so
|
|
we can get a date or description for a posting (from the transaction).
|
|
|
|
-}
|
|
|
|
module Ledger.Posting
|
|
where
|
|
import Ledger.Utils
|
|
import Ledger.Types
|
|
import Ledger.Amount
|
|
import Ledger.AccountName
|
|
import Ledger.Dates (nulldate)
|
|
|
|
|
|
instance Show Posting where show = showPosting
|
|
|
|
nullposting = Posting False "" nullmixedamt "" RegularPosting Nothing
|
|
|
|
showPosting :: Posting -> String
|
|
showPosting (Posting{paccount=a,pamount=amt,pcomment=com,ptype=t}) =
|
|
concatTopPadded [showaccountname a ++ " ", showamount amt, comment]
|
|
where
|
|
ledger3ishlayout = False
|
|
acctnamewidth = if ledger3ishlayout then 25 else 22
|
|
showaccountname = printf ("%-"++(show acctnamewidth)++"s") . bracket . elideAccountName width
|
|
(bracket,width) = case t of
|
|
BalancedVirtualPosting -> (\s -> "["++s++"]", acctnamewidth-2)
|
|
VirtualPosting -> (\s -> "("++s++")", acctnamewidth-2)
|
|
_ -> (id,acctnamewidth)
|
|
showamount = padleft 12 . showMixedAmountOrZero
|
|
comment = if null com then "" else " ; " ++ com
|
|
-- XXX refactor
|
|
showPostingWithoutPrice (Posting{paccount=a,pamount=amt,pcomment=com,ptype=t}) =
|
|
concatTopPadded [showaccountname a ++ " ", showamount amt, comment]
|
|
where
|
|
ledger3ishlayout = False
|
|
acctnamewidth = if ledger3ishlayout then 25 else 22
|
|
showaccountname = printf ("%-"++(show acctnamewidth)++"s") . bracket . elideAccountName width
|
|
(bracket,width) = case t of
|
|
BalancedVirtualPosting -> (\s -> "["++s++"]", acctnamewidth-2)
|
|
VirtualPosting -> (\s -> "("++s++")", acctnamewidth-2)
|
|
_ -> (id,acctnamewidth)
|
|
showamount = padleft 12 . showMixedAmountOrZeroWithoutPrice
|
|
comment = if null com then "" else " ; " ++ com
|
|
|
|
isReal :: Posting -> Bool
|
|
isReal p = ptype p == RegularPosting
|
|
|
|
isVirtual :: Posting -> Bool
|
|
isVirtual p = ptype p == VirtualPosting
|
|
|
|
isBalancedVirtual :: Posting -> Bool
|
|
isBalancedVirtual p = ptype p == BalancedVirtualPosting
|
|
|
|
hasAmount :: Posting -> Bool
|
|
hasAmount = (/= missingamt) . pamount
|
|
|
|
postingTypeFromAccountName a
|
|
| head a == '[' && last a == ']' = BalancedVirtualPosting
|
|
| head a == '(' && last a == ')' = VirtualPosting
|
|
| otherwise = RegularPosting
|
|
|
|
accountNamesFromPostings :: [Posting] -> [AccountName]
|
|
accountNamesFromPostings = nub . map paccount
|
|
|
|
sumPostings :: [Posting] -> MixedAmount
|
|
sumPostings = sum . map pamount
|
|
|
|
postingDate :: Posting -> Day
|
|
postingDate p = maybe nulldate tdate $ ptransaction p
|
|
|
|
postingCleared :: Posting -> Bool
|
|
postingCleared p = maybe False tstatus $ ptransaction p
|
|
|
|
-- | Does this posting fall within the given date span ?
|
|
isPostingInDateSpan :: DateSpan -> Posting -> Bool
|
|
isPostingInDateSpan (DateSpan Nothing Nothing) _ = True
|
|
isPostingInDateSpan (DateSpan Nothing (Just e)) p = postingDate p < e
|
|
isPostingInDateSpan (DateSpan (Just b) Nothing) p = postingDate p >= b
|
|
isPostingInDateSpan (DateSpan (Just b) (Just e)) p = d >= b && d < e where d = postingDate p
|
|
|
|
isEmptyPosting :: Posting -> Bool
|
|
isEmptyPosting = isZeroMixedAmount . pamount
|
|
|