-- Hoogle documentation, generated by Haddock -- See Hoogle, http://www.haskell.org/hoogle/ -- | Core types and utilities for working with hledger (or c++ ledger) data. -- -- This is the reusable core of the hledger financial app; use it to -- build hledger and c++-ledger compatible finance tools. @package hledger-lib @version 0.13 -- | Standard imports and utilities which are useful everywhere, or needed -- low in the module hierarchy. This is the bottom of hledger's module -- graph. module Hledger.Data.Utils underline :: String -> String unbracket :: String -> String -- | Join multi-line strings as side-by-side rectangular strings of the -- same height, top-padded. concatTopPadded :: [String] -> String -- | Join multi-line strings as side-by-side rectangular strings of the -- same height, bottom-padded. concatBottomPadded :: [String] -> String -- | Compose strings vertically and right-aligned. vConcatRightAligned :: [String] -> String -- | Convert a multi-line string to a rectangular string top-padded to the -- specified height. padtop :: Int -> String -> String -- | Convert a multi-line string to a rectangular string bottom-padded to -- the specified height. padbottom :: Int -> String -> String -- | Convert a multi-line string to a rectangular string left-padded to the -- specified width. padleft :: Int -> String -> String -- | Convert a multi-line string to a rectangular string right-padded to -- the specified width. padright :: Int -> String -> String -- | Clip a multi-line string to the specified width and height from the -- top left. cliptopleft :: Int -> Int -> String -> String -- | Clip and pad a multi-line string to fill the specified width and -- height. fitto :: Int -> Int -> String -> String -- | A platform string is a string value from or for the operating system, -- such as a file path or command-line argument (or environment -- variable's name or value ?). On some platforms (such as unix) these -- are not real unicode strings but have some encoding such as UTF-8. -- This alias does no type enforcement but aids code clarity. type PlatformString = String -- | Convert a possibly encoded platform string to a real unicode string. -- We decode the UTF-8 encoding recommended for unix systems (cf -- http:www.dwheeler.comessaysfixing-unix-linux-filenames.html) -- and leave anything else unchanged. fromPlatformString :: PlatformString -> String -- | Convert a unicode string to a possibly encoded platform string. On -- unix we encode with the recommended UTF-8 (cf -- http:www.dwheeler.comessaysfixing-unix-linux-filenames.html) -- and elsewhere we leave it unchanged. toPlatformString :: String -> PlatformString -- | A version of error that's better at displaying unicode. error' :: String -> a -- | A version of userError that's better at displaying unicode. userError' :: String -> IOError difforzero :: (Num a, Ord a) => a -> a -> a containsRegex :: String -> String -> Bool splitAtElement :: Eq a => a -> [a] -> [[a]] -- | List just the leaf nodes of a tree leaves :: Tree a -> [a] -- | get the sub-tree rooted at the first (left-most, depth-first) -- occurrence of the specified node value subtreeat :: Eq a => a -> Tree a -> Maybe (Tree a) -- | get the sub-tree for the specified node value in the first tree in -- forest in which it occurs. subtreeinforest :: Eq a => a -> [Tree a] -> Maybe (Tree a) -- | remove all nodes past a certain depth treeprune :: Int -> Tree a -> Tree a -- | apply f to all tree nodes treemap :: (a -> b) -> Tree a -> Tree b -- | remove all subtrees whose nodes do not fulfill predicate treefilter :: (a -> Bool) -> Tree a -> Tree a -- | is predicate true in any node of tree ? treeany :: (a -> Bool) -> Tree a -> Bool -- | show a compact ascii representation of a tree showtree :: Show a => Tree a -> String -- | show a compact ascii representation of a forest showforest :: Show a => Forest a -> String -- | trace (print on stdout at runtime) a showable expression (for easily -- tracing in the middle of a complex expression) strace :: Show a => a -> a -- | labelled trace - like strace, with a label prepended ltrace :: Show a => String -> a -> a -- | monadic trace - like strace, but works as a standalone line in a monad mtrace :: (Monad m, Show a) => a -> m a -- | trace an expression using a custom show function choice' :: [GenParser tok st a] -> GenParser tok st a parsewith :: Parser a -> String -> Either ParseError a parseWithCtx :: b -> GenParser Char b a -> String -> Either ParseError a fromparse :: Either ParseError a -> a nonspace :: GenParser Char st Char spacenonewline :: GenParser Char st Char restofline :: GenParser Char st String getCurrentLocalTime :: IO LocalTime -- | Get a Test's label, or the empty string. tname :: Test -> String -- | Flatten a Test containing TestLists into a list of single tests. tflatten :: Test -> [Test] -- | Filter TestLists in a Test, recursively, preserving the structure. tfilter :: (Test -> Bool) -> Test -> Test -- | Simple way to assert something is some expected value, with no label. is :: (Eq a, Show a) => a -> a -> Assertion -- | Assert a parse result is successful, printing the parse error on -- failure. assertParse :: (Either ParseError a) -> Assertion -- | Assert a parse result is some expected value, printing the parse error -- on failure. assertParseEqual :: (Show a, Eq a) => (Either ParseError a) -> a -> Assertion printParseError :: Show a => a -> IO () isLeft :: Either a b -> Bool isRight :: Either a b -> Bool -- | Most data types are defined here to avoid import cycles. Here is an -- overview of the hledger data model: -- --
--   Journal                  -- a journal is derived from one or more data files. It contains..
--    [Transaction]           -- journal transactions, which have date, status, code, description and..
--     [Posting]              -- multiple account postings (entries), which have account name and amount.
--    [HistoricalPrice]       -- historical commodity prices
--   
--   Ledger                   -- a ledger is derived from a journal, by applying a filter specification and doing some further processing. It contains..
--    Journal                 -- the filtered journal, containing only the transactions and postings we are interested in
--    Tree AccountName        -- account names referenced in the journal's transactions, as a tree
--    Map AccountName Account -- per-account postings and balances from the journal's transactions, as a  map from account name to account info
--   
-- -- For more detailed documentation on each type, see the corresponding -- modules. -- -- Evolution of transaction/entry/posting terminology: -- -- module Hledger.Data.Types type SmartDate = (String, String, String) data WhichDate ActualDate :: WhichDate EffectiveDate :: WhichDate data DateSpan DateSpan :: (Maybe Day) -> (Maybe Day) -> DateSpan data Interval NoInterval :: Interval Daily :: Interval Weekly :: Interval Monthly :: Interval Quarterly :: Interval Yearly :: Interval type AccountName = String data Side L :: Side R :: Side data Commodity Commodity :: String -> Side -> Bool -> Bool -> Int -> Commodity -- | the commodity's symbol display preferences for amounts of this -- commodity symbol :: Commodity -> String -- | should the symbol appear on the left or the right side :: Commodity -> Side -- | should there be a space between symbol and quantity spaced :: Commodity -> Bool -- | should thousands be comma-separated comma :: Commodity -> Bool -- | number of decimal places to display precision :: Commodity -> Int data Amount Amount :: Commodity -> Double -> Maybe MixedAmount -> Amount commodity :: Amount -> Commodity quantity :: Amount -> Double -- | unit price/conversion rate for this amount at posting time price :: Amount -> Maybe MixedAmount newtype MixedAmount Mixed :: [Amount] -> MixedAmount data PostingType RegularPosting :: PostingType VirtualPosting :: PostingType BalancedVirtualPosting :: PostingType data Posting Posting :: Bool -> AccountName -> MixedAmount -> String -> PostingType -> [(String, String)] -> Maybe Transaction -> Posting pstatus :: Posting -> Bool paccount :: Posting -> AccountName pamount :: Posting -> MixedAmount pcomment :: Posting -> String ptype :: Posting -> PostingType pmetadata :: Posting -> [(String, String)] -- | this posting's parent transaction (co-recursive types). Tying this -- knot gets tedious, Maybe makes it easier/optional. ptransaction :: Posting -> Maybe Transaction data Transaction Transaction :: Day -> Maybe Day -> Bool -> String -> String -> String -> [(String, String)] -> [Posting] -> String -> Transaction tdate :: Transaction -> Day teffectivedate :: Transaction -> Maybe Day tstatus :: Transaction -> Bool tcode :: Transaction -> String tdescription :: Transaction -> String tcomment :: Transaction -> String tmetadata :: Transaction -> [(String, String)] -- | this transaction's postings (co-recursive types). tpostings :: Transaction -> [Posting] tpreceding_comment_lines :: Transaction -> String data ModifierTransaction ModifierTransaction :: String -> [Posting] -> ModifierTransaction mtvalueexpr :: ModifierTransaction -> String mtpostings :: ModifierTransaction -> [Posting] data PeriodicTransaction PeriodicTransaction :: String -> [Posting] -> PeriodicTransaction ptperiodicexpr :: PeriodicTransaction -> String ptpostings :: PeriodicTransaction -> [Posting] data TimeLogCode SetBalance :: TimeLogCode SetRequiredHours :: TimeLogCode In :: TimeLogCode Out :: TimeLogCode FinalOut :: TimeLogCode data TimeLogEntry TimeLogEntry :: TimeLogCode -> LocalTime -> String -> TimeLogEntry tlcode :: TimeLogEntry -> TimeLogCode tldatetime :: TimeLogEntry -> LocalTime tlcomment :: TimeLogEntry -> String data HistoricalPrice HistoricalPrice :: Day -> String -> MixedAmount -> HistoricalPrice hdate :: HistoricalPrice -> Day hsymbol :: HistoricalPrice -> String hamount :: HistoricalPrice -> MixedAmount type Year = Integer -- | A journal context is some data which can change in the course -- of parsing a journal. An example is the default year, which changes -- when a Y directive is encountered. At the end of parsing, the final -- context is saved for later use by eg the add command. data JournalContext Ctx :: !Maybe Year -> !Maybe Commodity -> ![AccountName] -> JournalContext -- | the default year most recently specified with Y ctxYear :: JournalContext -> !Maybe Year -- | the default commodity most recently specified with D ctxCommodity :: JournalContext -> !Maybe Commodity -- | the current stack of parent accounts specified by !account ctxAccount :: JournalContext -> ![AccountName] data Journal Journal :: [ModifierTransaction] -> [PeriodicTransaction] -> [Transaction] -> [TimeLogEntry] -> [HistoricalPrice] -> String -> JournalContext -> [(FilePath, String)] -> ClockTime -> Journal jmodifiertxns :: Journal -> [ModifierTransaction] jperiodictxns :: Journal -> [PeriodicTransaction] jtxns :: Journal -> [Transaction] open_timelog_entries :: Journal -> [TimeLogEntry] historical_prices :: Journal -> [HistoricalPrice] -- | any trailing comments from the journal file final_comment_lines :: Journal -> String -- | the context (parse state) at the end of parsing jContext :: Journal -> JournalContext -- | the file path and raw text of the main and any included journal files. -- The main file is first followed by any included files in the order -- encountered. files :: Journal -> [(FilePath, String)] -- | when this journal was last read from its file(s) filereadtime :: Journal -> ClockTime -- | A JournalUpdate is some transformation of a Journal. It can do I/O or -- raise an error. type JournalUpdate = ErrorT String IO (Journal -> Journal) -- | A hledger journal reader is a triple of format name, format-detecting -- predicate, and a parser to Journal. data Reader Reader :: String -> (FilePath -> String -> Bool) -> (FilePath -> String -> ErrorT String IO Journal) -> Reader rFormat :: Reader -> String rDetector :: Reader -> FilePath -> String -> Bool rParser :: Reader -> FilePath -> String -> ErrorT String IO Journal data Ledger Ledger :: Journal -> Tree AccountName -> Map AccountName Account -> Ledger journal :: Ledger -> Journal accountnametree :: Ledger -> Tree AccountName accountmap :: Ledger -> Map AccountName Account data Account Account :: AccountName -> [Posting] -> MixedAmount -> Account aname :: Account -> AccountName -- | postings in this account apostings :: Account -> [Posting] -- | sum of postings in this account and subaccounts abalance :: Account -> MixedAmount -- | A generic, pure specification of how to filter transactions and -- postings. data FilterSpec FilterSpec :: DateSpan -> Maybe Bool -> Bool -> Bool -> Bool -> [String] -> [String] -> WhichDate -> Maybe Int -> FilterSpec -- | only include if in this date span datespan :: FilterSpec -> DateSpan -- | only include if cleared/uncleared/don't care cleared :: FilterSpec -> Maybe Bool -- | only include if real/don't care real :: FilterSpec -> Bool -- | include if empty (ie amount is zero) empty :: FilterSpec -> Bool -- | convert all amounts to cost basis costbasis :: FilterSpec -> Bool -- | only include if matching these account patterns acctpats :: FilterSpec -> [String] -- | only include if matching these description patterns descpats :: FilterSpec -> [String] -- | which dates to use (actual or effective) whichdate :: FilterSpec -> WhichDate depth :: FilterSpec -> Maybe Int instance Typeable Journal instance Show FilterSpec instance Eq Journal instance Read JournalContext instance Show JournalContext instance Eq JournalContext instance Eq HistoricalPrice instance Eq TimeLogEntry instance Ord TimeLogEntry instance Eq TimeLogCode instance Ord TimeLogCode instance Eq PeriodicTransaction instance Eq ModifierTransaction instance Eq Transaction instance Eq PostingType instance Show PostingType instance Eq MixedAmount instance Eq Amount instance Eq Commodity instance Show Commodity instance Read Commodity instance Ord Commodity instance Eq Side instance Show Side instance Read Side instance Ord Side instance Eq Interval instance Show Interval instance Ord Interval instance Eq DateSpan instance Show DateSpan instance Ord DateSpan instance Eq WhichDate instance Show WhichDate instance Eq Posting -- | Date parsing and utilities for hledger. -- -- For date and time values, we use the standard Day and UTCTime types. -- -- A SmartDate is a date which may be partially-specified or -- relative. Eg 2008/12/31, but also 2008/12, 12/31, tomorrow, last week, -- next year. We represent these as a triple of strings like -- ("2008","12",""), ("","","tomorrow"), ("","last","week"). -- -- A DateSpan is the span of time between two specific calendar -- dates, or an open-ended span where one or both dates are unspecified. -- (A date span with both ends unspecified matches all dates.) -- -- An Interval is ledger's "reporting interval" - weekly, monthly, -- quarterly, etc. module Hledger.Data.Dates showDate :: Day -> String getCurrentDay :: IO Day elapsedSeconds :: Fractional a => UTCTime -> UTCTime -> a -- | Split a DateSpan into one or more consecutive spans at the specified -- interval. splitSpan :: Interval -> DateSpan -> [DateSpan] splitspan :: (Day -> Day) -> (Day -> Day) -> DateSpan -> [DateSpan] -- | Count the days in a DateSpan, or if it is open-ended return Nothing. daysInSpan :: DateSpan -> Maybe Integer -- | Does the span include the given date ? spanContainsDate :: DateSpan -> Day -> Bool -- | Combine two datespans, filling any unspecified dates in the first with -- dates from the second. -- -- Parse a period expression to an Interval and overall DateSpan using -- the provided reference date, or return a parse error. parsePeriodExpr :: Day -> String -> Either ParseError (Interval, DateSpan) -- | Show a DateSpan as a human-readable pseudo-period-expression string. dateSpanAsText :: DateSpan -> String -- | Convert a single smart date string to a date span using the provided -- reference date, or raise an error. spanFromSmartDateString :: Day -> String -> DateSpan spanFromSmartDate :: Day -> SmartDate -> DateSpan showDay :: Day -> String -- | Convert a smart date string to an explicit yyyy/mm/dd string using the -- provided reference date, or raise an error. fixSmartDateStr :: Day -> String -> String -- | A safe version of fixSmartDateStr. fixSmartDateStrEither :: Day -> String -> Either ParseError String -- | Convert a SmartDate to an absolute date using the provided reference -- date. fixSmartDate :: Day -> SmartDate -> Day prevday :: Day -> Day -- | Parse a couple of date-time string formats to a time type. parsedatetimeM :: String -> Maybe LocalTime -- | Parse a couple of date string formats to a time type. parsedateM :: String -> Maybe Day -- | Parse a date-time string to a time type, or raise an error. parsedatetime :: String -> LocalTime -- | Parse a date string to a time type, or raise an error. parsedate :: String -> Day -- | Parse a time string to a time type using the provided pattern, or -- return the default. parsetimewith :: ParseTime t => String -> String -> t -> t -- | Parse a date in any of the formats allowed in ledger's period -- expressions, and maybe some others: -- --
--   2004
--   2004/10
--   2004/10/1
--   10/1
--   21
--   october, oct
--   yesterday, today, tomorrow
--   this/next/last week/day/month/quarter/year
--   
-- -- Returns a SmartDate, to be converted to a full date later (see -- fixSmartDate). Assumes any text in the parse stream has been -- lowercased. smartdate :: GenParser Char st SmartDate -- | Like smartdate, but there must be nothing other than whitespace after -- the date. smartdateonly :: GenParser Char st SmartDate validMonth :: String -> Bool validDay :: String -> Bool validYear :: String -> Bool failIfInvalidMonth :: Monad m => String -> m () failIfInvalidDay :: Monad m => String -> m () failIfInvalidYear :: Monad m => String -> m () yyyymmdd :: GenParser Char st SmartDate ymd :: GenParser Char st SmartDate ym :: GenParser Char st SmartDate y :: GenParser Char st SmartDate d :: GenParser Char st SmartDate md :: GenParser Char st SmartDate month :: GenParser Char st SmartDate mon :: GenParser Char st SmartDate yesterday :: GenParser Char st SmartDate tomorrow :: GenParser Char st SmartDate today :: GenParser Char st SmartDate lastthisnextthing :: GenParser Char st SmartDate periodexpr :: Day -> GenParser Char st (Interval, DateSpan) intervalanddateperiodexpr :: Day -> GenParser Char st (Interval, DateSpan) intervalperiodexpr :: GenParser Char st (Interval, DateSpan) dateperiodexpr :: Day -> GenParser Char st (Interval, DateSpan) periodexprinterval :: GenParser Char st Interval periodexprdatespan :: Day -> GenParser Char st DateSpan doubledatespan :: Day -> GenParser Char st DateSpan fromdatespan :: Day -> GenParser Char st DateSpan todatespan :: Day -> GenParser Char st DateSpan justdatespan :: Day -> GenParser Char st DateSpan mkdatespan :: String -> String -> DateSpan -- | A Commodity is a symbol representing a currency or some other -- kind of thing we are tracking, and some display preferences that tell -- how to display Amounts of the commodity - is the symbol on the -- left or right, are thousands separated by comma, significant decimal -- places and so on. module Hledger.Data.Commodity -- | Look up one of the hard-coded default commodities. For use in tests. comm :: String -> Commodity -- | Find the conversion rate between two commodities. Currently returns 1. conversionRate :: Commodity -> Commodity -> Double -- | Convert a list of commodities to a map from commodity symbols to -- unique, display-preference-canonicalised commodities. canonicaliseCommodities :: [Commodity] -> Map String Commodity -- | An Amount is some quantity of money, shares, or anything else. -- -- A simple amount is a Commodity, quantity pair: -- --
--   $1 
--   -50
--   EUR 3.44 
--   GOOG 500
--   1.5h
--   90 apples
--   0 
--   
-- -- An amount may also have a per-unit price, or conversion rate, in terms -- of some other commodity. If present, this is displayed after @: -- --
--   EUR 3 @ $1.35
--   
-- -- A MixedAmount is zero or more simple amounts. Mixed amounts are -- usually normalised so that there is no more than one amount in each -- commodity, and no zero amounts (or, there is just a single zero amount -- and no others.): -- --
--   $50 + EUR 3
--   16h + $13.55 + AAPL 500 + 6 oranges
--   0
--   
-- -- We can do limited arithmetic with simple or mixed amounts: either -- price-preserving arithmetic with similarly-priced amounts, or -- price-discarding arithmetic which ignores and discards prices. module Hledger.Data.Amount -- | Apply a binary arithmetic operator to two amounts, converting to the -- second one's commodity (and display precision), discarding any price -- information. (Using the second commodity is best since sum and other -- folds start with a no-commodity amount.) amountop :: (Double -> Double -> Double) -> Amount -> Amount -> Amount -- | Convert an amount to the specified commodity using the appropriate -- exchange rate (which is currently always 1). convertAmountTo :: Commodity -> Amount -> Amount -- | Convert mixed amount to the specified commodity convertMixedAmountTo :: Commodity -> MixedAmount -> Amount -- | Convert an amount to the commodity of its saved price, if any. costOfAmount :: Amount -> Amount -- | Get the string representation of an amount, based on its commodity's -- display settings. showAmount :: Amount -> String -- | Get the string representation of an amount, based on its commodity's -- display settings except using the specified precision. showAmountWithPrecision :: Int -> Amount -> String -- | Get the unambiguous string representation of an amount, for debugging. showAmountDebug :: Amount -> String -- | Get the string representation of an amount, without any @ price. showAmountWithoutPrice :: Amount -> String -- | Get the string representation of an amount, without any price or -- commodity symbol. showAmountWithoutPriceOrCommodity :: Amount -> String -- | Get the string representation of the number part of of an amount, -- using the display precision from its commodity. showAmount' :: Amount -> String -- | Add thousands-separating commas to a decimal number string punctuatethousands :: String -> String -- | Does this amount appear to be zero when displayed with its given -- precision ? isZeroAmount :: Amount -> Bool -- | Is this amount really zero, regardless of the display precision -- ? Since we are using floating point, for now just test to some high -- precision. isReallyZeroAmount :: Amount -> Bool -- | Is this amount negative ? The price is ignored. isNegativeAmount :: Amount -> Bool -- | Access a mixed amount's components. amounts :: MixedAmount -> [Amount] -- | Does this mixed amount appear to be zero - empty, or containing only -- simple amounts which appear to be zero ? isZeroMixedAmount :: MixedAmount -> Bool -- | Is this mixed amount really zero ? See isReallyZeroAmount. isReallyZeroMixedAmount :: MixedAmount -> Bool -- | Is this mixed amount negative, if it can be normalised to a single -- commodity ? isNegativeMixedAmount :: MixedAmount -> Maybe Bool -- | Is this mixed amount really zero, after converting to cost -- commodities where possible ? isReallyZeroMixedAmountCost :: MixedAmount -> Bool -- | MixedAmount derives Eq in Types.hs, but that doesn't know that we want -- $0 = EUR0 = 0. Yet we don't want to drag all this code in there. When -- zero equality is important, use this, for now; should be used -- everywhere. mixedAmountEquals :: MixedAmount -> MixedAmount -> Bool -- | Get the string representation of a mixed amount, showing each of its -- component amounts. NB a mixed amount can have an empty amounts list in -- which case it shows as "". showMixedAmount :: MixedAmount -> String setMixedAmountPrecision :: Int -> MixedAmount -> MixedAmount -- | Get the string representation of a mixed amount, showing each of its -- component amounts with the specified precision, ignoring their -- commoditys' display precision settings. NB a mixed amount can have an -- empty amounts list in which case it shows as "". showMixedAmountWithPrecision :: Int -> MixedAmount -> String -- | Get an unambiguous string representation of a mixed amount for -- debugging. showMixedAmountDebug :: MixedAmount -> String -- | Get the string representation of a mixed amount, but without any @ -- prices. showMixedAmountWithoutPrice :: MixedAmount -> String -- | Get the string representation of a mixed amount, and if it appears to -- be all zero just show a bare 0, ledger-style. showMixedAmountOrZero :: MixedAmount -> String -- | Get the string representation of a mixed amount, or a bare 0, without -- any @ prices. showMixedAmountOrZeroWithoutPrice :: MixedAmount -> String -- | Simplify a mixed amount by combining any component amounts which have -- the same commodity and the same price. Also removes zero amounts, or -- adds a single zero amount if there are no amounts at all. normaliseMixedAmount :: MixedAmount -> MixedAmount -- | Set a mixed amount's commodity to the canonicalised commodity from the -- provided commodity map. canonicaliseMixedAmount :: Maybe (Map String Commodity) -> MixedAmount -> MixedAmount -- | Set an amount's commodity to the canonicalised commodity from the -- provided commodity map. canonicaliseAmount :: Maybe (Map String Commodity) -> Amount -> Amount -- | Simplify a mixed amount by combining any component amounts which have -- the same commodity, ignoring and discarding their unit prices if any. -- Also removes zero amounts, or adds a single zero amount if there are -- no amounts at all. normaliseMixedAmountIgnoringPrice :: MixedAmount -> MixedAmount sumMixedAmountsPreservingHighestPrecision :: [MixedAmount] -> MixedAmount normaliseMixedAmountPreservingHighestPrecision :: MixedAmount -> MixedAmount sumAmountsPreservingHighestPrecision :: [Amount] -> Amount amountopPreservingHighestPrecision :: (Double -> Double -> Double) -> Amount -> Amount -> Amount -- | Convert a mixed amount's component amounts to the commodity of their -- saved price, if any. costOfMixedAmount :: MixedAmount -> MixedAmount -- | The empty simple amount. nullamt :: Amount -- | The empty mixed amount. nullmixedamt :: MixedAmount -- | A temporary value for parsed transactions which had no amount -- specified. missingamt :: MixedAmount instance Show HistoricalPrice instance Ord MixedAmount instance Num MixedAmount instance Ord Amount instance Num Amount instance Show MixedAmount instance Show Amount -- | AccountNames are strings like assets:cash:petty, with -- multiple components separated by :. From a set of these we -- derive the account hierarchy. module Hledger.Data.AccountName accountNameComponents :: AccountName -> [String] accountNameFromComponents :: [String] -> AccountName accountLeafName :: AccountName -> String accountNameLevel :: AccountName -> Int accountNameDrop :: Int -> AccountName -> AccountName -- | expandAccountNames :: [AccountName] -> [AccountName] -- | topAccountNames :: [AccountName] -> [AccountName] parentAccountName :: AccountName -> AccountName parentAccountNames :: AccountName -> [AccountName] isAccountNamePrefixOf :: AccountName -> AccountName -> Bool isSubAccountNameOf :: AccountName -> AccountName -> Bool -- | From a list of account names, select those which are direct -- subaccounts of the given account name. subAccountNamesFrom :: [AccountName] -> AccountName -> [AccountName] -- | Convert a list of account names to a tree. accountNameTreeFrom :: [AccountName] -> Tree AccountName newtype Tree' a T :: (Map a (Tree' a)) -> Tree' a mergeTrees :: Ord a => Tree' a -> Tree' a -> Tree' a pathtree :: [a] -> Tree' a fromPaths :: Ord a => [[a]] -> Tree' a converttree :: Tree' AccountName -> [Tree AccountName] expandTreeNames :: Tree AccountName -> Tree AccountName accountNameTreeFrom4 :: [AccountName] -> Tree AccountName -- | Elide an account name to fit in the specified width. From the ledger -- 2.6 news: -- --
--      What Ledger now does is that if an account name is too long, it will
--      start abbreviating the first parts of the account name down to two
--      letters in length.  If this results in a string that is still too
--      long, the front will be elided -- not the end.  For example:
--   
--   Expenses:Cash           ; OK, not too long
--        Ex:Wednesday:Cash       ; Expenses was abbreviated to fit
--        Ex:We:Afternoon:Cash    ; Expenses and Wednesday abbreviated
--        ; Expenses:Wednesday:Afternoon:Lunch:Snack:Candy:Chocolate:Cash
--        ..:Af:Lu:Sn:Ca:Ch:Cash  ; Abbreviated and elided!
--   
elideAccountName :: Int -> AccountName -> AccountName clipAccountName :: Int -> AccountName -> AccountName instance Show a => Show (Tree' a) instance Eq a => Eq (Tree' a) instance Ord a => Ord (Tree' a) -- | 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). Strictly speaking, -- "entry" is probably a better name for these. module Hledger.Data.Posting showPosting :: Posting -> String showPostingForRegister :: Posting -> String isReal :: Posting -> Bool isVirtual :: Posting -> Bool isBalancedVirtual :: Posting -> Bool hasAmount :: Posting -> Bool accountNamesFromPostings :: [Posting] -> [AccountName] sumPostings :: [Posting] -> MixedAmount postingDate :: Posting -> Day postingCleared :: Posting -> Bool -- | Does this posting fall within the given date span ? isPostingInDateSpan :: DateSpan -> Posting -> Bool isEmptyPosting :: Posting -> Bool -- | Get the minimal date span which contains all the postings, or DateSpan -- Nothing Nothing if there are none. postingsDateSpan :: [Posting] -> DateSpan instance Show Posting -- | A Transaction consists of two or more related Postings -- which balance to zero, representing a movement of some commodity(ies) -- between accounts, plus a date and optional metadata like description -- and cleared status. module Hledger.Data.Transaction nulltransaction :: Transaction -- | Show a journal transaction, formatted for the print command. ledger -- 2.x's standard format looks like this: -- --
--   yyyymmdd[ *][ CODE] description.........          [  ; comment...............]
--       account name 1.....................  ...$amount1[  ; comment...............]
--       account name 2.....................  ..$-amount1[  ; comment...............]
--   
--   pcodewidth    = no limit -- 10          -- mimicking ledger layout.
--   pdescwidth    = no limit -- 20          -- I don't remember what these mean,
--   pacctwidth    = 35 minimum, no maximum  -- they were important at the time.
--   pamtwidth     = 11
--   pcommentwidth = no limit -- 22
--   
showTransaction :: Transaction -> String showTransactionUnelided :: Transaction -> String showTransactionForPrint :: Bool -> Transaction -> String showTransaction' :: Bool -> Bool -> Transaction -> String -- | Show an account name, clipped to the given width if any, and -- appropriately bracketed/parenthesised for the given posting type. showAccountName :: Maybe Int -> PostingType -> AccountName -> String realPostings :: Transaction -> [Posting] virtualPostings :: Transaction -> [Posting] balancedVirtualPostings :: Transaction -> [Posting] -- | Get the sums of a transaction's real, virtual, and balanced virtual -- postings. transactionPostingBalances :: Transaction -> (MixedAmount, MixedAmount, MixedAmount) -- | Is this transaction balanced ? A balanced transaction's real -- (non-virtual) postings sum to 0, and any balanced virtual postings -- also sum to 0. isTransactionBalanced :: Maybe (Map String Commodity) -> Transaction -> Bool -- | Ensure that this entry is balanced, possibly auto-filling a missing -- amount first. We can auto-fill if there is just one non-virtual -- transaction without an amount. The auto-filled balance will be -- converted to cost basis if possible. If the entry can not be balanced, -- return an error message instead. balanceTransaction :: Maybe (Map String Commodity) -> Transaction -> Either String Transaction nonzerobalanceerror :: Transaction -> String -- | Convert the primary date to either the actual or effective date. journalTransactionWithDate :: WhichDate -> Transaction -> Transaction -- | Ensure a transaction's postings refer back to it. txnTieKnot :: Transaction -> Transaction -- | Set a posting's parent transaction. settxn :: Transaction -> Posting -> Posting instance Show PeriodicTransaction instance Show ModifierTransaction instance Show Transaction -- | A TimeLogEntry is a clock-in, clock-out, or other directive in -- a timelog file (see timeclock.el or the command-line version). These -- can be converted to Transactions and queried like a ledger. module Hledger.Data.TimeLog -- | Convert time log entries to journal transactions. When there is no -- clockout, add one with the provided current time. Sessions crossing -- midnight are split into days to give accurate per-day totals. timeLogEntriesToTransactions :: LocalTime -> [TimeLogEntry] -> [Transaction] -- | Convert a timelog clockin and clockout entry to an equivalent journal -- transaction, representing the time expenditure. Note this entry is not -- balanced, since we omit the "assets:time" transaction for simpler -- output. entryFromTimeLogInOut :: TimeLogEntry -> TimeLogEntry -> Transaction instance Read TimeLogCode instance Show TimeLogCode instance Show TimeLogEntry -- | A Journal is a set of Transactions and related data, -- usually parsed from a hledger/ledger journal file or timelog. This is -- the primary hledger data object. module Hledger.Data.Journal nulljournal :: Journal nullctx :: JournalContext journalFilePath :: Journal -> FilePath journalFilePaths :: Journal -> [FilePath] mainfile :: Journal -> (FilePath, String) addTransaction :: Transaction -> Journal -> Journal addModifierTransaction :: ModifierTransaction -> Journal -> Journal addPeriodicTransaction :: PeriodicTransaction -> Journal -> Journal addHistoricalPrice :: HistoricalPrice -> Journal -> Journal addTimeLogEntry :: TimeLogEntry -> Journal -> Journal journalPostings :: Journal -> [Posting] journalAccountNamesUsed :: Journal -> [AccountName] journalAccountNames :: Journal -> [AccountName] journalAccountNameTree :: Journal -> Tree AccountName -- | Keep only transactions we are interested in, as described by the -- filter specification. May also massage the data a little. filterJournalTransactions :: FilterSpec -> Journal -> Journal -- | Keep only postings we are interested in, as described by the filter -- specification. May also massage the data a little. This can leave -- unbalanced transactions. filterJournalPostings :: FilterSpec -> Journal -> Journal -- | Keep only transactions whose description matches the description -- patterns. filterJournalTransactionsByDescription :: [String] -> Journal -> Journal -- | Keep only transactions which fall between begin and end dates. We -- include transactions on the begin date and exclude transactions on the -- end date, like ledger. An empty date string means no restriction. filterJournalTransactionsByDate :: DateSpan -> Journal -> Journal -- | Keep only transactions which have the requested cleared/uncleared -- status, if there is one. filterJournalTransactionsByClearedStatus :: Maybe Bool -> Journal -> Journal -- | Keep only postings which have the requested cleared/uncleared status, -- if there is one. filterJournalPostingsByClearedStatus :: Maybe Bool -> Journal -> Journal -- | Strip out any virtual postings, if the flag is true, otherwise do no -- filtering. filterJournalPostingsByRealness :: Bool -> Journal -> Journal -- | Strip out any postings with zero amount, unless the flag is true. filterJournalPostingsByEmpty :: Bool -> Journal -> Journal -- | Keep only transactions which affect accounts deeper than the specified -- depth. filterJournalTransactionsByDepth :: Maybe Int -> Journal -> Journal -- | Strip out any postings to accounts deeper than the specified depth -- (and any transactions which have no postings as a result). filterJournalPostingsByDepth :: Maybe Int -> Journal -> Journal -- | Keep only transactions which affect accounts matched by the account -- patterns. More precisely: each positive account pattern excludes -- transactions which do not contain a posting to a matched account, and -- each negative account pattern excludes transactions containing a -- posting to a matched account. filterJournalTransactionsByAccount :: [String] -> Journal -> Journal -- | Keep only postings which affect accounts matched by the account -- patterns. This can leave transactions unbalanced. filterJournalPostingsByAccount :: [String] -> Journal -> Journal -- | Convert this journal's transactions' primary date to either the actual -- or effective date. journalSelectingDate :: WhichDate -> Journal -> Journal -- | Do post-parse processing on a journal, to make it ready for use. journalFinalise :: ClockTime -> LocalTime -> FilePath -> String -> JournalContext -> Journal -> Either String Journal -- | Fill in any missing amounts and check that all journal transactions -- balance, or return an error message. This is done after parsing all -- amounts and working out the canonical commodities, since balancing -- depends on display precision. Reports only the first error -- encountered. journalBalanceTransactions :: Journal -> Either String Journal -- | Convert all the journal's amounts to their canonical display settings. -- Ie, all amounts in a given commodity will use (a) the display settings -- of the first, and (b) the greatest precision, of the amounts in that -- commodity. Prices are canonicalised as well, so consider calling -- journalApplyHistoricalPrices before this. journalCanonicaliseAmounts :: Journal -> Journal -- | Apply this journal's historical price records to unpriced amounts -- where possible. journalApplyHistoricalPrices :: Journal -> Journal -- | Get the price for a commodity on the specified day from the price -- database, if known. Does only one lookup step, ie will not look up the -- price of a price. journalHistoricalPriceFor :: Journal -> Day -> Commodity -> Maybe MixedAmount -- | Close any open timelog sessions in this journal using the provided -- current time. journalCloseTimeLogEntries :: LocalTime -> Journal -> Journal -- | Convert all this journal's amounts to cost by applying their prices, -- if any. journalConvertAmountsToCost :: Journal -> Journal -- | Get this journal's unique, display-preference-canonicalised -- commodities, by symbol. journalCanonicalCommodities :: Journal -> Map String Commodity -- | Get all this journal's amounts' commodities, in the order parsed. journalAmountCommodities :: Journal -> [Commodity] -- | Get all this journal's amount and price commodities, in the order -- parsed. journalAmountAndPriceCommodities :: Journal -> [Commodity] -- | Get this amount's commodity and any commodities referenced in its -- price. amountCommodities :: Amount -> [Commodity] -- | Get all this journal's amounts, in the order parsed. journalAmounts :: Journal -> [MixedAmount] -- | The (fully specified) date span containing this journal's -- transactions, or DateSpan Nothing Nothing if there are none. journalDateSpan :: Journal -> DateSpan -- | Check if a set of hledger account/description filter patterns matches -- the given account name or entry description. Patterns are -- case-insensitive regular expressions. Prefixed with not:, they become -- anti-patterns. matchpats :: [String] -> String -> Bool -- | Calculate the account tree and all account balances from a journal's -- postings, returning the results for efficient lookup. journalAccountInfo :: Journal -> (Tree AccountName, Map AccountName Account) -- | Given a list of postings, return an account name tree and three query -- functions that fetch postings, subaccount-excluding-balance and -- subaccount-including-balance by account name. groupPostings :: [Posting] -> (Tree AccountName, AccountName -> [Posting], AccountName -> MixedAmount, AccountName -> MixedAmount) -- | Add subaccount-excluding and subaccount-including balances to a tree -- of account names somewhat efficiently, given a function that looks up -- transactions by account name. calculateBalances :: Tree AccountName -> (AccountName -> [Posting]) -> Tree (AccountName, (MixedAmount, MixedAmount)) -- | Convert a list of postings to a map from account name to that -- account's postings. postingsByAccount :: [Posting] -> Map AccountName [Posting] instance Show Journal -- | Utilities common to hledger journal readers. module Hledger.Read.Utils juSequence :: [JournalUpdate] -> JournalUpdate -- | Given a JournalUpdate-generating parsec parser, file path and data -- string, parse and post-process a Journal so that it's ready to use, or -- give an error. parseJournalWith :: (GenParser Char JournalContext (JournalUpdate, JournalContext)) -> FilePath -> String -> ErrorT String IO Journal setYear :: Integer -> GenParser tok JournalContext () getYear :: GenParser tok JournalContext (Maybe Integer) setCommodity :: Commodity -> GenParser tok JournalContext () getCommodity :: GenParser tok JournalContext (Maybe Commodity) pushParentAccount :: String -> GenParser tok JournalContext () popParentAccount :: GenParser tok JournalContext () getParentAccount :: GenParser tok JournalContext String -- | Convert a possibly relative, possibly tilde-containing file path to an -- absolute one. using the current directory from a parsec source -- position. ~username is not supported. expandPath :: MonadIO m => SourcePos -> FilePath -> m FilePath fileSuffix :: FilePath -> String -- | An Account stores -- -- module Hledger.Data.Account instance Eq Account instance Show Account -- | A Ledger is derived from a Journal by applying a filter -- specification to select Transactions and Postings of -- interest. It contains the filtered journal and knows the resulting -- chart of accounts, account balances, and postings in each account. module Hledger.Data.Ledger nullledger :: Ledger -- | Filter a journal's transactions as specified, and then process them to -- derive a ledger containing all balances, the chart of accounts, -- canonicalised commodities etc. journalToLedger :: FilterSpec -> Journal -> Ledger -- | List a ledger's account names. ledgerAccountNames :: Ledger -> [AccountName] -- | Get the named account from a ledger. ledgerAccount :: Ledger -> AccountName -> Account -- | List a ledger's accounts, in tree order ledgerAccounts :: Ledger -> [Account] -- | List a ledger's top-level accounts, in tree order ledgerTopAccounts :: Ledger -> [Account] -- | Accounts in ledger whose name matches the pattern, in tree order. ledgerAccountsMatching :: [String] -> Ledger -> [Account] -- | List a ledger account's immediate subaccounts ledgerSubAccounts :: Ledger -> Account -> [Account] -- | List a ledger's postings, in the order parsed. ledgerPostings :: Ledger -> [Posting] -- | Get a ledger's tree of accounts to the specified depth. ledgerAccountTree :: Int -> Ledger -> Tree Account -- | Get a ledger's tree of accounts rooted at the specified account. ledgerAccountTreeAt :: Ledger -> Account -> Maybe (Tree Account) -- | The (fully specified) date span containing all the ledger's (filtered) -- transactions, or DateSpan Nothing Nothing if there are none. ledgerDateSpan :: Ledger -> DateSpan -- | Convenience aliases. accountnames :: Ledger -> [AccountName] account :: Ledger -> AccountName -> Account accounts :: Ledger -> [Account] topaccounts :: Ledger -> [Account] accountsmatching :: [String] -> Ledger -> [Account] subaccounts :: Ledger -> Account -> [Account] postings :: Ledger -> [Posting] commodities :: Ledger -> Map String Commodity accounttree :: Int -> Ledger -> Tree Account accounttreeat :: Ledger -> Account -> Maybe (Tree Account) rawdatespan :: Ledger -> DateSpan ledgeramounts :: Ledger -> [MixedAmount] instance Show Ledger -- | The Hledger.Data library allows parsing and querying of C++ -- ledger-style journal files. It generally provides a compatible subset -- of C++ ledger's functionality. This package re-exports all the -- Hledger.Data.* modules. module Hledger.Data tests_Hledger_Data :: Test -- | A reader for hledger's (and c++ ledger's) journal file format. -- -- From the ledger 2.5 manual: -- --
--   The ledger file format is quite simple, but also very flexible. It supports
--   many options, though typically the user can ignore most of them. They are
--   summarized below.  The initial character of each line determines what the
--   line means, and how it should be interpreted. Allowable initial characters
--   are:
--   
--   NUMBER      A line beginning with a number denotes an entry. It may be followed by any
--               number of lines, each beginning with whitespace, to denote the entrys account
--               transactions. The format of the first line is:
--   
--   DATE[=EDATE] [*|!] [(CODE)] DESC
--   
--   If * appears after the date (with optional eective date), it indicates the entry
--               is cleared, which can mean whatever the user wants it t omean. If ! appears
--               after the date, it indicates d the entry is pending; i.e., tentatively cleared from
--               the users point of view, but not yet actually cleared. If a CODE appears in
--               parentheses, it may be used to indicate a check number, or the type of the
--               transaction. Following these is the payee, or a description of the transaction.
--               The format of each following transaction is:
--   
--   ACCOUNT     AMOUNT    [; NOTE]
--   
--   The ACCOUNT may be surrounded by parentheses if it is a virtual
--               transactions, or square brackets if it is a virtual transactions that must
--               balance. The AMOUNT can be followed by a per-unit transaction cost,
--               by specifying  AMOUNT, or a complete transaction cost with @ AMOUNT.
--               Lastly, the NOTE may specify an actual and/or eective date for the
--               transaction by using the syntax [ACTUAL_DATE] or [=EFFECTIVE_DATE] or
--               [ACTUAL_DATE=EFFECtIVE_DATE].
--   
--   =           An automated entry. A value expression must appear after the equal sign.
--               After this initial line there should be a set of one or more transactions, just as
--               if it were normal entry. If the amounts of the transactions have no commodity,
--               they will be applied as modifiers to whichever real transaction is matched by
--               the value expression.
--   
--   ~           A period entry. A period expression must appear after the tilde.
--               After this initial line there should be a set of one or more transactions, just as
--               if it were normal entry.
--   
--   !           A line beginning with an exclamation mark denotes a command directive. It
--               must be immediately followed by the command word. The supported commands
--               are:
--   
--   !include
--                           Include the stated ledger file.
--              !account
--                           The account name is given is taken to be the parent of all transac-
--                           tions that follow, until !end is seen.
--              !end       Ends an account block.
--   
--   ;          A line beginning with a colon indicates a comment, and is ignored.
--   
--   Y          If a line begins with a capital Y, it denotes the year used for all subsequent
--              entries that give a date without a year. The year should appear immediately
--              after the Y, for example: Y2004. This is useful at the beginning of a file, to
--              specify the year for that file. If all entries specify a year, however, this command
--              has no eect.
--   
--   P          Specifies a historical price for a commodity. These are usually found in a pricing
--              history file (see the -Q option). The syntax is:
--   
--   P DATE SYMBOL PRICE
--   
--   N SYMBOL   Indicates that pricing information is to be ignored for a given symbol, nor will
--              quotes ever be downloaded for that symbol. Useful with a home currency, such
--              as the dollar ($). It is recommended that these pricing options be set in the price
--              database file, which defaults to ~/.pricedb. The syntax for this command is:
--   
--   N SYMBOL
--   
--   D AMOUNT   Specifies the default commodity to use, by specifying an amount in the expected
--              format. The entry command will use this commodity as the default when none
--              other can be determined. This command may be used multiple times, to set
--              the default flags for dierent commodities; whichever is seen last is used as the
--              default commodity. For example, to set US dollars as the default commodity,
--              while also setting the thousands flag and decimal flag for that commodity, use:
--   
--   D $1,000.00
--   
--   C AMOUNT1 = AMOUNT2
--              Specifies a commodity conversion, where the first amount is given to be equiv-
--              alent to the second amount. The first amount should use the decimal precision
--              desired during reporting:
--   
--   C 1.00 Kb = 1024 bytes
--   
--   i, o, b, h
--              These four relate to timeclock support, which permits ledger to read timelog
--              files. See the timeclocks documentation for more info on the syntax of its
--              timelog files.
--   
module Hledger.Read.JournalReader tests_JournalReader :: Test reader :: Reader -- | Top-level journal parser. Returns a single composite, I/O performing, -- error-raising JournalUpdate (and final JournalContext) -- which can be applied to an empty journal to get the final result. journalFile :: GenParser Char JournalContext (JournalUpdate, JournalContext) journalAddFile :: (FilePath, String) -> Journal -> Journal someamount :: GenParser Char JournalContext MixedAmount -- | Parse an account name. Account names may have single spaces inside -- them, and are terminated by two or more spaces. They should have one -- or more components of at least one character, separated by the account -- separator char. ledgeraccountname :: GenParser Char st AccountName ledgerExclamationDirective :: GenParser Char JournalContext JournalUpdate ledgerHistoricalPrice :: GenParser Char JournalContext HistoricalPrice ledgerDefaultYear :: GenParser Char JournalContext JournalUpdate emptyLine :: GenParser Char JournalContext () ledgerdatetime :: GenParser Char JournalContext LocalTime -- | A reader for the timelog file format generated by timeclock.el. -- -- From timeclock.el 2.6: -- --
--   A timelog contains data in the form of a single entry per line.
--   Each entry has the form:
--   
--   CODE YYYYMMDD HH:MM:SS [COMMENT]
--   
--   CODE is one of: b, h, i, o or O.  COMMENT is optional when the code is
--   i, o or O.  The meanings of the codes are:
--   
--   b  Set the current time balance, or "time debt".  Useful when
--        archiving old log data, when a debt must be carried forward.
--        The COMMENT here is the number of seconds of debt.
--   
--   h  Set the required working time for the given day.  This must
--        be the first entry for that day.  The COMMENT in this case is
--        the number of hours in this workday.  Floating point amounts
--        are allowed.
--   
--   i  Clock in.  The COMMENT in this case should be the name of the
--        project worked on.
--   
--   o  Clock out.  COMMENT is unnecessary, but can be used to provide
--        a description of how the period went, for example.
--   
--   O  Final clock out.  Whatever project was being worked on, it is
--        now finished.  Useful for creating summary reports.
--   
-- -- Example: -- --
--   i 20070310 12:26:00 hledger
--   o 20070310 17:26:02
--   
module Hledger.Read.TimelogReader tests_TimelogReader :: Test reader :: Reader -- | Read hledger data from various data formats, and related utilities. module Hledger.Read tests_Hledger_Read :: Test -- | Read a journal from this file, using the specified data format or -- trying all known formats, or give an error string; also create the -- file if it doesn't exist. readJournalFile :: Maybe String -> FilePath -> IO (Either String Journal) -- | Read a Journal from this string, using the specified data format or -- trying all known formats, or give an error string. readJournal :: Maybe String -> String -> IO (Either String Journal) -- | Read a Journal from this string (and file path), auto-detecting the -- data format, or give a useful error string. Tries to parse each known -- data format in turn. If none succeed, gives the error message specific -- to the intended data format, which if not specified is guessed from -- the file suffix and possibly the data. journalFromPathAndString :: Maybe String -> FilePath -> String -> IO (Either String Journal) -- | Get the user's default journal file path. myJournalPath :: IO String -- | Get the user's default timelog file path. myTimelogPath :: IO String -- | Read the user's default journal file, or give an error. myJournal :: IO Journal -- | Read the user's default timelog file, or give an error. myTimelog :: IO Journal