hledger-lib 1.9 → 1.9.1
raw patch · 33 files changed
+1616/−980 lines, 33 filesdep +tabulardep ~base-compat
Dependencies added: tabular
Dependency ranges changed: base-compat
Files
- CHANGES +12/−0
- Hledger/Data/AccountName.hs +17/−1
- Hledger/Data/Amount.hs +21/−0
- Hledger/Data/AutoTransaction.hs +3/−2
- Hledger/Data/Journal.hs +21/−42
- Hledger/Data/Transaction.hs +17/−11
- Hledger/Data/Types.hs +1/−24
- Hledger/Read.hs +53/−106
- Hledger/Read/Common.hs +46/−9
- Hledger/Read/CsvReader.hs +22/−5
- Hledger/Read/JournalReader.hs +13/−4
- Hledger/Read/TimeclockReader.hs +2/−2
- Hledger/Read/TimedotReader.hs +2/−2
- Hledger/Reports.hs +6/−1
- Hledger/Reports/BalanceReport.hs +1/−1
- Hledger/Reports/BudgetReport.hs +361/−0
- Hledger/Reports/MultiBalanceReports.hs +25/−0
- Hledger/Reports/ReportOptions.hs +0/−3
- Hledger/Reports/ReportTypes.hs +40/−0
- Text/Tabular/AsciiWide.hs +111/−0
- hledger-lib.cabal +81/−66
- hledger_csv.5 +1/−1
- hledger_csv.info +30/−30
- hledger_csv.txt +1/−1
- hledger_journal.5 +205/−185
- hledger_journal.info +311/−291
- hledger_journal.txt +203/−183
- hledger_timeclock.5 +1/−1
- hledger_timeclock.info +2/−2
- hledger_timeclock.txt +1/−1
- hledger_timedot.5 +1/−1
- hledger_timedot.info +4/−4
- hledger_timedot.txt +1/−1
CHANGES view
@@ -2,6 +2,18 @@ Most user-visible changes are noted in the hledger changelog, instead. +# 1.9.1 (2018/4/30)++* new generic PeriodicReport, and some report-related type aliases++* new BudgetReport++* make (readJournal|tryReader)s?WithOpts the default api, dropping "WithOpts"++* automated postings and command line account aliases happen earlier+ in journal processing (see hledger changelog)++ # 1.9 (2018/3/31) * support ghc 8.4, latest deps
Hledger/Data/AccountName.hs view
@@ -57,8 +57,24 @@ accountNameLevel "" = 0 accountNameLevel a = T.length (T.filter (==acctsepchar) a) + 1 +-- | A top-level account prefixed to some accounts in budget reports.+-- Defined here so it can be ignored by accountNameDrop. +unbudgetedAccountName :: T.Text+unbudgetedAccountName = "<unbudgeted>"++-- | Remove some number of account name components from the front of the account name.+-- If the special "<unbudgeted>" top-level account is present, it is preserved and+-- dropping affects the rest of the account name. accountNameDrop :: Int -> AccountName -> AccountName-accountNameDrop n = accountNameFromComponents . drop n . accountNameComponents+accountNameDrop n a+ | a == unbudgetedAccountName = a+ | unbudgetedAccountAndSep `T.isPrefixOf` a =+ case accountNameDrop n $ T.drop (T.length unbudgetedAccountAndSep) a of+ "" -> unbudgetedAccountName+ a' -> unbudgetedAccountAndSep <> a'+ | otherwise = accountNameFromComponents $ drop n $ accountNameComponents a+ where + unbudgetedAccountAndSep = unbudgetedAccountName <> acctsep -- | Sorted unique account names implied by these account names, -- ie these plus all their parent accounts up to the root.
Hledger/Data/Amount.hs view
@@ -61,6 +61,7 @@ amountValue, -- ** rendering amountstyle,+ styleAmount, showAmount, cshowAmount, showAmountWithZeroCommodity,@@ -93,6 +94,7 @@ isReallyZeroMixedAmountCost, mixedAmountValue, -- ** rendering+ styleMixedAmount, showMixedAmount, showMixedAmountOneLine, showMixedAmountDebug,@@ -131,8 +133,14 @@ deriving instance Show MarketPrice ++-------------------------------------------------------------------------------+-- Amount styles++-- | Default amount style amountstyle = AmountStyle L False 0 (Just '.') Nothing + ------------------------------------------------------------------------------- -- Amount @@ -265,6 +273,14 @@ showPriceDebug (UnitPrice pa) = " @ " ++ showAmountDebug pa showPriceDebug (TotalPrice pa) = " @@ " ++ showAmountDebug pa +-- | Given a map of standard amount display styles, apply the appropriate one to this amount.+-- If there's no standard style for this amount's commodity, return the amount unchanged.+styleAmount :: M.Map CommoditySymbol AmountStyle -> Amount -> Amount+styleAmount styles a =+ case M.lookup (acommodity a) styles of+ Just s -> a{astyle=s}+ Nothing -> a + -- | Get the string representation of an amount, based on its -- commodity's display settings. String representations equivalent to -- zero are converted to just \"0\". The special "missing" amount is@@ -555,6 +571,10 @@ -- where a' = normaliseMixedAmountSquashPricesForDisplay a -- b' = normaliseMixedAmountSquashPricesForDisplay b +-- | Given a map of standard amount display styles, apply the appropriate ones to each individual amount.+styleMixedAmount :: M.Map CommoditySymbol AmountStyle -> MixedAmount -> MixedAmount+styleMixedAmount styles (Mixed as) = Mixed $ map (styleAmount styles) as + -- | Get the string representation of a mixed amount, after -- normalising it to one amount per commodity. Assumes amounts have -- no or similar prices, otherwise this can show misleading prices.@@ -647,6 +667,7 @@ mixedAmountValue :: Journal -> Day -> MixedAmount -> MixedAmount mixedAmountValue j d (Mixed as) = Mixed $ map (amountValue j d) as+ ------------------------------------------------------------------------------- -- misc
Hledger/Data/AutoTransaction.hs view
@@ -71,8 +71,9 @@ runModifierTransaction q mt = modifier where q' = simplifyQuery $ And [q, mtvaluequery mt (error "query cannot depend on current time")] mods = map runModifierPosting $ mtpostings mt- generatePostings ps = [m p | p <- ps, q' `matchesPosting` p, m <- mods]- modifier t@(tpostings -> ps) = t { tpostings = ps ++ generatePostings ps }+ generatePostings ps = [p' | p <- ps+ , p' <- if q' `matchesPosting` p then p:[ m p | m <- mods] else [p]]+ modifier t@(tpostings -> ps) = t { tpostings = generatePostings ps } -- | Extract 'Query' equivalent of 'mtvalueexpr' from 'ModifierTransaction' --
Hledger/Data/Journal.hs view
@@ -16,10 +16,10 @@ addModifierTransaction, addPeriodicTransaction, addTransaction,- journalApplyAliases, journalBalanceTransactions, journalApplyCommodityStyles, commodityStylesFromAmounts,+ journalCommodityStyles, journalConvertAmountsToCost, journalFinalise, journalPivot,@@ -485,19 +485,6 @@ -} --- | Apply additional account aliases (eg from the command-line) to all postings in a journal.-journalApplyAliases :: [AccountAlias] -> Journal -> Journal-journalApplyAliases aliases j@Journal{jtxns=ts} =- -- (if null aliases- -- then id- -- else (dbgtrace $- -- "applying additional command-line aliases:\n"- -- ++ chomp (unlines $ map (" "++) $ lines $ ppShow aliases))) $- j{jtxns=map dotransaction ts}- where- dotransaction t@Transaction{tpostings=ps} = t{tpostings=map doposting ps}- doposting p@Posting{paccount=a} = p{paccount= accountNameApplyAliases aliases a}- -- | Do post-parse processing on a parsed journal to make it ready for -- use. Reverse parsed data to normal order, canonicalise amount -- formats, check/ensure that transactions are balanced, and maybe@@ -617,8 +604,11 @@ runExceptT $ do bals <- lift $ HT.newSized size txStore <- lift $ createStore- flip R.runReaderT (Env bals (storeIn txStore) assrt $- Just $ jinferredcommodities j) $ do+ let env = Env bals + (storeIn txStore) + assrt+ (Just $ journalCommodityStyles j)+ flip R.runReaderT env $ do dated <- fmap snd . sortBy (comparing fst) . concat <$> mapM' discriminateByDate (jtxns j) mapM' checkInferAndRegisterAmounts dated@@ -738,7 +728,6 @@ liftModifier :: (Env s -> ST s a) -> CurrentBalancesModifier s a liftModifier f = R.ask >>= lift . lift . f - -- | Choose and apply a consistent display format to the posting -- amounts in each commodity. Each commodity's format is specified by -- a commodity format directive, or otherwise inferred from posting@@ -747,28 +736,20 @@ journalApplyCommodityStyles j@Journal{jtxns=ts, jmarketprices=mps} = j'' where j' = journalInferCommodityStyles j+ styles = journalCommodityStyles j' j'' = j'{jtxns=map fixtransaction ts, jmarketprices=map fixmarketprice mps} fixtransaction t@Transaction{tpostings=ps} = t{tpostings=map fixposting ps}- fixposting p@Posting{pamount=a} = p{pamount=fixmixedamount a}- fixmarketprice mp@MarketPrice{mpamount=a} = mp{mpamount=fixamount a}- fixmixedamount (Mixed as) = Mixed $ map fixamount as- fixamount a@Amount{acommodity=c} = a{astyle=journalCommodityStyle j' c}---- | Get this journal's standard display style for the given--- commodity. That is the style defined by the last corresponding--- commodity format directive if any, otherwise the style inferred--- from the posting amounts (or in some cases, price amounts) in this--- commodity if any, otherwise the default style.-journalCommodityStyle :: Journal -> CommoditySymbol -> AmountStyle-journalCommodityStyle j = fromMaybe amountstyle{asprecision=2} . journalCommodityStyleLookup j+ fixposting p@Posting{pamount=a} = p{pamount=styleMixedAmount styles a}+ fixmarketprice mp@MarketPrice{mpamount=a} = mp{mpamount=styleAmount styles a} -journalCommodityStyleLookup :: Journal -> CommoditySymbol -> Maybe AmountStyle-journalCommodityStyleLookup j c =- listToMaybe $- catMaybes [- M.lookup c (jcommodities j) >>= cformat- ,M.lookup c $ jinferredcommodities j- ]+-- | Get all the amount styles defined in this journal, either +-- declared by a commodity directive (preferred) or inferred from amounts,+-- as a map from symbol to style. +journalCommodityStyles :: Journal -> M.Map CommoditySymbol AmountStyle+journalCommodityStyles j = declaredstyles <> inferredstyles+ where+ declaredstyles = M.mapMaybe cformat $ jcommodities j+ inferredstyles = jinferredcommodities j -- | Infer a display format for each commodity based on the amounts parsed. -- "hledger... will use the format of the first posting amount in the@@ -776,8 +757,8 @@ journalInferCommodityStyles :: Journal -> Journal journalInferCommodityStyles j = j{jinferredcommodities =- commodityStylesFromAmounts $- dbg8 "journalChooseCommmodityStyles using amounts" $ journalAmounts j}+ commodityStylesFromAmounts $+ dbg8 "journalInferCommmodityStyles using amounts" $ journalAmounts j} -- | Given a list of amounts in parse order, build a map from their commodity names -- to standard commodity display formats.@@ -833,10 +814,8 @@ fixtransaction t@Transaction{tpostings=ps} = t{tpostings=map fixposting ps} fixposting p@Posting{pamount=a} = p{pamount=fixmixedamount a} fixmixedamount (Mixed as) = Mixed $ map fixamount as- fixamount = applyJournalStyle . costOfAmount- applyJournalStyle a- | Just s <- journalCommodityStyleLookup j (acommodity a) = a{astyle=s}- | otherwise = a+ fixamount = styleAmount styles . costOfAmount+ styles = journalCommodityStyles j -- -- | Get this journal's unique, display-preference-canonicalised commodities, by symbol. -- journalCanonicalCommodities :: Journal -> M.Map String CommoditySymbol
Hledger/Data/Transaction.hs view
@@ -278,7 +278,7 @@ "inferBalancingAmount" ~: do let p `gives` p' = assertEqual (show p) (Right p') $ inferTransaction p inferTransaction :: Transaction -> Either String Transaction- inferTransaction = runIdentity . runExceptT . inferBalancingAmount (\_ _ -> return ())+ inferTransaction = runIdentity . runExceptT . inferBalancingAmount (\_ _ -> return ()) Map.empty nulltransaction `gives` nulltransaction nulltransaction{ tpostings=[@@ -382,11 +382,11 @@ -- ^ update function -> Maybe (Map.Map CommoditySymbol AmountStyle) -> Transaction -> m Transaction-balanceTransactionUpdate update styles t =- finalize =<< inferBalancingAmount update t+balanceTransactionUpdate update mstyles t =+ finalize =<< inferBalancingAmount update (fromMaybe Map.empty mstyles) t where finalize t' = let t'' = inferBalancingPrices t'- in if isTransactionBalanced styles t''+ in if isTransactionBalanced mstyles t'' then return $ txnTieKnot t'' else throwError $ printerr $ nonzerobalanceerror t'' printerr s = intercalate "\n" [s, showTransactionUnelided t]@@ -409,11 +409,12 @@ -- We can infer a missing amount when there are multiple postings and exactly -- one of them is amountless. If the amounts had price(s) the inferred amount -- have the same price(s), and will be converted to the price commodity.-inferBalancingAmount :: MonadError String m- => (AccountName -> MixedAmount -> m ())- -- ^ update function- -> Transaction -> m Transaction-inferBalancingAmount update t@Transaction{tpostings=ps}+inferBalancingAmount :: MonadError String m =>+ (AccountName -> MixedAmount -> m ()) -- ^ update function+ -> Map.Map CommoditySymbol AmountStyle -- ^ standard amount styles+ -> Transaction+ -> m Transaction+inferBalancingAmount update styles t@Transaction{tpostings=ps} | length amountlessrealps > 1 = throwError $ printerr "could not balance this transaction - can't have more than one real posting with no amount (remember to put 2 or more spaces before amounts)" | length amountlessbvps > 1@@ -432,8 +433,13 @@ inferamount p@Posting{ptype=BalancedVirtualPosting} | not (hasAmount p) = updateAmount p bvsum inferamount p = return p- updateAmount p amt = update (paccount p) amt' >> return p { pamount=amt', porigin=Just $ originalPosting p }- where amt' = normaliseMixedAmount $ costOfMixedAmount (-amt)+ updateAmount p amt = + update (paccount p) amt' >> return p { pamount=amt', porigin=Just $ originalPosting p }+ where+ -- Inferred amounts are converted to cost.+ -- Also, ensure the new amount has the standard style for its commodity + -- (the main amount styling pass happened before this balancing pass). + amt' = styleMixedAmount styles $ normaliseMixedAmount $ costOfMixedAmount (-amt) -- | Infer prices for this transaction's posting amounts, if needed to make -- the postings balance, and if possible. This is done once for the real
Hledger/Data/Types.hs view
@@ -22,7 +22,6 @@ import GHC.Generics (Generic) import Control.DeepSeq (NFData)-import Control.Monad.Except (ExceptT) import Data.Data import Data.Decimal import Data.Default@@ -303,7 +302,7 @@ -- principal data ,jaccounts :: [(AccountName, Maybe AccountCode)] -- ^ accounts that have been declared by account directives ,jcommodities :: M.Map CommoditySymbol Commodity -- ^ commodities and formats declared by commodity directives- ,jinferredcommodities :: M.Map CommoditySymbol AmountStyle -- ^ commodities and formats inferred from journal amounts+ ,jinferredcommodities :: M.Map CommoditySymbol AmountStyle -- ^ commodities and formats inferred from journal amounts XXX misnamed ,jmarketprices :: [MarketPrice] ,jmodifiertxns :: [ModifierTransaction] ,jperiodictxns :: [PeriodicTransaction]@@ -328,28 +327,6 @@ -- | The id of a data format understood by hledger, eg @journal@ or @csv@. -- The --output-format option selects one of these for output. type StorageFormat = String---- | A hledger journal reader is a triple of storage format name, a--- detector of that format, and a parser from that format to Journal.-data Reader = Reader {-- -- The canonical name of the format handled by this reader- rFormat :: StorageFormat-- -- The file extensions recognised as containing this format- ,rExtensions :: [String]-- -- A text parser for this format, accepting an optional rules file,- -- assertion-checking flag, and file path for error messages,- -- producing an exception-raising IO action that returns a journal- -- or error message.- ,rParser :: Maybe FilePath -> Bool -> FilePath -> Text -> ExceptT String IO Journal-- -- Experimental readers are never tried automatically.- ,rExperimental :: Bool- }--instance Show Reader where show r = rFormat r ++ " reader" -- | An account, with name, balances and links to parent/subaccounts -- which let you walk up or down the account tree.
Hledger/Read.hs view
@@ -14,7 +14,6 @@ PrefixedFilePath, defaultJournal, defaultJournalPath,- readJournalFilesWithOpts, readJournalFiles, readJournalFile, requireJournalFileExists,@@ -26,7 +25,6 @@ readJournal', -- * Re-exported- JournalReader.accountaliasp, JournalReader.postingp, module Hledger.Read.Common, @@ -36,10 +34,10 @@ ) where -import Control.Applicative ((<|>)) import Control.Arrow (right) import qualified Control.Exception as C import Control.Monad.Except+import Data.Default import Data.List import Data.Maybe import Data.Ord@@ -90,7 +88,7 @@ -- | Read the default journal file specified by the environment, or raise an error. defaultJournal :: IO Journal-defaultJournal = defaultJournalPath >>= readJournalFile Nothing Nothing True >>= either error' return+defaultJournal = defaultJournalPath >>= readJournalFile def >>= either error' return -- | Get the default journal file path specified by the environment. -- Like ledger, we look first for the LEDGER_FILE environment@@ -112,52 +110,6 @@ home <- getHomeDirectory `C.catch` (\(_::C.IOException) -> return "") return $ home </> journalDefaultFilename --- | @readJournalFiles mformat mrulesfile assrt prefixedfiles@------ Read a Journal from each specified file path and combine them into one.--- Or, return the first error message.------ Combining Journals means concatenating them, basically.--- The parse state resets at the start of each file, which means that--- directives & aliases do not cross file boundaries.--- (The final parse state saved in the Journal does span all files, however.)------ As with readJournalFile,--- file paths can optionally have a READER: prefix,--- and the @mformat@, @mrulesfile, and @assrt@ arguments are supported--- (and these are applied to all files).----readJournalFiles :: Maybe StorageFormat -> Maybe FilePath -> Bool -> [PrefixedFilePath] -> IO (Either String Journal)-readJournalFiles mformat mrulesfile assrt prefixedfiles = do- (right mconcat1 . sequence)- <$> mapM (readJournalFile mformat mrulesfile assrt) prefixedfiles- where mconcat1 :: Monoid t => [t] -> t- mconcat1 [] = mempty- mconcat1 x = foldr1 mappend x---- | @readJournalFile mformat mrulesfile assrt prefixedfile@------ Read a Journal from this file, or from stdin if the file path is -,--- or return an error message. The file path can have a READER: prefix.------ The reader (data format) is chosen based on (in priority order):--- the @mformat@ argument;--- the file path's READER: prefix, if any;--- a recognised file name extension (in readJournal);--- if none of these identify a known reader, all built-in readers are tried in turn.------ A CSV conversion rules file (@mrulesfiles@) can be specified to help convert CSV data.------ Optionally, any balance assertions in the journal can be checked (@assrt@).----readJournalFile :: Maybe StorageFormat -> Maybe FilePath -> Bool -> PrefixedFilePath -> IO (Either String Journal)-readJournalFile mformat mrulesfile assrt prefixedfile = do- let- (mprefixformat, f) = splitReaderPrefix prefixedfile- mfmt = mformat <|> mprefixformat- requireJournalFileExists f- readFileOrStdinPortably f >>= readJournal mfmt mrulesfile assrt (Just f)- -- | If a filepath is prefixed by one of the reader names and a colon, -- split that off. Eg "csv:-" -> (Just "csv", "-"). splitReaderPrefix :: PrefixedFilePath -> (Maybe String, FilePath)@@ -195,7 +147,7 @@ -- | Read a Journal from the given text trying all readers in turn, or throw an error. readJournal' :: Text -> IO Journal-readJournal' t = readJournal Nothing Nothing True Nothing t >>= either error' return+readJournal' t = readJournal def Nothing t >>= either error' return tests_readJournal' = [ "readJournal' parses sample journal" ~: do@@ -203,28 +155,6 @@ assertBool "" True ] --- | @readJournal mformat mrulesfile assrt mfile txt@------ Read a Journal from some text, or return an error message.------ The reader (data format) is chosen based on (in priority order):--- the @mformat@ argument;--- a recognised file name extension in @mfile@ (if provided).--- If none of these identify a known reader, all built-in readers are tried in turn--- (returning the first one's error message if none of them succeed).------ A CSV conversion rules file (@mrulesfiles@) can be specified to help convert CSV data.------ Optionally, any balance assertions in the journal can be checked (@assrt@).----readJournal :: Maybe StorageFormat -> Maybe FilePath -> Bool -> Maybe FilePath -> Text -> IO (Either String Journal)-readJournal mformat mrulesfile assrt mfile txt =- let- stablereaders = filter (not.rExperimental) readers- rs = maybe stablereaders (:[]) $ findReader mformat mfile- in- tryReaders rs mrulesfile assrt mfile txt- -- | @findReader mformat mpath@ -- -- Find the reader named by @mformat@, if provided.@@ -241,43 +171,41 @@ (prefix,path') = splitReaderPrefix path ext = drop 1 $ takeExtension path' --- | @tryReaders readers mrulesfile assrt path t@+-- | Read a Journal from each specified file path and combine them into one.+-- Or, return the first error message. ----- Try to parse the given text to a Journal using each reader in turn,--- returning the first success, or if all of them fail, the first error message.-tryReaders :: [Reader] -> Maybe FilePath -> Bool -> Maybe FilePath -> Text -> IO (Either String Journal)-tryReaders readers mrulesfile assrt path t = firstSuccessOrFirstError [] readers- where- firstSuccessOrFirstError :: [String] -> [Reader] -> IO (Either String Journal)- firstSuccessOrFirstError [] [] = return $ Left "no readers found"- firstSuccessOrFirstError errs (r:rs) = do- dbg1IO "trying reader" (rFormat r)- result <- (runExceptT . (rParser r) mrulesfile assrt path') t- dbg1IO "reader result" $ either id show result- case result of Right j -> return $ Right j -- success!- Left e -> firstSuccessOrFirstError (errs++[e]) rs -- keep trying- firstSuccessOrFirstError (e:_) [] = return $ Left e -- none left, return first error- path' = fromMaybe "(string)" path------ New versions of readJournal* with easier arguments, and support for --new.--readJournalFilesWithOpts :: InputOpts -> [FilePath] -> IO (Either String Journal)-readJournalFilesWithOpts iopts =- (right mconcat1 . sequence <$>) . mapM (readJournalFileWithOpts iopts)+-- Combining Journals means concatenating them, basically.+-- The parse state resets at the start of each file, which means that+-- directives & aliases do not affect subsequent sibling or parent files.+-- They do affect included child files though. +-- Also the final parse state saved in the Journal does span all files.+readJournalFiles :: InputOpts -> [FilePath] -> IO (Either String Journal)+readJournalFiles iopts =+ (right mconcat1 . sequence <$>) . mapM (readJournalFile iopts) where mconcat1 :: Monoid t => [t] -> t mconcat1 [] = mempty mconcat1 x = foldr1 mappend x -readJournalFileWithOpts :: InputOpts -> PrefixedFilePath -> IO (Either String Journal)-readJournalFileWithOpts iopts prefixedfile = do+-- | Read a Journal from this file, or from stdin if the file path is -,+-- or return an error message. The file path can have a READER: prefix.+--+-- The reader (data format) to use is determined from (in priority order):+-- the @mformat_@ specified in the input options, if any;+-- the file path's READER: prefix, if any;+-- a recognised file name extension.+-- if none of these identify a known reader, all built-in readers are tried in turn.+--+-- The input options can also configure balance assertion checking, automated posting+-- generation, a rules file for converting CSV data, etc.+readJournalFile :: InputOpts -> PrefixedFilePath -> IO (Either String Journal)+readJournalFile iopts prefixedfile = do let (mfmt, f) = splitReaderPrefix prefixedfile iopts' = iopts{mformat_=firstJust [mfmt, mformat_ iopts]} requireJournalFileExists f t <- readFileOrStdinPortably f- ej <- readJournalWithOpts iopts' (Just f) t+ ej <- readJournal iopts' (Just f) t case ej of Left e -> return $ Left e Right j | new_ iopts -> do@@ -342,21 +270,40 @@ j' = j{jtxns=newsamedatets++laterts} ds' = latestDates $ map tdate $ samedatets++laterts -readJournalWithOpts :: InputOpts -> Maybe FilePath -> Text -> IO (Either String Journal)-readJournalWithOpts iopts mfile txt =- tryReadersWithOpts iopts mfile specifiedorallreaders txt+-- | @readJournal iopts mfile txt@+--+-- Read a Journal from some text, or return an error message.+--+-- The reader (data format) is chosen based on a recognised file name extension in @mfile@ (if provided).+-- If it does not identify a known reader, all built-in readers are tried in turn+-- (returning the first one's error message if none of them succeed).+--+-- Input ioptions (@iopts@) specify CSV conversion rules file to help convert CSV data,+-- enable or disable balance assertion checking and automated posting generation.+--+readJournal :: InputOpts -> Maybe FilePath -> Text -> IO (Either String Journal)+readJournal iopts mfile txt =+ tryReaders iopts mfile specifiedorallreaders txt where specifiedorallreaders = maybe stablereaders (:[]) $ findReader (mformat_ iopts) mfile stablereaders = filter (not.rExperimental) readers -tryReadersWithOpts :: InputOpts -> Maybe FilePath -> [Reader] -> Text -> IO (Either String Journal)-tryReadersWithOpts iopts mpath readers txt = firstSuccessOrFirstError [] readers+-- | @tryReaders iopts readers path t@+--+-- Try to parse the given text to a Journal using each reader in turn,+-- returning the first success, or if all of them fail, the first error message.+-- +-- Input ioptions (@iopts@) specify CSV conversion rules file to help convert CSV data,+-- enable or disable balance assertion checking and automated posting generation.+--+tryReaders :: InputOpts -> Maybe FilePath -> [Reader] -> Text -> IO (Either String Journal)+tryReaders iopts mpath readers txt = firstSuccessOrFirstError [] readers where firstSuccessOrFirstError :: [String] -> [Reader] -> IO (Either String Journal) firstSuccessOrFirstError [] [] = return $ Left "no readers found" firstSuccessOrFirstError errs (r:rs) = do dbg1IO "trying reader" (rFormat r)- result <- (runExceptT . (rParser r) (mrules_file_ iopts) (not $ ignore_assertions_ iopts) path) txt+ result <- (runExceptT . (rParser r) iopts path) txt dbg1IO "reader result" $ either id show result case result of Right j -> return $ Right j -- success! Left e -> firstSuccessOrFirstError (errs++[e]) rs -- keep trying@@ -408,7 +355,7 @@ "journal" ~: do r <- runExceptT $ parseWithState mempty JournalReader.journalp "" assertBool "journalp should parse an empty file" (isRight $ r)- jE <- readJournal Nothing Nothing True Nothing "" -- don't know how to get it from journal+ jE <- readJournal def Nothing "" -- don't know how to get it from journal either error' (assertBool "journalp parsing an empty file should give an empty journal" . null . jtxns) jE ]
Hledger/Read/Common.hs view
@@ -47,7 +47,29 @@ import Hledger.Data import Hledger.Utils+import qualified Hledger.Query as Q (Query(Any)) +-- | A hledger journal reader is a triple of storage format name, a+-- detector of that format, and a parser from that format to Journal.+data Reader = Reader {++ -- The canonical name of the format handled by this reader+ rFormat :: StorageFormat++ -- The file extensions recognised as containing this format+ ,rExtensions :: [String]++ -- A text parser for this format, accepting input options, file+ -- path for error messages and file contents, producing an exception-raising IO+ -- action that returns a journal or error message.+ ,rParser :: InputOpts -> FilePath -> Text -> ExceptT String IO Journal++ -- Experimental readers are never tried automatically.+ ,rExperimental :: Bool+ }++instance Show Reader where show r = rFormat r ++ " reader"+ -- $setup -- | Various options to use when reading journal files.@@ -63,12 +85,13 @@ ,new_ :: Bool -- ^ read only new transactions since this file was last read ,new_save_ :: Bool -- ^ save latest new transactions state for next time ,pivot_ :: String -- ^ use the given field's value as the account name + ,auto_ :: Bool -- ^ generate automatic postings when journal is parsed } deriving (Show, Data) --, Typeable) instance Default InputOpts where def = definputopts definputopts :: InputOpts-definputopts = InputOpts def def def def def def True def+definputopts = InputOpts def def def def def def True def def rawOptsToInputOpts :: RawOpts -> InputOpts rawOptsToInputOpts rawopts = InputOpts{@@ -81,6 +104,7 @@ ,new_ = boolopt "new" rawopts ,new_save_ = True ,pivot_ = stringopt "pivot" rawopts+ ,auto_ = boolopt "auto" rawopts } --- * parsing utils@@ -115,27 +139,40 @@ | otherwise = unPos $ sourceLine p' -- might be at end of file withat last new-line --- | Given a megaparsec ParsedJournal parser, balance assertion flag, file+-- | Generate Automatic postings and add them to the current journal.+generateAutomaticPostings :: Journal -> Journal+generateAutomaticPostings j = j { jtxns = map modifier $ jtxns j }+ where+ modifier = foldr (flip (.) . runModifierTransaction') id mtxns+ runModifierTransaction' = fmap txnTieKnot . runModifierTransaction Q.Any+ mtxns = jmodifiertxns j++-- | Given a megaparsec ParsedJournal parser, input options, file -- path and file content: parse and post-process a Journal, or give an error.-parseAndFinaliseJournal :: ErroringJournalParser IO ParsedJournal -> Bool- -> FilePath -> Text -> ExceptT String IO Journal-parseAndFinaliseJournal parser assrt f txt = do+parseAndFinaliseJournal :: ErroringJournalParser IO ParsedJournal -> InputOpts+ -> FilePath -> Text -> ExceptT String IO Journal+parseAndFinaliseJournal parser iopts f txt = do t <- liftIO getClockTime y <- liftIO getCurrentYear ep <- runParserT (evalStateT parser nulljournal {jparsedefaultyear=Just y}) f txt case ep of- Right pj -> case journalFinalise t f txt assrt pj of+ Right pj -> + let pj' = if auto_ iopts then generateAutomaticPostings pj else pj in+ case journalFinalise t f txt (not $ ignore_assertions_ iopts) pj' of Right j -> return j Left e -> throwError e Left e -> throwError $ parseErrorPretty e -parseAndFinaliseJournal' :: JournalParser Identity ParsedJournal -> Bool -> FilePath -> Text -> ExceptT String IO Journal-parseAndFinaliseJournal' parser assrt f txt = do+parseAndFinaliseJournal' :: JournalParser Identity ParsedJournal -> InputOpts + -> FilePath -> Text -> ExceptT String IO Journal+parseAndFinaliseJournal' parser iopts f txt = do t <- liftIO getClockTime y <- liftIO getCurrentYear let ep = runParser (evalStateT parser nulljournal {jparsedefaultyear=Just y}) f txt case ep of- Right pj -> case journalFinalise t f txt assrt pj of+ Right pj -> + let pj' = if auto_ iopts then generateAutomaticPostings pj else pj in + case journalFinalise t f txt (not $ ignore_assertions_ iopts) pj' of Right j -> return j Left e -> throwError e Left e -> throwError $ parseErrorPretty e
Hledger/Read/CsvReader.hs view
@@ -60,7 +60,7 @@ import Hledger.Data import Hledger.Utils.UTF8IOCompat (getContents) import Hledger.Utils-import Hledger.Read.Common (amountp, statusp, genericSourcePos)+import Hledger.Read.Common (Reader(..),InputOpts(..),amountp, statusp, genericSourcePos) reader :: Reader@@ -73,8 +73,9 @@ -- | Parse and post-process a "Journal" from CSV data, or give an error. -- XXX currently ignores the string and reads from the file path-parse :: Maybe FilePath -> Bool -> FilePath -> Text -> ExceptT String IO Journal-parse rulesfile _ f t = do+parse :: InputOpts -> FilePath -> Text -> ExceptT String IO Journal+parse iopts f t = do+ let rulesfile = mrules_file_ iopts r <- liftIO $ readJournalFromCsv rulesfile f t case r of Left e -> throwError e Right j -> return $ journalNumberAndTieTransactions j@@ -725,10 +726,26 @@ type CsvAmountString = String -- | Canonicalise the sign in a CSV amount string.--- Such strings can be parenthesized, which is equivalent to having a minus sign.--- Also they can end up with a double minus sign, which cancels out.+-- Such strings can have a minus sign, negating parentheses, +-- or any two of these (which cancels out).+--+-- >>> simplifySign "1"+-- "1"+-- >>> simplifySign "-1"+-- "-1"+-- >>> simplifySign "(1)"+-- "-1"+-- >>> simplifySign "--1"+-- "1"+-- >>> simplifySign "-(1)"+-- "1"+-- >>> simplifySign "(-1)"+-- "1"+-- >>> simplifySign "((1))"+-- "1" simplifySign :: CsvAmountString -> CsvAmountString simplifySign ('(':s) | lastMay s == Just ')' = simplifySign $ negateStr $ init s+simplifySign ('-':'(':s) | lastMay s == Just ')' = simplifySign $ init s simplifySign ('-':'-':s) = s simplifySign s = s
Hledger/Read/JournalReader.hs view
@@ -63,8 +63,7 @@ -- numberp, statusp, emptyorcommentlinep,- followingcommentp,- accountaliasp+ followingcommentp -- * Tests ,tests_Hledger_Read_JournalReader@@ -119,8 +118,18 @@ -- | Parse and post-process a "Journal" from hledger's journal file -- format, or give an error.-parse :: Maybe FilePath -> Bool -> FilePath -> Text -> ExceptT String IO Journal-parse _ = parseAndFinaliseJournal journalp+parse :: InputOpts -> FilePath -> Text -> ExceptT String IO Journal+parse iopts = parseAndFinaliseJournal journalp' iopts+ where+ journalp' = do + -- reverse parsed aliases to ensure that they are applied in order given on commandline+ mapM_ addAccountAlias (reverse $ aliasesFromOpts iopts) + journalp++-- | Get the account name aliases from options, if any.+aliasesFromOpts :: InputOpts -> [AccountAlias]+aliasesFromOpts = map (\a -> fromparse $ runParser accountaliasp ("--alias "++quoteIfNeeded a) $ T.pack a)+ . aliases_ --- * parsers --- ** journal
Hledger/Read/TimeclockReader.hs view
@@ -79,8 +79,8 @@ -- | Parse and post-process a "Journal" from timeclock.el's timeclock -- format, saving the provided file path and the current time, or give an -- error.-parse :: Maybe FilePath -> Bool -> FilePath -> Text -> ExceptT String IO Journal-parse _ = parseAndFinaliseJournal timeclockfilep+parse :: InputOpts -> FilePath -> Text -> ExceptT String IO Journal+parse = parseAndFinaliseJournal timeclockfilep timeclockfilep :: ErroringJournalParser IO ParsedJournal timeclockfilep = do many timeclockitemp
Hledger/Read/TimedotReader.hs view
@@ -65,8 +65,8 @@ } -- | Parse and post-process a "Journal" from the timedot format, or give an error.-parse :: Maybe FilePath -> Bool -> FilePath -> Text -> ExceptT String IO Journal-parse _ = parseAndFinaliseJournal timedotfilep+parse :: InputOpts -> FilePath -> Text -> ExceptT String IO Journal+parse = parseAndFinaliseJournal timedotfilep timedotfilep :: JournalParser m ParsedJournal timedotfilep = do many timedotfileitemp
Hledger/Reports.hs view
@@ -10,11 +10,13 @@ module Hledger.Reports ( module Hledger.Reports.ReportOptions,+ module Hledger.Reports.ReportTypes, module Hledger.Reports.EntriesReport, module Hledger.Reports.PostingsReport, module Hledger.Reports.TransactionsReports, module Hledger.Reports.BalanceReport, module Hledger.Reports.MultiBalanceReports,+ module Hledger.Reports.BudgetReport, -- module Hledger.Reports.BalanceHistoryReport, -- * Tests@@ -25,11 +27,13 @@ import Test.HUnit import Hledger.Reports.ReportOptions+import Hledger.Reports.ReportTypes import Hledger.Reports.EntriesReport import Hledger.Reports.PostingsReport import Hledger.Reports.TransactionsReports import Hledger.Reports.BalanceReport import Hledger.Reports.MultiBalanceReports+import Hledger.Reports.BudgetReport -- import Hledger.Reports.BalanceHistoryReport tests_Hledger_Reports :: Test@@ -40,5 +44,6 @@ tests_Hledger_Reports_EntriesReport, tests_Hledger_Reports_PostingsReport, tests_Hledger_Reports_BalanceReport,- tests_Hledger_Reports_MultiBalanceReport+ tests_Hledger_Reports_MultiBalanceReport,+ tests_Hledger_Reports_BudgetReport ]
Hledger/Reports/BalanceReport.hs view
@@ -350,7 +350,7 @@ ] ,"accounts report with cost basis" ~: do- j <- (readJournal Nothing Nothing Nothing $ unlines+ j <- (readJournal def Nothing $ unlines ["" ,"2008/1/1 test " ," a:b 10h @ $50"
+ Hledger/Reports/BudgetReport.hs view
@@ -0,0 +1,361 @@+{- |+-}++{-# LANGUAGE CPP #-}+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE ScopedTypeVariables #-}++module Hledger.Reports.BudgetReport+where++import Data.Decimal+import Data.List+import Data.Maybe+#if !(MIN_VERSION_base(4,11,0))+import Data.Monoid ((<>))+#endif+import Data.Ord+import Data.Time.Calendar+import Safe+import Test.HUnit+--import Data.List+--import Data.Maybe+import qualified Data.Map as Map+import Data.Map (Map)+import qualified Data.Text as T+--import qualified Data.Text.Lazy as TL+--import System.Console.CmdArgs.Explicit as C+--import Lucid as L+--import Text.CSV+--import Test.HUnit+import Text.Printf (printf)+import Text.Tabular as T+--import Text.Tabular.AsciiWide++import Hledger.Data+--import Hledger.Query+import Hledger.Utils+--import Hledger.Read (mamountp')+import Hledger.Reports.ReportOptions+import Hledger.Reports.ReportTypes+import Hledger.Reports.MultiBalanceReports+++--type MultiBalanceReportRow = (AccountName, AccountName, Int, [MixedAmount], MixedAmount, MixedAmount)+--type MultiBalanceReportTotals = ([MixedAmount], MixedAmount, MixedAmount) -- (Totals list, sum of totals, average of totals)++--type PeriodicReportRow a =+-- ( AccountName -- ^ A full account name.+-- , [a] -- ^ The data value for each subperiod.+-- , a -- ^ The total of this row's values.+-- , a -- ^ The average of this row's values.+-- )++type BudgetGoal = Change+type BudgetTotal = Total+type BudgetAverage = Average++-- | A budget report tracks expected and actual changes per account and subperiod.+type BudgetReport = PeriodicReport (Maybe Change, Maybe BudgetGoal)++-- | Calculate budget goals from all periodic transactions,+-- actual balance changes from the regular transactions,+-- and compare these to get a 'BudgetReport'.+-- Unbudgeted accounts may be hidden or renamed (see budgetRollup).+budgetReport :: ReportOpts -> Bool -> Bool -> DateSpan -> Day -> Journal -> BudgetReport+budgetReport ropts assrt showunbudgeted reportspan d j =+ let+ q = queryFromOpts d ropts + budgetedaccts = + dbg2 "budgetedacctsinperiod" $+ accountNamesFromPostings $ + concatMap tpostings $ + concatMap (flip runPeriodicTransaction reportspan) $ + jperiodictxns j+ actualj = dbg1 "actualj" $ budgetRollUp budgetedaccts showunbudgeted j+ budgetj = dbg1 "budgetj" $ budgetJournal assrt ropts reportspan j+ actualreport@(MultiBalanceReport (actualspans, _, _)) = dbg1 "actualreport" $ multiBalanceReport ropts q actualj+ budgetgoalreport@(MultiBalanceReport (_, budgetgoalitems, budgetgoaltotals)) = dbg1 "budgetgoalreport" $ multiBalanceReport ropts q budgetj+ budgetgoalreport'+ -- If no interval is specified:+ -- budgetgoalreport's span might be shorter actualreport's due to periodic txns; + -- it should be safe to replace it with the latter, so they combine well. + | interval_ ropts == NoInterval = MultiBalanceReport (actualspans, budgetgoalitems, budgetgoaltotals)+ | otherwise = budgetgoalreport + in+ dbg1 "budgetreport" $ combineBudgetAndActual budgetgoalreport' actualreport++-- | Use all periodic transactions in the journal to generate +-- budget transactions in the specified report period.+-- Budget transactions are similar to forecast transactions except+-- their purpose is to set goal amounts (of change) per account and period.+budgetJournal :: Bool -> ReportOpts -> DateSpan -> Journal -> Journal+budgetJournal assrt _ropts reportspan j =+ either error' id $ journalBalanceTransactions assrt j{ jtxns = budgetts }+ where+ budgetspan = dbg2 "budgetspan" $ reportspan+ budgetts =+ dbg1 "budgetts" $+ [makeBudgetTxn t+ | pt <- jperiodictxns j+ , t <- runPeriodicTransaction pt budgetspan+ ]+ makeBudgetTxn t = txnTieKnot $ t { tdescription = T.pack "Budget transaction" }++-- | Adjust a journal's account names for budget reporting, in two ways:+--+-- 1. accounts with no budget goal anywhere in their ancestry are moved +-- under the "unbudgeted" top level account.+--+-- 2. subaccounts with no budget goal are merged with their closest parent account+-- with a budget goal, so that only budgeted accounts are shown. +-- This can be disabled by --show-unbudgeted.+--+budgetRollUp :: [AccountName] -> Bool -> Journal -> Journal+budgetRollUp budgetedaccts showunbudgeted j = j { jtxns = remapTxn <$> jtxns j }+ where+ remapTxn = mapPostings (map remapPosting)+ where+ mapPostings f t = txnTieKnot $ t { tpostings = f $ tpostings t }+ remapPosting p = p { paccount = remapAccount $ paccount p, porigin = Just . fromMaybe p $ porigin p }+ where+ remapAccount a+ | hasbudget = a+ | hasbudgetedparent = if showunbudgeted then a else budgetedparent + | otherwise = if showunbudgeted then u <> acctsep <> a else u+ where+ hasbudget = a `elem` budgetedaccts+ hasbudgetedparent = not $ T.null budgetedparent+ budgetedparent = headDef "" $ filter (`elem` budgetedaccts) $ parentAccountNames a+ u = unbudgetedAccountName++-- | Combine a per-account-and-subperiod report of budget goals, and one+-- of actual change amounts, into a budget performance report.+-- The two reports should have the same report interval, but need not+-- have exactly the same account rows or date columns.+-- (Cells in the combined budget report can be missing a budget goal,+-- an actual amount, or both.) The combined report will include:+--+-- - consecutive subperiods at the same interval as the two reports,+-- spanning the period of both reports+--+-- - all accounts mentioned in either report, sorted by account code or+-- account name or amount as appropriate.+--+combineBudgetAndActual :: MultiBalanceReport -> MultiBalanceReport -> BudgetReport+combineBudgetAndActual+ (MultiBalanceReport (budgetperiods, budgetrows, (budgettots, budgetgrandtot, budgetgrandavg)))+ (MultiBalanceReport (actualperiods, actualrows, (actualtots, actualgrandtot, actualgrandavg))) =+ let+ periods = nub $ sort $ filter (/= nulldatespan) $ budgetperiods ++ actualperiods++ -- first, combine any corresponding budget goals with actual changes+ rows1 =+ [ (acct, treeacct, treeindent, amtandgoals, totamtandgoal, avgamtandgoal)+ | (acct, treeacct, treeindent, actualamts, actualtot, actualavg) <- actualrows+ , let mbudgetgoals = Map.lookup acct budgetGoalsByAcct :: Maybe ([BudgetGoal], BudgetTotal, BudgetAverage)+ , let budgetmamts = maybe (replicate (length periods) Nothing) (map Just . first3) mbudgetgoals :: [Maybe BudgetGoal]+ , let mbudgettot = maybe Nothing (Just . second3) mbudgetgoals :: Maybe BudgetTotal+ , let mbudgetavg = maybe Nothing (Just . third3) mbudgetgoals :: Maybe BudgetAverage+ , let acctBudgetByPeriod = Map.fromList [ (p,budgetamt) | (p, Just budgetamt) <- zip budgetperiods budgetmamts ] :: Map DateSpan BudgetGoal+ , let acctActualByPeriod = Map.fromList [ (p,actualamt) | (p, Just actualamt) <- zip actualperiods (map Just actualamts) ] :: Map DateSpan Change+ , let amtandgoals = [ (Map.lookup p acctActualByPeriod, Map.lookup p acctBudgetByPeriod) | p <- periods ] :: [(Maybe Change, Maybe BudgetGoal)]+ , let totamtandgoal = (Just actualtot, mbudgettot)+ , let avgamtandgoal = (Just actualavg, mbudgetavg)+ ]+ where+ budgetGoalsByAcct :: Map AccountName ([BudgetGoal], BudgetTotal, BudgetAverage) =+ Map.fromList [ (acct, (amts, tot, avg)) | (acct, _, _, amts, tot, avg) <- budgetrows ]++ -- next, make rows for budget goals with no actual changes+ rows2 =+ [ (acct, treeacct, treeindent, amtandgoals, totamtandgoal, avgamtandgoal)+ | (acct, treeacct, treeindent, budgetgoals, budgettot, budgetavg) <- budgetrows+ , not $ acct `elem` acctsdone+ , let acctBudgetByPeriod = Map.fromList $ zip budgetperiods budgetgoals :: Map DateSpan BudgetGoal+ , let amtandgoals = [ (Nothing, Map.lookup p acctBudgetByPeriod) | p <- periods ] :: [(Maybe Change, Maybe BudgetGoal)]+ , let totamtandgoal = (Nothing, Just budgettot)+ , let avgamtandgoal = (Nothing, Just budgetavg)+ ]+ where+ acctsdone = map first6 rows1++ -- combine and re-sort rows+ -- TODO: respect hierarchy in tree mode+ -- TODO: respect --sort-amount+ -- TODO: add --sort-budget to sort by budget goal amount+ rows :: [PeriodicReportRow (Maybe Change, Maybe BudgetGoal)] =+ sortBy (comparing first6) $ rows1 ++ rows2+-- massive duplication from multiBalanceReport to handle tree mode sorting ?+-- dbg1 "sorteditems" $+-- sortitems items+-- where+-- sortitems+-- | sort_amount_ opts && accountlistmode_ opts == ALTree = sortTreeMultiBalanceReportRowsByAmount+-- | sort_amount_ opts = sortFlatMultiBalanceReportRowsByAmount+-- | not (sort_amount_ opts) && accountlistmode_ opts == ALTree = sortTreeMultiBalanceReportRowsByAccountCodeAndName+-- | otherwise = sortFlatMultiBalanceReportRowsByAccountCodeAndName+-- where+-- -- Sort the report rows, representing a flat account list, by row total.+-- sortFlatMultiBalanceReportRowsByAmount = sortBy (maybeflip $ comparing fifth6)+-- where+-- maybeflip = if normalbalance_ opts == Just NormallyNegative then id else flip+--+-- -- Sort the report rows, representing a tree of accounts, by row total at each level.+-- -- To do this we recreate an Account tree with the row totals as balances,+-- -- so we can do a hierarchical sort, flatten again, and then reorder the+-- -- report rows similarly. Yes this is pretty long winded.+-- sortTreeMultiBalanceReportRowsByAmount rows = sortedrows+-- where+-- anamesandrows = [(first6 r, r) | r <- rows]+-- anames = map fst anamesandrows+-- atotals = [(a,tot) | (a,_,_,_,tot,_) <- rows]+-- nametree = treeFromPaths $ map expandAccountName anames+-- accounttree = nameTreeToAccount "root" nametree+-- accounttreewithbals = mapAccounts setibalance accounttree+-- where+-- -- this error should not happen, but it's ugly TODO+-- setibalance a = a{aibalance=fromMaybe (error "sortTreeMultiBalanceReportRowsByAmount 1") $ lookup (aname a) atotals}+-- sortedaccounttree = sortAccountTreeByAmount (fromMaybe NormallyPositive $ normalbalance_ opts) accounttreewithbals+-- sortedaccounts = drop 1 $ flattenAccounts sortedaccounttree+-- -- dropped the root account, also ignore any parent accounts not in rows+-- sortedrows = concatMap (\a -> maybe [] (:[]) $ lookup (aname a) anamesandrows) sortedaccounts+--+-- -- Sort the report rows by account code if any, with the empty account code coming last, then account name.+-- sortFlatMultiBalanceReportRowsByAccountCodeAndName = sortBy (comparing acodeandname)+-- where+-- acodeandname r = (acode', aname)+-- where+-- aname = first6 r+-- macode = fromMaybe Nothing $ lookup aname $ jaccounts j+-- acode' = fromMaybe maxBound macode+--+-- -- Sort the report rows, representing a tree of accounts, by account code and then account name at each level.+-- -- Convert a tree of account names, look up the account codes, sort and flatten the tree, reorder the rows.+-- sortTreeMultiBalanceReportRowsByAccountCodeAndName rows = sortedrows+-- where+-- anamesandrows = [(first6 r, r) | r <- rows]+-- anames = map fst anamesandrows+-- nametree = treeFromPaths $ map expandAccountName anames+-- accounttree = nameTreeToAccount "root" nametree+-- accounttreewithcodes = mapAccounts (accountSetCodeFrom j) accounttree+-- sortedaccounttree = sortAccountTreeByAccountCodeAndName accounttreewithcodes+-- sortedaccounts = drop 1 $ flattenAccounts sortedaccounttree+-- -- dropped the root account, also ignore any parent accounts not in rows+-- sortedrows = concatMap (\a -> maybe [] (:[]) $ lookup (aname a) anamesandrows) sortedaccounts+--++ -- TODO: grand total & average shows 0% when there are no actual amounts, inconsistent with other cells+ totalrow =+ ( ""+ , ""+ , 0+ , [ (Map.lookup p totActualByPeriod, Map.lookup p totBudgetByPeriod) | p <- periods ] :: [(Maybe Total, Maybe BudgetTotal)]+ , ( Just actualgrandtot, Just budgetgrandtot ) :: (Maybe Total, Maybe BudgetTotal)+ , ( Just actualgrandavg, Just budgetgrandavg ) :: (Maybe Total, Maybe BudgetTotal)+ )+ where+ totBudgetByPeriod = Map.fromList $ zip budgetperiods budgettots :: Map DateSpan BudgetTotal+ totActualByPeriod = Map.fromList $ zip actualperiods actualtots :: Map DateSpan Change++ in+ PeriodicReport+ ( periods+ , rows+ , totalrow+ )++-- | Figure out the overall period of a BudgetReport.+budgetReportSpan :: BudgetReport -> DateSpan+budgetReportSpan (PeriodicReport ([], _, _)) = DateSpan Nothing Nothing+budgetReportSpan (PeriodicReport (spans, _, _)) = DateSpan (spanStart $ head spans) (spanEnd $ last spans)++-- | Render a budget report as plain text suitable for console output.+budgetReportAsText :: ReportOpts -> BudgetReport -> String+budgetReportAsText ropts budgetr =+ printf "Budget performance in %s:\n\n" (showDateSpan $ budgetReportSpan budgetr)+ ++ + tableAsText ropts showcell (budgetReportAsTable ropts budgetr)+ where+ -- XXX lay out actual, percentage and/or goal in the single table cell for now, should probably use separate cells+ showcell :: (Maybe Change, Maybe BudgetGoal) -> String+ showcell (mactual, mbudget) = actualstr ++ " " ++ budgetstr+ where+ actualwidth = 7+ percentwidth = 4+ budgetwidth = 5+ actual = fromMaybe 0 mactual+ actualstr = printf ("%"++show actualwidth++"s") (showamt actual)+ budgetstr = case mbudget of+ Nothing -> replicate (percentwidth + 7 + budgetwidth) ' '+ Just budget ->+ case percentage actual budget of+ Just pct ->+ printf ("[%"++show percentwidth++"s%% of %"++show budgetwidth++"s]")+ (show $ roundTo 0 pct) (showbudgetamt budget)+ Nothing ->+ printf ("["++replicate (percentwidth+5) ' '++"%"++show budgetwidth++"s]")+ (showbudgetamt budget)++ -- | Calculate the percentage of actual change to budget goal to show, if any.+ -- Both amounts are converted to cost, if possible, before comparing.+ -- A percentage will not be shown if:+ -- - actual or goal are not the same, single, commodity+ -- - the goal is zero+ percentage :: Change -> BudgetGoal -> Maybe Percentage+ percentage actual budget =+ case (toCost actual, toCost budget) of+ (Mixed [a], Mixed [b]) | (acommodity a == acommodity b || isZeroAmount a) && not (isZeroAmount b) + -> Just $ 100 * aquantity a / aquantity b+ _ -> Nothing+ where+ toCost = normaliseMixedAmount . costOfMixedAmount ++ showamt :: MixedAmount -> String+ showamt | color_ ropts = cshowMixedAmountOneLineWithoutPrice+ | otherwise = showMixedAmountOneLineWithoutPrice++ -- don't show the budget amount in color, it messes up alignment+ showbudgetamt = showMixedAmountOneLineWithoutPrice++-- | Build a 'Table' from a multi-column balance report.+budgetReportAsTable :: ReportOpts -> BudgetReport -> Table String String (Maybe MixedAmount, Maybe MixedAmount)+budgetReportAsTable + ropts + (PeriodicReport+ ( periods+ , rows+ , (_, _, _, coltots, grandtot, grandavg)+ )) =+ addtotalrow $ + Table+ (T.Group NoLine $ map Header accts)+ (T.Group NoLine $ map Header colheadings)+ (map rowvals rows)+ where+ colheadings = map showDateSpanMonthAbbrev periods+ ++ (if row_total_ ropts then [" Total"] else [])+ ++ (if average_ ropts then ["Average"] else [])+ accts = map renderacct rows+ renderacct (a,a',i,_,_,_)+ | tree_ ropts = replicate ((i-1)*2) ' ' ++ T.unpack a'+ | otherwise = T.unpack $ maybeAccountNameDrop ropts a+ rowvals (_,_,_,as,rowtot,rowavg) = as+ ++ (if row_total_ ropts then [rowtot] else [])+ ++ (if average_ ropts then [rowavg] else [])+ addtotalrow | no_total_ ropts = id+ | otherwise = (+----+ (row "" $+ coltots+ ++ (if row_total_ ropts && not (null coltots) then [grandtot] else [])+ ++ (if average_ ropts && not (null coltots) then [grandavg] else [])+ ))++-- XXX here for now+-- | Drop leading components of accounts names as specified by --drop, but only in --flat mode.+maybeAccountNameDrop :: ReportOpts -> AccountName -> AccountName+maybeAccountNameDrop opts a | tree_ opts = a+ | otherwise = accountNameDrop (drop_ opts) a++tests_Hledger_Reports_BudgetReport :: Test+tests_Hledger_Reports_BudgetReport = TestList [+ ]
Hledger/Reports/MultiBalanceReports.hs view
@@ -12,6 +12,8 @@ balanceReportFromMultiBalanceReport, mbrNegate, mbrNormaliseSign,+ multiBalanceReportSpan,+ tableAsText, -- -- * Tests tests_Hledger_Reports_MultiBalanceReport@@ -24,6 +26,8 @@ import Data.Time.Calendar import Safe import Test.HUnit+import Text.Tabular as T+import Text.Tabular.AsciiWide import Hledger.Data import Hledger.Query@@ -259,6 +263,11 @@ mbrRowNegate (acct,shortacct,indent,amts,tot,avg) = (acct,shortacct,indent,map negate amts,-tot,-avg) mbrTotalsRowNegate (amts,tot,avg) = (map negate amts,-tot,-avg) +-- | Figure out the overall date span of a multicolumn balance report.+multiBalanceReportSpan :: MultiBalanceReport -> DateSpan+multiBalanceReportSpan (MultiBalanceReport ([], _, _)) = DateSpan Nothing Nothing+multiBalanceReportSpan (MultiBalanceReport (colspans, _, _)) = DateSpan (spanStart $ head colspans) (spanEnd $ last colspans)+ -- | Generates a simple non-columnar BalanceReport, but using multiBalanceReport, -- in order to support --historical. Does not support tree-mode boring parent eliding. -- If the normalbalance_ option is set, it adjusts the sorting and sign of amounts @@ -321,6 +330,22 @@ ], Mixed [usd0]) ]++-- common rendering helper, XXX here for now++tableAsText :: ReportOpts -> (a -> String) -> Table String String a -> String+tableAsText (ReportOpts{pretty_tables_ = pretty}) showcell =+ unlines+ . trimborder+ . lines+ . render pretty id id showcell+ . align+ where+ trimborder = drop 1 . init . map (drop 1 . init)+ align (Table l t d) = Table l' t d+ where+ acctswidth = maximum' $ map strWidth (headerContents l)+ l' = padRightWide acctswidth <$> l tests_Hledger_Reports_MultiBalanceReport :: Test tests_Hledger_Reports_MultiBalanceReport = TestList
Hledger/Reports/ReportOptions.hs view
@@ -115,7 +115,6 @@ -- normally positive for a more conventional display. ,color_ :: Bool ,forecast_ :: Bool- ,auto_ :: Bool } deriving (Show, Data, Typeable) instance Default ReportOpts where def = defreportopts@@ -148,7 +147,6 @@ def def def- def rawOptsToReportOpts :: RawOpts -> IO ReportOpts rawOptsToReportOpts rawopts = checkReportOpts <$> do@@ -181,7 +179,6 @@ ,pretty_tables_ = boolopt "pretty-tables" rawopts' ,color_ = color ,forecast_ = boolopt "forecast" rawopts'- ,auto_ = boolopt "auto" rawopts' } -- | Do extra validation of raw option values, raising an error if there's a problem.
+ Hledger/Reports/ReportTypes.hs view
@@ -0,0 +1,40 @@+{- |+New common report types, used by the BudgetReport for now, perhaps all reports later.+-}++module Hledger.Reports.ReportTypes+where++import Data.Decimal+import Hledger.Data++type Percentage = Decimal++type Change = MixedAmount -- ^ A change in balance during a certain period.+type Balance = MixedAmount -- ^ An ending balance as of some date.+type Total = MixedAmount -- ^ The sum of 'Change's in a report or a report row. Does not make sense for 'Balance's.+type Average = MixedAmount -- ^ The average of 'Change's or 'Balance's in a report or report row.++-- | A generic tabular report of some value, where each row corresponds to an account+-- and each column is a date period. The column periods are usually consecutive subperiods+-- formed by splitting the overall report period by some report interval (daily, weekly, etc.)+-- Depending on the value type, this can be a report of balance changes, ending balances,+-- budget performance, etc. Successor to MultiBalanceReport.+data PeriodicReport a =+ PeriodicReport+ ( [DateSpan] -- The subperiods formed by splitting the overall report period by the report interval.+ -- For ending-balance reports, only the end date is significant.+ -- Usually displayed as report columns.+ , [PeriodicReportRow a] -- One row per account in the report.+ , PeriodicReportRow a -- The grand totals row. The account name in this row is always empty.+ )+ deriving (Show)++type PeriodicReportRow a =+ ( AccountName -- A full account name.+ , AccountName -- Shortened form of the account name to display in tree mode. Usually the leaf name, possibly with parent accounts prefixed.+ , Int -- Indent level for displaying this account name in tree mode. 0, 1, 2... + , [a] -- The data value for each subperiod.+ , a -- The total of this row's values.+ , a -- The average of this row's values.+ )
+ Text/Tabular/AsciiWide.hs view
@@ -0,0 +1,111 @@+-- | Text.Tabular.AsciiArt from tabular-0.2.2.7, modified to treat+-- wide characters as double width.++module Text.Tabular.AsciiWide where++import Data.List (intersperse, transpose)+import Text.Tabular+import Hledger.Utils.String++-- | for simplicity, we assume that each cell is rendered+-- on a single line+render :: Bool -- ^ pretty tables+ -> (rh -> String)+ -> (ch -> String)+ -> (a -> String)+ -> Table rh ch a+ -> String+render pretty fr fc f (Table rh ch cells) =+ unlines $ [ bar SingleLine -- +--------------------------------------++ , renderColumns pretty sizes ch2+ , bar DoubleLine -- +======================================++ ] +++ (renderRs $ fmap renderR $ zipHeader [] cells $ fmap fr rh) +++ [ bar SingleLine ] -- +--------------------------------------++ where+ bar = concat . renderHLine pretty sizes ch2+ -- ch2 and cell2 include the row and column labels+ ch2 = Group DoubleLine [Header "", fmap fc ch]+ cells2 = headerContents ch2+ : zipWith (\h cs -> h : map f cs) rhStrings cells+ --+ renderR (cs,h) = renderColumns pretty sizes $ Group DoubleLine+ [ Header h+ , fmap fst $ zipHeader "" (map f cs) ch]+ rhStrings = map fr $ headerContents rh+ -- maximum width for each column+ sizes = map (maximum . map strWidth) . transpose $ cells2+ renderRs (Header s) = [s]+ renderRs (Group p hs) = concat . intersperse sep . map renderRs $ hs+ where sep = renderHLine pretty sizes ch2 p++verticalBar :: Bool -> Char+verticalBar pretty = if pretty then '│' else '|'++leftBar :: Bool -> String+leftBar pretty = verticalBar pretty : " "++rightBar :: Bool -> String+rightBar pretty = " " ++ [verticalBar pretty]++midBar :: Bool -> String+midBar pretty = " " ++ verticalBar pretty : " "++doubleMidBar :: Bool -> String+doubleMidBar pretty = if pretty then " ║ " else " || "++horizontalBar :: Bool -> Char+horizontalBar pretty = if pretty then '─' else '-'++doubleHorizontalBar :: Bool -> Char+doubleHorizontalBar pretty = if pretty then '═' else '='++-- | We stop rendering on the shortest list!+renderColumns :: Bool -- ^ pretty+ -> [Int] -- ^ max width for each column+ -> Header String+ -> String+renderColumns pretty is h = leftBar pretty ++ coreLine ++ rightBar pretty+ where+ coreLine = concatMap helper $ flattenHeader $ zipHeader 0 is h+ helper = either hsep (uncurry padLeftWide)+ hsep :: Properties -> String+ hsep NoLine = " "+ hsep SingleLine = midBar pretty+ hsep DoubleLine = doubleMidBar pretty++renderHLine :: Bool -- ^ pretty+ -> [Int] -- ^ width specifications+ -> Header String+ -> Properties+ -> [String]+renderHLine _ _ _ NoLine = []+renderHLine pretty w h SingleLine = [renderHLine' pretty SingleLine w (horizontalBar pretty) h]+renderHLine pretty w h DoubleLine = [renderHLine' pretty DoubleLine w (doubleHorizontalBar pretty) h]++doubleCross :: Bool -> String+doubleCross pretty = if pretty then "╬" else "++"++doubleVerticalCross :: Bool -> String+doubleVerticalCross pretty = if pretty then "╫" else "++"++cross :: Bool -> Char+cross pretty = if pretty then '┼' else '+'++renderHLine' :: Bool -> Properties -> [Int] -> Char -> Header String -> String+renderHLine' pretty prop is sep h = [ cross pretty, sep ] ++ coreLine ++ [sep, cross pretty]+ where+ coreLine = concatMap helper $ flattenHeader $ zipHeader 0 is h+ helper = either vsep dashes+ dashes (i,_) = replicate i sep+ vsep NoLine = replicate 2 sep -- match the double space sep in renderColumns + vsep SingleLine = sep : cross pretty : [sep]+ vsep DoubleLine = sep : cross' ++ [sep]+ cross' = case prop of+ DoubleLine -> doubleCross pretty+ _ -> doubleVerticalCross pretty++-- padLeft :: Int -> String -> String+-- padLeft l s = padding ++ s+-- where padding = replicate (l - length s) ' '+
hledger-lib.cabal view
@@ -1,11 +1,11 @@--- This file has been generated from package.yaml by hpack version 0.20.0.+-- This file has been generated from package.yaml by hpack version 0.28.2. -- -- see: https://github.com/sol/hpack ----- hash: 151fb38a89818af88d66f068ef87e0af6f8497b1ef11ab825558b8147952c88d+-- hash: 1905b347a666e216347e595c5fcb0b340e5618a383a5493438200c6bcd5e6f98 name: hledger-lib-version: 1.9+version: 1.9.1 synopsis: Core data types, parsers and functionality for the hledger accounting tools description: This is a reusable library containing hledger's core functionality. .@@ -26,7 +26,6 @@ tested-with: GHC==7.10.3, GHC==8.0.2, GHC==8.2.1 build-type: Simple cabal-version: >= 1.10- extra-source-files: CHANGES hledger_csv.5@@ -48,44 +47,6 @@ location: https://github.com/simonmichael/hledger library- hs-source-dirs:- ./.- ghc-options: -Wall -fno-warn-unused-do-bind -fno-warn-name-shadowing -fno-warn-missing-signatures -fno-warn-type-defaults -fno-warn-orphans- build-depends:- Decimal- , HUnit- , ansi-terminal >=0.6.2.3- , array- , base >=4.8 && <4.12- , base-compat >=0.8.1- , blaze-markup >=0.5.1- , bytestring- , cmdargs >=0.10- , containers- , csv- , data-default >=0.5- , deepseq- , directory- , extra- , filepath- , hashtables >=1.2- , megaparsec >=5.0- , mtl- , mtl-compat- , old-time- , parsec >=3- , pretty-show >=1.6.4- , regex-tdfa- , safe >=0.2- , split >=0.1- , text >=1.2- , time >=1.5- , transformers >=0.2- , uglymemo- , utf8-string >=0.3.5- if (!impl(ghc >= 8.0))- build-depends:- semigroups ==0.18.* exposed-modules: Hledger Hledger.Data@@ -114,8 +75,10 @@ Hledger.Read.TimeclockReader Hledger.Reports Hledger.Reports.ReportOptions+ Hledger.Reports.ReportTypes Hledger.Reports.BalanceHistoryReport Hledger.Reports.BalanceReport+ Hledger.Reports.BudgetReport Hledger.Reports.EntriesReport Hledger.Reports.MultiBalanceReports Hledger.Reports.PostingsReport@@ -131,20 +94,14 @@ Hledger.Utils.Tree Hledger.Utils.UTF8IOCompat Text.Megaparsec.Compat+ Text.Tabular.AsciiWide other-modules: Paths_hledger_lib- default-language: Haskell2010--test-suite doctests- type: exitcode-stdio-1.0- main-is: doctests.hs hs-source-dirs: ./.- tests ghc-options: -Wall -fno-warn-unused-do-bind -fno-warn-name-shadowing -fno-warn-missing-signatures -fno-warn-type-defaults -fno-warn-orphans build-depends: Decimal- , Glob >=0.7 , HUnit , ansi-terminal >=0.6.2.3 , array@@ -158,7 +115,6 @@ , data-default >=0.5 , deepseq , directory- , doctest >=0.8 , extra , filepath , hashtables >=1.2@@ -171,6 +127,7 @@ , regex-tdfa , safe >=0.2 , split >=0.1+ , tabular >=0.2 , text >=1.2 , time >=1.5 , transformers >=0.2@@ -179,8 +136,11 @@ if (!impl(ghc >= 8.0)) build-depends: semigroups ==0.18.*- if impl(ghc >= 8.4) && os(darwin)- buildable: False+ default-language: Haskell2010++test-suite doctests+ type: exitcode-stdio-1.0+ main-is: doctests.hs other-modules: Hledger Hledger.Data@@ -210,10 +170,12 @@ Hledger.Reports Hledger.Reports.BalanceHistoryReport Hledger.Reports.BalanceReport+ Hledger.Reports.BudgetReport Hledger.Reports.EntriesReport Hledger.Reports.MultiBalanceReports Hledger.Reports.PostingsReport Hledger.Reports.ReportOptions+ Hledger.Reports.ReportTypes Hledger.Reports.TransactionsReports Hledger.Utils Hledger.Utils.Color@@ -226,18 +188,15 @@ Hledger.Utils.Tree Hledger.Utils.UTF8IOCompat Text.Megaparsec.Compat+ Text.Tabular.AsciiWide Paths_hledger_lib- default-language: Haskell2010--test-suite easytests- type: exitcode-stdio-1.0- main-is: easytests.hs hs-source-dirs: ./. tests ghc-options: -Wall -fno-warn-unused-do-bind -fno-warn-name-shadowing -fno-warn-missing-signatures -fno-warn-type-defaults -fno-warn-orphans build-depends: Decimal+ , Glob >=0.7 , HUnit , ansi-terminal >=0.6.2.3 , array@@ -251,11 +210,10 @@ , data-default >=0.5 , deepseq , directory- , easytest+ , doctest >=0.8 , extra , filepath , hashtables >=1.2- , hledger-lib , megaparsec >=5.0 , mtl , mtl-compat@@ -265,6 +223,7 @@ , regex-tdfa , safe >=0.2 , split >=0.1+ , tabular >=0.2 , text >=1.2 , time >=1.5 , transformers >=0.2@@ -273,6 +232,13 @@ if (!impl(ghc >= 8.0)) build-depends: semigroups ==0.18.*+ if impl(ghc >= 8.4) && os(darwin)+ buildable: False+ default-language: Haskell2010++test-suite easytests+ type: exitcode-stdio-1.0+ main-is: easytests.hs other-modules: Hledger Hledger.Data@@ -302,10 +268,12 @@ Hledger.Reports Hledger.Reports.BalanceHistoryReport Hledger.Reports.BalanceReport+ Hledger.Reports.BudgetReport Hledger.Reports.EntriesReport Hledger.Reports.MultiBalanceReports Hledger.Reports.PostingsReport Hledger.Reports.ReportOptions+ Hledger.Reports.ReportTypes Hledger.Reports.TransactionsReports Hledger.Utils Hledger.Utils.Color@@ -318,12 +286,8 @@ Hledger.Utils.Tree Hledger.Utils.UTF8IOCompat Text.Megaparsec.Compat+ Text.Tabular.AsciiWide Paths_hledger_lib- default-language: Haskell2010--test-suite hunittests- type: exitcode-stdio-1.0- main-is: hunittests.hs hs-source-dirs: ./. tests@@ -343,6 +307,7 @@ , data-default >=0.5 , deepseq , directory+ , easytest , extra , filepath , hashtables >=1.2@@ -356,8 +321,7 @@ , regex-tdfa , safe >=0.2 , split >=0.1- , test-framework- , test-framework-hunit+ , tabular >=0.2 , text >=1.2 , time >=1.5 , transformers >=0.2@@ -366,6 +330,11 @@ if (!impl(ghc >= 8.0)) build-depends: semigroups ==0.18.*+ default-language: Haskell2010++test-suite hunittests+ type: exitcode-stdio-1.0+ main-is: hunittests.hs other-modules: Hledger Hledger.Data@@ -395,10 +364,12 @@ Hledger.Reports Hledger.Reports.BalanceHistoryReport Hledger.Reports.BalanceReport+ Hledger.Reports.BudgetReport Hledger.Reports.EntriesReport Hledger.Reports.MultiBalanceReports Hledger.Reports.PostingsReport Hledger.Reports.ReportOptions+ Hledger.Reports.ReportTypes Hledger.Reports.TransactionsReports Hledger.Utils Hledger.Utils.Color@@ -411,5 +382,49 @@ Hledger.Utils.Tree Hledger.Utils.UTF8IOCompat Text.Megaparsec.Compat+ Text.Tabular.AsciiWide Paths_hledger_lib+ hs-source-dirs:+ ./.+ tests+ ghc-options: -Wall -fno-warn-unused-do-bind -fno-warn-name-shadowing -fno-warn-missing-signatures -fno-warn-type-defaults -fno-warn-orphans+ build-depends:+ Decimal+ , HUnit+ , ansi-terminal >=0.6.2.3+ , array+ , base >=4.8 && <4.12+ , base-compat >=0.8.1+ , blaze-markup >=0.5.1+ , bytestring+ , cmdargs >=0.10+ , containers+ , csv+ , data-default >=0.5+ , deepseq+ , directory+ , extra+ , filepath+ , hashtables >=1.2+ , hledger-lib+ , megaparsec >=5.0+ , mtl+ , mtl-compat+ , old-time+ , parsec >=3+ , pretty-show >=1.6.4+ , regex-tdfa+ , safe >=0.2+ , split >=0.1+ , tabular >=0.2+ , test-framework+ , test-framework-hunit+ , text >=1.2+ , time >=1.5+ , transformers >=0.2+ , uglymemo+ , utf8-string >=0.3.5+ if (!impl(ghc >= 8.0))+ build-depends:+ semigroups ==0.18.* default-language: Haskell2010
hledger_csv.5 view
@@ -1,5 +1,5 @@ -.TH "hledger_csv" "5" "March 2018" "hledger 1.9" "hledger User Manuals"+.TH "hledger_csv" "5" "April 2018" "hledger 1.9.1" "hledger User Manuals"
hledger_csv.info view
@@ -3,8 +3,8 @@ File: hledger_csv.info, Node: Top, Next: CSV RULES, Up: (dir) -hledger_csv(5) hledger 1.9-**************************+hledger_csv(5) hledger 1.9.1+**************************** hledger can read CSV (comma-separated value) files as if they were journal files, automatically converting each CSV record into a@@ -317,33 +317,33 @@ Tag Table: Node: Top72-Node: CSV RULES2161-Ref: #csv-rules2269-Node: skip2531-Ref: #skip2625-Node: date-format2797-Ref: #date-format2924-Node: field list3430-Ref: #field-list3567-Node: field assignment4272-Ref: #field-assignment4427-Node: conditional block4931-Ref: #conditional-block5085-Node: include5981-Ref: #include6111-Node: newest-first6342-Ref: #newest-first6456-Node: CSV TIPS6867-Ref: #csv-tips6961-Node: CSV ordering7079-Ref: #csv-ordering7197-Node: CSV accounts7378-Ref: #csv-accounts7516-Node: CSV amounts7770-Ref: #csv-amounts7916-Node: CSV balance assertions8691-Ref: #csv-balance-assertions8873-Node: Reading multiple CSV files9078-Ref: #reading-multiple-csv-files9248+Node: CSV RULES2165+Ref: #csv-rules2273+Node: skip2535+Ref: #skip2629+Node: date-format2801+Ref: #date-format2928+Node: field list3434+Ref: #field-list3571+Node: field assignment4276+Ref: #field-assignment4431+Node: conditional block4935+Ref: #conditional-block5089+Node: include5985+Ref: #include6115+Node: newest-first6346+Ref: #newest-first6460+Node: CSV TIPS6871+Ref: #csv-tips6965+Node: CSV ordering7083+Ref: #csv-ordering7201+Node: CSV accounts7382+Ref: #csv-accounts7520+Node: CSV amounts7774+Ref: #csv-amounts7920+Node: CSV balance assertions8695+Ref: #csv-balance-assertions8877+Node: Reading multiple CSV files9082+Ref: #reading-multiple-csv-files9252 End Tag Table
hledger_csv.txt view
@@ -249,4 +249,4 @@ -hledger 1.9 March 2018 hledger_csv(5)+hledger 1.9.1 April 2018 hledger_csv(5)
hledger_journal.5 view
@@ -1,6 +1,6 @@ .\"t -.TH "hledger_journal" "5" "March 2018" "hledger 1.9" "hledger User Manuals"+.TH "hledger_journal" "5" "April 2018" "hledger 1.9.1" "hledger User Manuals" @@ -758,11 +758,6 @@ (Star comments cause org\-mode nodes to be ignored, allowing emacs users to fold and navigate their journals with org\-mode or orgstruct\-mode.) .PP-Also, anything between \f[C]comment\f[] and \f[C]end\ comment\f[]-directives is a (multi\-line) comment.-If there is no \f[C]end\ comment\f[], the comment extends to the end of-the file.-.PP You can attach comments to a transaction by writing them after the description and/or indented on the following lines (before the postings).@@ -795,6 +790,9 @@ ;\ a\ file\ comment\ (because\ not\ indented) \f[] .fi+.PP+You can also comment larger regions of a file using \f[C]comment\f[] and+\f[C]end\ comment\f[] directives. .SS Tags .PP Tags are a way to add extra labels or labelled data to postings and@@ -855,8 +853,174 @@ Tags are like Ledger's metadata feature, except hledger's tag values are simple strings. .SS Directives-.SS Account aliases+.SS Comment blocks .PP+A line containing just \f[C]comment\f[] starts a commented region of the+file, and a line containing just \f[C]end\ comment\f[] (or the end of+the current file) ends it.+See also comments.+.SS Including other files+.PP+You can pull in the content of additional files by writing an include+directive, like this:+.IP+.nf+\f[C]+include\ path/to/file.journal+\f[]+.fi+.PP+If the path does not begin with a slash, it is relative to the current+file.+Glob patterns (\f[C]*\f[]) are not currently supported.+.PP+The \f[C]include\f[] directive can only be used in journal files.+It can include journal, timeclock or timedot files, but not CSV files.+.SS Default year+.PP+You can set a default year to be used for subsequent dates which don't+specify a year.+This is a line beginning with \f[C]Y\f[] followed by the year.+Eg:+.IP+.nf+\f[C]+Y2009\ \ \ \ \ \ ;\ set\ default\ year\ to\ 2009++12/15\ \ \ \ \ \ ;\ equivalent\ to\ 2009/12/15+\ \ expenses\ \ 1+\ \ assets++Y2010\ \ \ \ \ \ ;\ change\ default\ year\ to\ 2010++2009/1/30\ \ ;\ specifies\ the\ year,\ not\ affected+\ \ expenses\ \ 1+\ \ assets++1/31\ \ \ \ \ \ \ ;\ equivalent\ to\ 2010/1/31+\ \ expenses\ \ 1+\ \ assets+\f[]+.fi+.SS Declaring commodities+.PP+The \f[C]commodity\f[] directive declares commodities which may be used+in the journal (though currently we do not enforce this).+It may be written on a single line, like this:+.IP+.nf+\f[C]+;\ commodity\ EXAMPLEAMOUNT++;\ display\ AAAA\ amounts\ with\ the\ symbol\ on\ the\ right,\ space\-separated,+;\ using\ period\ as\ decimal\ point,\ with\ four\ decimal\ places,\ and+;\ separating\ thousands\ with\ comma.+commodity\ 1,000.0000\ AAAA+\f[]+.fi+.PP+or on multiple lines, using the \[lq]format\[rq] subdirective.+In this case the commodity symbol appears twice and should be the same+in both places:+.IP+.nf+\f[C]+;\ commodity\ SYMBOL+;\ \ \ format\ EXAMPLEAMOUNT++;\ display\ indian\ rupees\ with\ currency\ name\ on\ the\ left,+;\ thousands,\ lakhs\ and\ crores\ comma\-separated,+;\ period\ as\ decimal\ point,\ and\ two\ decimal\ places.+commodity\ INR+\ \ format\ INR\ 9,99,99,999.00+\f[]+.fi+.PP+Commodity directives have a second purpose: they define the standard+display format for amounts in the commodity.+Normally the display format is inferred from journal entries, but this+can be unpredictable; declaring it with a commodity directive overrides+this and removes ambiguity.+Towards this end, amounts in commodity directives must always be written+with a decimal point (a period or comma, followed by 0 or more decimal+digits).+.SS Default commodity+.PP+The D directive sets a default commodity (and display format), to be+used for amounts without a commodity symbol (ie, plain numbers).+(Note this differs from Ledger's default commodity directive.) The+commodity and display format will be applied to all subsequent+commodity\-less amounts, or until the next D directive.+.IP+.nf+\f[C]+#\ commodity\-less\ amounts\ should\ be\ treated\ as\ dollars+#\ (and\ displayed\ with\ symbol\ on\ the\ left,\ thousands\ separators\ and\ two\ decimal\ places)+D\ $1,000.00++1/1+\ \ a\ \ \ \ \ 5\ \ \ \ ;\ <\-\ commodity\-less\ amount,\ becomes\ $1+\ \ b+\f[]+.fi+.PP+As with the \f[C]commodity\f[] directive, the amount must always be+written with a decimal point.+.SS Declaring accounts+.PP+The \f[C]account\f[] directive predeclares account names.+The simplest form is \f[C]account\ ACCTNAME\f[], eg:+.IP+.nf+\f[C]+account\ assets:bank:checking+\f[]+.fi+.PP+Currently this mainly helps with account name autocompletion in eg+hledger add, hledger\-iadd, hledger\-web, and ledger\-mode.+.PD 0+.P+.PD+In future it will also help detect misspelled accounts.+.PP+Account names can be followed by a numeric account code:+.IP+.nf+\f[C]+account\ assets\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ 1000+account\ assets:bank:checking\ \ \ \ 1110+account\ liabilities\ \ \ \ \ \ \ \ \ \ \ \ \ 2000+account\ revenues\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ 4000+account\ expenses\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ 6000+\f[]+.fi+.PP+This affects account display order in reports: accounts with codes are+listed before accounts without codes, in increasing code order.+(Otherwise, accounts are listed alphabetically.) Account codes should be+all numeric digits, unique, and separated from the account name by at+least two spaces (since account names may contain single spaces).+By convention, often the first digit indicates the type of account, as+in this numbering scheme and the example above.+In future, we might use this to recognize account types.+.PP+An account directive can also have indented subdirectives following it,+which are currently ignored.+Here is the full syntax:+.IP+.nf+\f[C]+;\ account\ ACCTNAME\ \ [OPTIONALCODE]+;\ \ \ [OPTIONALSUBDIRECTIVES]++account\ assets:bank:checking\ \ \ 1110+\ \ a\ comment+\ \ some\-tag:12345+\f[]+.fi+.SS Rewriting accounts+.PP You can define aliases which rewrite your account names (after reading the journal, before generating reports). hledger's account aliases can be useful for:@@ -871,7 +1035,7 @@ .IP \[bu] 2 customising reports .PP-See also Cookbook: rewrite account names.+See also Cookbook: Rewrite account names. .SS Basic aliases .PP To set an account alias, use the \f[C]alias\f[] directive in your@@ -946,7 +1110,7 @@ precedence over earlier ones; directives not yet seen are ignored) .IP "2." 3 alias options, in the order they appear on the command line-.SS end aliases+.SS \f[C]end\ aliases\f[] .PP You can clear (forget) all currently defined aliases with the \f[C]end\ aliases\f[] directive:@@ -956,60 +1120,7 @@ end\ aliases \f[] .fi-.SS account directive-.PP-The \f[C]account\f[] directive predeclares account names.-The simplest form is \f[C]account\ ACCTNAME\f[], eg:-.IP-.nf-\f[C]-account\ assets:bank:checking-\f[]-.fi-.PP-Currently this mainly helps with account name autocompletion in eg-hledger add, hledger\-iadd, hledger\-web, and ledger\-mode.-.PD 0-.P-.PD-In future it will also help detect misspelled accounts.-.PP-Account names can be followed by a numeric account code:-.IP-.nf-\f[C]-account\ assets\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ 1000-account\ assets:bank:checking\ \ \ \ 1110-account\ liabilities\ \ \ \ \ \ \ \ \ \ \ \ \ 2000-account\ revenues\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ 4000-account\ expenses\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ 6000-\f[]-.fi-.PP-This affects account display order in reports: accounts with codes are-listed before accounts without codes, in increasing code order.-(Otherwise, accounts are listed alphabetically.) Account codes should be-all numeric digits, unique, and separated from the account name by at-least two spaces (since account names may contain single spaces).-By convention, often the first digit indicates the type of account, as-in this numbering scheme and the example above.-In future, we might use this to recognize account types.-.PP-An account directive can also have indented subdirectives following it,-which are currently ignored.-Here is the full syntax:-.IP-.nf-\f[C]-;\ account\ ACCTNAME\ \ [OPTIONALCODE]-;\ \ \ [OPTIONALSUBDIRECTIVES]--account\ assets:bank:checking\ \ \ 1110-\ \ a\ comment-\ \ some\-tag:12345-\f[]-.fi-.SS apply account directive+.SS Default parent account .PP You can specify a parent account which will be prepended to all accounts within a section of the journal.@@ -1054,116 +1165,13 @@ .PP Prior to hledger 1.0, legacy \f[C]account\f[] and \f[C]end\f[] spellings were also supported.-.SS Multi\-line comments-.PP-A line containing just \f[C]comment\f[] starts a multi\-line comment,-and a line containing just \f[C]end\ comment\f[] ends it.-See comments.-.SS commodity directive-.PP-The \f[C]commodity\f[] directive predefines commodities (currently this-is just informational), and also it may define the display format for-amounts in this commodity (overriding the automatically inferred-format).-.PP-It may be written on a single line, like this:-.IP-.nf-\f[C]-;\ commodity\ EXAMPLEAMOUNT--;\ display\ AAAA\ amounts\ with\ the\ symbol\ on\ the\ right,\ space\-separated,-;\ using\ period\ as\ decimal\ point,\ with\ four\ decimal\ places,\ and-;\ separating\ thousands\ with\ comma.-commodity\ 1,000.0000\ AAAA-\f[]-.fi-.PP-or on multiple lines, using the \[lq]format\[rq] subdirective.-In this case the commodity symbol appears twice and should be the same-in both places:-.IP-.nf-\f[C]-;\ commodity\ SYMBOL-;\ \ \ format\ EXAMPLEAMOUNT--;\ display\ indian\ rupees\ with\ currency\ name\ on\ the\ left,-;\ thousands,\ lakhs\ and\ crores\ comma\-separated,-;\ period\ as\ decimal\ point,\ and\ two\ decimal\ places.-commodity\ INR-\ \ format\ INR\ 9,99,99,999.00-\f[]-.fi-.SS Default commodity-.PP-The D directive sets a default commodity (and display format), to be-used for amounts without a commodity symbol (ie, plain numbers).-(Note this differs from Ledger's default commodity directive.) The-commodity and display format will be applied to all subsequent-commodity\-less amounts, or until the next D directive.-.IP-.nf-\f[C]-#\ commodity\-less\ amounts\ should\ be\ treated\ as\ dollars-#\ (and\ displayed\ with\ symbol\ on\ the\ left,\ thousands\ separators\ and\ two\ decimal\ places)-D\ $1,000.00--1/1-\ \ a\ \ \ \ \ 5\ \ \ \ ;\ <\-\ commodity\-less\ amount,\ becomes\ $1-\ \ b-\f[]-.fi-.SS Default year-.PP-You can set a default year to be used for subsequent dates which don't-specify a year.-This is a line beginning with \f[C]Y\f[] followed by the year.-Eg:-.IP-.nf-\f[C]-Y2009\ \ \ \ \ \ ;\ set\ default\ year\ to\ 2009--12/15\ \ \ \ \ \ ;\ equivalent\ to\ 2009/12/15-\ \ expenses\ \ 1-\ \ assets--Y2010\ \ \ \ \ \ ;\ change\ default\ year\ to\ 2010--2009/1/30\ \ ;\ specifies\ the\ year,\ not\ affected-\ \ expenses\ \ 1-\ \ assets--1/31\ \ \ \ \ \ \ ;\ equivalent\ to\ 2010/1/31-\ \ expenses\ \ 1-\ \ assets-\f[]-.fi-.SS Including other files-.PP-You can pull in the content of additional journal files by writing an-include directive, like this:-.IP-.nf-\f[C]-include\ path/to/file.journal-\f[]-.fi-.PP-If the path does not begin with a slash, it is relative to the current-file.-Glob patterns (\f[C]*\f[]) are not currently supported.-.PP-The \f[C]include\f[] directive can only be used in journal files.-It can include journal, timeclock or timedot files, but not CSV files.-.SH Periodic transactions+.SS Periodic transactions .PP-Periodic transactions are a kind of rule with a dual purpose: they can-specify recurring future transactions (with \f[C]\-\-forecast\f[]), or-budget goals (with \f[C]\-\-budget\f[]).-They look a bit like a transaction, except the first line is a tilde-(\f[C]~\f[]) followed by a period expression:+Periodic transaction rules (enabled by \f[C]\-\-forecast\f[] or+\f[C]\-\-budget\f[]) describe recurring transactions.+They look like a transaction where the first line is a tilde+(\f[C]~\f[]) followed by a period expression (mnemonic: \f[C]~\f[] is+like a recurring sine wave): .IP .nf \f[C]@@ -1173,25 +1181,34 @@ \f[] .fi .PP+Periodic transactions have a dual purpose:+.IP \[bu] 2 With \f[C]\-\-forecast\f[], each periodic transaction rule generates-recurring \[lq]forecast\[rq] transactions at the specified interval,-beginning the day after the latest recorded journal transaction (or-today, if there are no transactions) and ending 6 months from today (or-at the report end date, if specified).-.PP-With \f[C]balance\ \-\-budget\f[], each periodic transaction declares-recurring budget goals for the specified accounts.+future transactions, recurring at the specified interval, which can be+seen in reports.+Forecast transactions begin the day after the latest recorded journal+transaction (or today, if there are no transactions) and end 6 months+from today (or at the report end date, if specified).+.IP \[bu] 2+With \f[C]\-\-budget\f[] (supported by the balance command), each+periodic transaction rule declares recurring budget goals for the+specified accounts, which can be seen in budget reports. Eg the example above declares the goal of receiving $400 from \f[C]income:acme\ inc\f[] (and also, depositing $400 into \f[C]assets:bank:checking\f[]) every week. .PP-For more details, see: balance: Budgeting and Budgeting and Forecasting.-.SH Automated postings+(Actually, you can generate one\-off transactions too, by writing a+period expression with no report interval.) .PP-Automated postings are postings added automatically by rule to certain-transactions (with \f[C]\-\-auto\f[]).+For more details, see: balance: Budget report and Cookbook: Budgeting+and Forecasting.+.SS Automated postings+.PP+Automated postings (enabled by \f[C]\-\-auto\f[]) are postings added+automatically by rule to certain transactions. An automated posting rule looks like a transaction where the first line-is an equal sign (\f[C]=\f[]) followed by a query:+is an equal sign (\f[C]=\f[]) followed by a query (mnemonic: \f[C]=\f[]+tests for matching transactions, and also looks like posting lines): .IP .nf \f[C]@@ -1226,10 +1243,13 @@ $\ hledger\ print\ \-\-auto 2017/12/14 \ \ \ \ expenses:gifts\ \ \ \ \ \ \ \ \ \ \ \ \ $20-\ \ \ \ assets \ \ \ \ (budget:gifts)\ \ \ \ \ \ \ \ \ \ \ \ $\-20+\ \ \ \ assets \f[] .fi+.PP+Like postings recorded by hand, automated postings participate in+transaction balancing, missing amount inference and balance assertions. .SH EDITOR SUPPORT .PP Add\-on modes exist for various text editors, to make working with
hledger_journal.info view
@@ -4,8 +4,8 @@ File: hledger_journal.info, Node: Top, Next: FILE FORMAT, Up: (dir) -hledger_journal(5) hledger 1.9-******************************+hledger_journal(5) hledger 1.9.1+******************************** hledger's usual data source is a plain text file containing journal entries in hledger journal format. This file represents a standard@@ -57,12 +57,10 @@ * Menu: * FILE FORMAT::-* Periodic transactions::-* Automated postings:: * EDITOR SUPPORT:: -File: hledger_journal.info, Node: FILE FORMAT, Next: Periodic transactions, Prev: Top, Up: Top+File: hledger_journal.info, Node: FILE FORMAT, Next: EDITOR SUPPORT, Prev: Top, Up: Top 1 FILE FORMAT *************@@ -83,6 +81,8 @@ * Comments:: * Tags:: * Directives::+* Periodic transactions::+* Automated postings:: File: hledger_journal.info, Node: Transactions, Next: Postings, Up: FILE FORMAT@@ -713,10 +713,6 @@ org-mode nodes to be ignored, allowing emacs users to fold and navigate their journals with org-mode or orgstruct-mode.) - Also, anything between 'comment' and 'end comment' directives is a-(multi-line) comment. If there is no 'end comment', the comment extends-to the end of the file.- You can attach comments to a transaction by writing them after the description and/or indented on the following lines (before the postings). Similarly, you can attach comments to an individual posting@@ -744,6 +740,9 @@ ; another comment line for posting 2 ; a file comment (because not indented) + You can also comment larger regions of a file using 'comment' and+'end comment' directives.+ File: hledger_journal.info, Node: Tags, Next: Directives, Prev: Comments, Up: FILE FORMAT @@ -788,28 +787,184 @@ are simple strings. -File: hledger_journal.info, Node: Directives, Prev: Tags, Up: FILE FORMAT+File: hledger_journal.info, Node: Directives, Next: Periodic transactions, Prev: Tags, Up: FILE FORMAT 1.14 Directives =============== * Menu: -* Account aliases::-* account directive::-* apply account directive::-* Multi-line comments::-* commodity directive::-* Default commodity::-* Default year::+* Comment blocks:: * Including other files::+* Default year::+* Declaring commodities::+* Default commodity::+* Declaring accounts::+* Rewriting accounts::+* Default parent account:: -File: hledger_journal.info, Node: Account aliases, Next: account directive, Up: Directives+File: hledger_journal.info, Node: Comment blocks, Next: Including other files, Up: Directives -1.14.1 Account aliases-----------------------+1.14.1 Comment blocks+--------------------- +A line containing just 'comment' starts a commented region of the file,+and a line containing just 'end comment' (or the end of the current+file) ends it. See also comments.+++File: hledger_journal.info, Node: Including other files, Next: Default year, Prev: Comment blocks, Up: Directives++1.14.2 Including other files+----------------------------++You can pull in the content of additional files by writing an include+directive, like this:++include path/to/file.journal++ If the path does not begin with a slash, it is relative to the+current file. Glob patterns ('*') are not currently supported.++ The 'include' directive can only be used in journal files. It can+include journal, timeclock or timedot files, but not CSV files.+++File: hledger_journal.info, Node: Default year, Next: Declaring commodities, Prev: Including other files, Up: Directives++1.14.3 Default year+-------------------++You can set a default year to be used for subsequent dates which don't+specify a year. This is a line beginning with 'Y' followed by the year.+Eg:++Y2009 ; set default year to 2009++12/15 ; equivalent to 2009/12/15+ expenses 1+ assets++Y2010 ; change default year to 2010++2009/1/30 ; specifies the year, not affected+ expenses 1+ assets++1/31 ; equivalent to 2010/1/31+ expenses 1+ assets+++File: hledger_journal.info, Node: Declaring commodities, Next: Default commodity, Prev: Default year, Up: Directives++1.14.4 Declaring commodities+----------------------------++The 'commodity' directive declares commodities which may be used in the+journal (though currently we do not enforce this). It may be written on+a single line, like this:++; commodity EXAMPLEAMOUNT++; display AAAA amounts with the symbol on the right, space-separated,+; using period as decimal point, with four decimal places, and+; separating thousands with comma.+commodity 1,000.0000 AAAA++ or on multiple lines, using the "format" subdirective. In this case+the commodity symbol appears twice and should be the same in both+places:++; commodity SYMBOL+; format EXAMPLEAMOUNT++; display indian rupees with currency name on the left,+; thousands, lakhs and crores comma-separated,+; period as decimal point, and two decimal places.+commodity INR+ format INR 9,99,99,999.00++ Commodity directives have a second purpose: they define the standard+display format for amounts in the commodity. Normally the display+format is inferred from journal entries, but this can be unpredictable;+declaring it with a commodity directive overrides this and removes+ambiguity. Towards this end, amounts in commodity directives must+always be written with a decimal point (a period or comma, followed by 0+or more decimal digits).+++File: hledger_journal.info, Node: Default commodity, Next: Declaring accounts, Prev: Declaring commodities, Up: Directives++1.14.5 Default commodity+------------------------++The D directive sets a default commodity (and display format), to be+used for amounts without a commodity symbol (ie, plain numbers). (Note+this differs from Ledger's default commodity directive.) The commodity+and display format will be applied to all subsequent commodity-less+amounts, or until the next D directive.++# commodity-less amounts should be treated as dollars+# (and displayed with symbol on the left, thousands separators and two decimal places)+D $1,000.00++1/1+ a 5 ; <- commodity-less amount, becomes $1+ b++ As with the 'commodity' directive, the amount must always be written+with a decimal point.+++File: hledger_journal.info, Node: Declaring accounts, Next: Rewriting accounts, Prev: Default commodity, Up: Directives++1.14.6 Declaring accounts+-------------------------++The 'account' directive predeclares account names. The simplest form is+'account ACCTNAME', eg:++account assets:bank:checking++ Currently this mainly helps with account name autocompletion in eg+hledger add, hledger-iadd, hledger-web, and ledger-mode.+In future it will also help detect misspelled accounts.++ Account names can be followed by a numeric account code:++account assets 1000+account assets:bank:checking 1110+account liabilities 2000+account revenues 4000+account expenses 6000++ This affects account display order in reports: accounts with codes+are listed before accounts without codes, in increasing code order.+(Otherwise, accounts are listed alphabetically.) Account codes should+be all numeric digits, unique, and separated from the account name by at+least two spaces (since account names may contain single spaces). By+convention, often the first digit indicates the type of account, as in+this numbering scheme and the example above. In future, we might use+this to recognize account types.++ An account directive can also have indented subdirectives following+it, which are currently ignored. Here is the full syntax:++; account ACCTNAME [OPTIONALCODE]+; [OPTIONALSUBDIRECTIVES]++account assets:bank:checking 1110+ a comment+ some-tag:12345+++File: hledger_journal.info, Node: Rewriting accounts, Next: Default parent account, Prev: Declaring accounts, Up: Directives++1.14.7 Rewriting accounts+-------------------------+ You can define aliases which rewrite your account names (after reading the journal, before generating reports). hledger's account aliases can be useful for:@@ -821,7 +976,7 @@ or combining two accounts into one * customising reports - See also Cookbook: rewrite account names.+ See also Cookbook: Rewrite account names. * Menu: * Basic aliases::@@ -830,9 +985,9 @@ * end aliases:: -File: hledger_journal.info, Node: Basic aliases, Next: Regex aliases, Up: Account aliases+File: hledger_journal.info, Node: Basic aliases, Next: Regex aliases, Up: Rewriting accounts -1.14.1.1 Basic aliases+1.14.7.1 Basic aliases ...................... To set an account alias, use the 'alias' directive in your journal file.@@ -853,9 +1008,9 @@ # rewrites "checking" to "assets:bank:wells fargo:checking", or "checking:a" to "assets:bank:wells fargo:checking:a" -File: hledger_journal.info, Node: Regex aliases, Next: Multiple aliases, Prev: Basic aliases, Up: Account aliases+File: hledger_journal.info, Node: Regex aliases, Next: Multiple aliases, Prev: Basic aliases, Up: Rewriting accounts -1.14.1.2 Regex aliases+1.14.7.2 Regex aliases ...................... There is also a more powerful variant that uses a regular expression,@@ -878,9 +1033,9 @@ whitespace. -File: hledger_journal.info, Node: Multiple aliases, Next: end aliases, Prev: Regex aliases, Up: Account aliases+File: hledger_journal.info, Node: Multiple aliases, Next: end aliases, Prev: Regex aliases, Up: Rewriting accounts -1.14.1.3 Multiple aliases+1.14.7.3 Multiple aliases ......................... You can define as many aliases as you like using directives or@@ -894,10 +1049,10 @@ 2. alias options, in the order they appear on the command line -File: hledger_journal.info, Node: end aliases, Prev: Multiple aliases, Up: Account aliases+File: hledger_journal.info, Node: end aliases, Prev: Multiple aliases, Up: Rewriting accounts -1.14.1.4 end aliases-....................+1.14.7.4 'end aliases'+...................... You can clear (forget) all currently defined aliases with the 'end aliases' directive:@@ -905,52 +1060,10 @@ end aliases -File: hledger_journal.info, Node: account directive, Next: apply account directive, Prev: Account aliases, Up: Directives--1.14.2 account directive---------------------------The 'account' directive predeclares account names. The simplest form is-'account ACCTNAME', eg:--account assets:bank:checking-- Currently this mainly helps with account name autocompletion in eg-hledger add, hledger-iadd, hledger-web, and ledger-mode.-In future it will also help detect misspelled accounts.-- Account names can be followed by a numeric account code:--account assets 1000-account assets:bank:checking 1110-account liabilities 2000-account revenues 4000-account expenses 6000-- This affects account display order in reports: accounts with codes-are listed before accounts without codes, in increasing code order.-(Otherwise, accounts are listed alphabetically.) Account codes should-be all numeric digits, unique, and separated from the account name by at-least two spaces (since account names may contain single spaces). By-convention, often the first digit indicates the type of account, as in-this numbering scheme and the example above. In future, we might use-this to recognize account types.-- An account directive can also have indented subdirectives following-it, which are currently ignored. Here is the full syntax:--; account ACCTNAME [OPTIONALCODE]-; [OPTIONALSUBDIRECTIVES]--account assets:bank:checking 1110- a comment- some-tag:12345---File: hledger_journal.info, Node: apply account directive, Next: Multi-line comments, Prev: account directive, Up: Directives+File: hledger_journal.info, Node: Default parent account, Prev: Rewriting accounts, Up: Directives -1.14.3 apply account directive-------------------------------+1.14.8 Default parent account+----------------------------- You can specify a parent account which will be prepended to all accounts within a section of the journal. Use the 'apply account' and 'end apply@@ -983,148 +1096,52 @@ supported. -File: hledger_journal.info, Node: Multi-line comments, Next: commodity directive, Prev: apply account directive, Up: Directives--1.14.4 Multi-line comments-----------------------------A line containing just 'comment' starts a multi-line comment, and a line-containing just 'end comment' ends it. See comments.---File: hledger_journal.info, Node: commodity directive, Next: Default commodity, Prev: Multi-line comments, Up: Directives--1.14.5 commodity directive-----------------------------The 'commodity' directive predefines commodities (currently this is just-informational), and also it may define the display format for amounts in-this commodity (overriding the automatically inferred format).-- It may be written on a single line, like this:--; commodity EXAMPLEAMOUNT--; display AAAA amounts with the symbol on the right, space-separated,-; using period as decimal point, with four decimal places, and-; separating thousands with comma.-commodity 1,000.0000 AAAA-- or on multiple lines, using the "format" subdirective. In this case-the commodity symbol appears twice and should be the same in both-places:--; commodity SYMBOL-; format EXAMPLEAMOUNT--; display indian rupees with currency name on the left,-; thousands, lakhs and crores comma-separated,-; period as decimal point, and two decimal places.-commodity INR- format INR 9,99,99,999.00---File: hledger_journal.info, Node: Default commodity, Next: Default year, Prev: commodity directive, Up: Directives--1.14.6 Default commodity---------------------------The D directive sets a default commodity (and display format), to be-used for amounts without a commodity symbol (ie, plain numbers). (Note-this differs from Ledger's default commodity directive.) The commodity-and display format will be applied to all subsequent commodity-less-amounts, or until the next D directive.--# commodity-less amounts should be treated as dollars-# (and displayed with symbol on the left, thousands separators and two decimal places)-D $1,000.00--1/1- a 5 ; <- commodity-less amount, becomes $1- b---File: hledger_journal.info, Node: Default year, Next: Including other files, Prev: Default commodity, Up: Directives--1.14.7 Default year----------------------You can set a default year to be used for subsequent dates which don't-specify a year. This is a line beginning with 'Y' followed by the year.-Eg:--Y2009 ; set default year to 2009--12/15 ; equivalent to 2009/12/15- expenses 1- assets--Y2010 ; change default year to 2010--2009/1/30 ; specifies the year, not affected- expenses 1- assets--1/31 ; equivalent to 2010/1/31- expenses 1- assets---File: hledger_journal.info, Node: Including other files, Prev: Default year, Up: Directives--1.14.8 Including other files-------------------------------You can pull in the content of additional journal files by writing an-include directive, like this:--include path/to/file.journal-- If the path does not begin with a slash, it is relative to the-current file. Glob patterns ('*') are not currently supported.-- The 'include' directive can only be used in journal files. It can-include journal, timeclock or timedot files, but not CSV files.---File: hledger_journal.info, Node: Periodic transactions, Next: Automated postings, Prev: FILE FORMAT, Up: Top+File: hledger_journal.info, Node: Periodic transactions, Next: Automated postings, Prev: Directives, Up: FILE FORMAT -2 Periodic transactions-***********************+1.15 Periodic transactions+========================== -Periodic transactions are a kind of rule with a dual purpose: they can-specify recurring future transactions (with '--forecast'), or budget-goals (with '--budget'). They look a bit like a transaction, except the-first line is a tilde ('~') followed by a period expression:+Periodic transaction rules (enabled by '--forecast' or '--budget')+describe recurring transactions. They look like a transaction where the+first line is a tilde ('~') followed by a period expression (mnemonic:+'~' is like a recurring sine wave): ~ weekly assets:bank:checking $400 ; paycheck income:acme inc - With '--forecast', each periodic transaction rule generates recurring-"forecast" transactions at the specified interval, beginning the day-after the latest recorded journal transaction (or today, if there are no-transactions) and ending 6 months from today (or at the report end date,-if specified).+ Periodic transactions have a dual purpose: - With 'balance --budget', each periodic transaction declares recurring-budget goals for the specified accounts. Eg the example above declares-the goal of receiving $400 from 'income:acme inc' (and also, depositing-$400 into 'assets:bank:checking') every week.+ * With '--forecast', each periodic transaction rule generates future+ transactions, recurring at the specified interval, which can be+ seen in reports. Forecast transactions begin the day after the+ latest recorded journal transaction (or today, if there are no+ transactions) and end 6 months from today (or at the report end+ date, if specified). - For more details, see: balance: Budgeting and Budgeting and-Forecasting.+ * With '--budget' (supported by the balance command), each periodic+ transaction rule declares recurring budget goals for the specified+ accounts, which can be seen in budget reports. Eg the example+ above declares the goal of receiving $400 from 'income:acme inc'+ (and also, depositing $400 into 'assets:bank:checking') every week. + (Actually, you can generate one-off transactions too, by writing a+period expression with no report interval.)++ For more details, see: balance: Budget report and Cookbook: Budgeting+and Forecasting.+ -File: hledger_journal.info, Node: Automated postings, Next: EDITOR SUPPORT, Prev: Periodic transactions, Up: Top+File: hledger_journal.info, Node: Automated postings, Prev: Periodic transactions, Up: FILE FORMAT -3 Automated postings-********************+1.16 Automated postings+======================= -Automated postings are postings added automatically by rule to certain-transactions (with '--auto'). An automated posting rule looks like a-transaction where the first line is an equal sign ('=') followed by a-query:+Automated postings (enabled by '--auto') are postings added+automatically by rule to certain transactions. An automated posting+rule looks like a transaction where the first line is an equal sign+('=') followed by a query (mnemonic: '=' tests for matching+transactions, and also looks like posting lines): = expenses:gifts budget:gifts *-1@@ -1149,13 +1166,16 @@ $ hledger print --auto 2017/12/14 expenses:gifts $20- assets (budget:gifts) $-20+ assets + Like postings recorded by hand, automated postings participate in+transaction balancing, missing amount inference and balance assertions.+ -File: hledger_journal.info, Node: EDITOR SUPPORT, Prev: Automated postings, Up: Top+File: hledger_journal.info, Node: EDITOR SUPPORT, Prev: FILE FORMAT, Up: Top -4 EDITOR SUPPORT+2 EDITOR SUPPORT **************** Add-on modes exist for various text editors, to make working with@@ -1182,89 +1202,89 @@ Tag Table: Node: Top76-Node: FILE FORMAT2419-Ref: #file-format2550-Node: Transactions2773-Ref: #transactions2894-Node: Postings3578-Ref: #postings3705-Node: Dates4700-Ref: #dates4815-Node: Simple dates4880-Ref: #simple-dates5006-Node: Secondary dates5372-Ref: #secondary-dates5526-Node: Posting dates7089-Ref: #posting-dates7218-Node: Status8592-Ref: #status8712-Node: Description10420-Ref: #description10558-Node: Payee and note10877-Ref: #payee-and-note10991-Node: Account names11233-Ref: #account-names11376-Node: Amounts11863-Ref: #amounts11999-Node: Virtual Postings15014-Ref: #virtual-postings15173-Node: Balance Assertions16393-Ref: #balance-assertions16568-Node: Assertions and ordering17464-Ref: #assertions-and-ordering17650-Node: Assertions and included files18350-Ref: #assertions-and-included-files18591-Node: Assertions and multiple -f options18924-Ref: #assertions-and-multiple--f-options19178-Node: Assertions and commodities19310-Ref: #assertions-and-commodities19545-Node: Assertions and subaccounts20241-Ref: #assertions-and-subaccounts20473-Node: Assertions and virtual postings20994-Ref: #assertions-and-virtual-postings21201-Node: Balance Assignments21343-Ref: #balance-assignments21512-Node: Prices22632-Ref: #prices22765-Node: Transaction prices22816-Ref: #transaction-prices22961-Node: Market prices25117-Ref: #market-prices25252-Node: Comments26212-Ref: #comments26334-Node: Tags27576-Ref: #tags27694-Node: Directives29096-Ref: #directives29209-Node: Account aliases29402-Ref: #account-aliases29546-Node: Basic aliases30150-Ref: #basic-aliases30293-Node: Regex aliases30983-Ref: #regex-aliases31151-Node: Multiple aliases31869-Ref: #multiple-aliases32041-Node: end aliases32539-Ref: #end-aliases32679-Node: account directive32780-Ref: #account-directive32960-Node: apply account directive34307-Ref: #apply-account-directive34503-Node: Multi-line comments35162-Ref: #multi-line-comments35352-Node: commodity directive35480-Ref: #commodity-directive35664-Node: Default commodity36536-Ref: #default-commodity36709-Node: Default year37246-Ref: #default-year37411-Node: Including other files37834-Ref: #including-other-files37991-Node: Periodic transactions38388-Ref: #periodic-transactions38554-Node: Automated postings39543-Ref: #automated-postings39706-Node: EDITOR SUPPORT40608-Ref: #editor-support40733+Node: FILE FORMAT2374+Ref: #file-format2498+Node: Transactions2770+Ref: #transactions2891+Node: Postings3575+Ref: #postings3702+Node: Dates4697+Ref: #dates4812+Node: Simple dates4877+Ref: #simple-dates5003+Node: Secondary dates5369+Ref: #secondary-dates5523+Node: Posting dates7086+Ref: #posting-dates7215+Node: Status8589+Ref: #status8709+Node: Description10417+Ref: #description10555+Node: Payee and note10874+Ref: #payee-and-note10988+Node: Account names11230+Ref: #account-names11373+Node: Amounts11860+Ref: #amounts11996+Node: Virtual Postings15011+Ref: #virtual-postings15170+Node: Balance Assertions16390+Ref: #balance-assertions16565+Node: Assertions and ordering17461+Ref: #assertions-and-ordering17647+Node: Assertions and included files18347+Ref: #assertions-and-included-files18588+Node: Assertions and multiple -f options18921+Ref: #assertions-and-multiple--f-options19175+Node: Assertions and commodities19307+Ref: #assertions-and-commodities19542+Node: Assertions and subaccounts20238+Ref: #assertions-and-subaccounts20470+Node: Assertions and virtual postings20991+Ref: #assertions-and-virtual-postings21198+Node: Balance Assignments21340+Ref: #balance-assignments21509+Node: Prices22629+Ref: #prices22762+Node: Transaction prices22813+Ref: #transaction-prices22958+Node: Market prices25114+Ref: #market-prices25249+Node: Comments26209+Ref: #comments26331+Node: Tags27501+Ref: #tags27619+Node: Directives29021+Ref: #directives29164+Node: Comment blocks29357+Ref: #comment-blocks29502+Node: Including other files29678+Ref: #including-other-files29858+Node: Default year30247+Ref: #default-year30416+Node: Declaring commodities30839+Ref: #declaring-commodities31022+Node: Default commodity32249+Ref: #default-commodity32430+Node: Declaring accounts33062+Ref: #declaring-accounts33242+Node: Rewriting accounts34589+Ref: #rewriting-accounts34774+Node: Basic aliases35378+Ref: #basic-aliases35524+Node: Regex aliases36214+Ref: #regex-aliases36385+Node: Multiple aliases37103+Ref: #multiple-aliases37278+Node: end aliases37776+Ref: #end-aliases37923+Node: Default parent account38024+Ref: #default-parent-account38190+Node: Periodic transactions38849+Ref: #periodic-transactions39028+Node: Automated postings40327+Ref: #automated-postings40481+Node: EDITOR SUPPORT41614+Ref: #editor-support41732 End Tag Table
hledger_journal.txt view
@@ -553,10 +553,6 @@ nodes to be ignored, allowing emacs users to fold and navigate their journals with org-mode or orgstruct-mode.) - Also, anything between comment and end comment directives is a- (multi-line) comment. If there is no end comment, the comment extends- to the end of the file.- You can attach comments to a transaction by writing them after the description and/or indented on the following lines (before the post- ings). Similarly, you can attach comments to an individual posting by@@ -584,21 +580,24 @@ ; another comment line for posting 2 ; a file comment (because not indented) + You can also comment larger regions of a file using comment and+ end comment directives.+ Tags- Tags are a way to add extra labels or labelled data to postings and+ Tags are a way to add extra labels or labelled data to postings and transactions, which you can then search or pivot on. - A simple tag is a word (which may contain hyphens) followed by a full+ A simple tag is a word (which may contain hyphens) followed by a full colon, written inside a transaction or posting comment line: 2017/1/16 bought groceries ; sometag: - Tags can have a value, which is the text after the colon, up to the+ Tags can have a value, which is the text after the colon, up to the next comma or end of line, with leading/trailing whitespace removed: expenses:food $10 ; a-posting-tag: the tag value - Note this means hledger's tag values can not contain commas or new-+ Note this means hledger's tag values can not contain commas or new- lines. Ending at commas means you can write multiple short tags on one line, comma separated: @@ -612,21 +611,147 @@ o "tag2" is another tag, whose value is "some value ..." - Tags in a transaction comment affect the transaction and all of its- postings, while tags in a posting comment affect only that posting.- For example, the following transaction has three tags (A, TAG2,+ Tags in a transaction comment affect the transaction and all of its+ postings, while tags in a posting comment affect only that posting.+ For example, the following transaction has three tags (A, TAG2, third-tag) and the posting has four (those plus posting-tag): 1/1 a transaction ; A:, TAG2: ; third-tag: a third transaction tag, <- with a value (a) $1 ; posting-tag: - Tags are like Ledger's metadata feature, except hledger's tag values+ Tags are like Ledger's metadata feature, except hledger's tag values are simple strings. Directives- Account aliases- You can define aliases which rewrite your account names (after reading+ Comment blocks+ A line containing just comment starts a commented region of the file,+ and a line containing just end comment (or the end of the current file)+ ends it. See also comments.++ Including other files+ You can pull in the content of additional files by writing an include+ directive, like this:++ include path/to/file.journal++ If the path does not begin with a slash, it is relative to the current+ file. Glob patterns (*) are not currently supported.++ The include directive can only be used in journal files. It can+ include journal, timeclock or timedot files, but not CSV files.++ Default year+ You can set a default year to be used for subsequent dates which don't+ specify a year. This is a line beginning with Y followed by the year.+ Eg:++ Y2009 ; set default year to 2009++ 12/15 ; equivalent to 2009/12/15+ expenses 1+ assets++ Y2010 ; change default year to 2010++ 2009/1/30 ; specifies the year, not affected+ expenses 1+ assets++ 1/31 ; equivalent to 2010/1/31+ expenses 1+ assets++ Declaring commodities+ The commodity directive declares commodities which may be used in the+ journal (though currently we do not enforce this). It may be written+ on a single line, like this:++ ; commodity EXAMPLEAMOUNT++ ; display AAAA amounts with the symbol on the right, space-separated,+ ; using period as decimal point, with four decimal places, and+ ; separating thousands with comma.+ commodity 1,000.0000 AAAA++ or on multiple lines, using the "format" subdirective. In this case+ the commodity symbol appears twice and should be the same in both+ places:++ ; commodity SYMBOL+ ; format EXAMPLEAMOUNT++ ; display indian rupees with currency name on the left,+ ; thousands, lakhs and crores comma-separated,+ ; period as decimal point, and two decimal places.+ commodity INR+ format INR 9,99,99,999.00++ Commodity directives have a second purpose: they define the standard+ display format for amounts in the commodity. Normally the display for-+ mat is inferred from journal entries, but this can be unpredictable;+ declaring it with a commodity directive overrides this and removes+ ambiguity. Towards this end, amounts in commodity directives must+ always be written with a decimal point (a period or comma, followed by+ 0 or more decimal digits).++ Default commodity+ The D directive sets a default commodity (and display format), to be+ used for amounts without a commodity symbol (ie, plain numbers). (Note+ this differs from Ledger's default commodity directive.) The commodity+ and display format will be applied to all subsequent commodity-less+ amounts, or until the next D directive.++ # commodity-less amounts should be treated as dollars+ # (and displayed with symbol on the left, thousands separators and two decimal places)+ D $1,000.00++ 1/1+ a 5 ; <- commodity-less amount, becomes $1+ b++ As with the commodity directive, the amount must always be written with+ a decimal point.++ Declaring accounts+ The account directive predeclares account names. The simplest form is+ account ACCTNAME, eg:++ account assets:bank:checking++ Currently this mainly helps with account name autocompletion in eg+ hledger add, hledger-iadd, hledger-web, and ledger-mode.+ In future it will also help detect misspelled accounts.++ Account names can be followed by a numeric account code:++ account assets 1000+ account assets:bank:checking 1110+ account liabilities 2000+ account revenues 4000+ account expenses 6000++ This affects account display order in reports: accounts with codes are+ listed before accounts without codes, in increasing code order. (Oth-+ erwise, accounts are listed alphabetically.) Account codes should be+ all numeric digits, unique, and separated from the account name by at+ least two spaces (since account names may contain single spaces). By+ convention, often the first digit indicates the type of account, as in+ this numbering scheme and the example above. In future, we might use+ this to recognize account types.++ An account directive can also have indented subdirectives following it,+ which are currently ignored. Here is the full syntax:++ ; account ACCTNAME [OPTIONALCODE]+ ; [OPTIONALSUBDIRECTIVES]++ account assets:bank:checking 1110+ a comment+ some-tag:12345++ Rewriting accounts+ You can define aliases which rewrite your account names (after reading the journal, before generating reports). hledger's account aliases can be useful for: @@ -640,11 +765,11 @@ o customising reports - See also Cookbook: rewrite account names.+ See also Cookbook: Rewrite account names. Basic aliases- To set an account alias, use the alias directive in your journal file.- This affects all subsequent journal entries in the current file or its+ To set an account alias, use the alias directive in your journal file.+ This affects all subsequent journal entries in the current file or its included files. The spaces around the = are optional: alias OLD = NEW@@ -652,91 +777,54 @@ Or, you can use the --alias 'OLD=NEW' option on the command line. This affects all entries. It's useful for trying out aliases interactively. - OLD and NEW are full account names. hledger will replace any occur-- rence of the old account name with the new one. Subaccounts are also+ OLD and NEW are full account names. hledger will replace any occur-+ rence of the old account name with the new one. Subaccounts are also affected. Eg: alias checking = assets:bank:wells fargo:checking # rewrites "checking" to "assets:bank:wells fargo:checking", or "checking:a" to "assets:bank:wells fargo:checking:a" Regex aliases- There is also a more powerful variant that uses a regular expression,+ There is also a more powerful variant that uses a regular expression, indicated by the forward slashes: alias /REGEX/ = REPLACEMENT or --alias '/REGEX/=REPLACEMENT'. - REGEX is a case-insensitive regular expression. Anywhere it matches- inside an account name, the matched part will be replaced by REPLACE-- MENT. If REGEX contains parenthesised match groups, these can be ref-+ REGEX is a case-insensitive regular expression. Anywhere it matches+ inside an account name, the matched part will be replaced by REPLACE-+ MENT. If REGEX contains parenthesised match groups, these can be ref- erenced by the usual numeric backreferences in REPLACEMENT. Eg: alias /^(.+):bank:([^:]+)(.*)/ = \1:\2 \3 # rewrites "assets:bank:wells fargo:checking" to "assets:wells fargo checking" - Also note that REPLACEMENT continues to the end of line (or on command- line, to end of option argument), so it can contain trailing white-+ Also note that REPLACEMENT continues to the end of line (or on command+ line, to end of option argument), so it can contain trailing white- space. Multiple aliases- You can define as many aliases as you like using directives or com-- mand-line options. Aliases are recursive - each alias sees the result- of applying previous ones. (This is different from Ledger, where+ You can define as many aliases as you like using directives or com-+ mand-line options. Aliases are recursive - each alias sees the result+ of applying previous ones. (This is different from Ledger, where aliases are non-recursive by default). Aliases are applied in the fol- lowing order: - 1. alias directives, most recently seen first (recent directives take+ 1. alias directives, most recently seen first (recent directives take precedence over earlier ones; directives not yet seen are ignored) 2. alias options, in the order they appear on the command line end aliases- You can clear (forget) all currently defined aliases with the+ You can clear (forget) all currently defined aliases with the end aliases directive: end aliases - account directive- The account directive predeclares account names. The simplest form is- account ACCTNAME, eg:-- account assets:bank:checking-- Currently this mainly helps with account name autocompletion in eg- hledger add, hledger-iadd, hledger-web, and ledger-mode.- In future it will also help detect misspelled accounts.-- Account names can be followed by a numeric account code:-- account assets 1000- account assets:bank:checking 1110- account liabilities 2000- account revenues 4000- account expenses 6000-- This affects account display order in reports: accounts with codes are- listed before accounts without codes, in increasing code order. (Oth-- erwise, accounts are listed alphabetically.) Account codes should be- all numeric digits, unique, and separated from the account name by at- least two spaces (since account names may contain single spaces). By- convention, often the first digit indicates the type of account, as in- this numbering scheme and the example above. In future, we might use- this to recognize account types.-- An account directive can also have indented subdirectives following it,- which are currently ignored. Here is the full syntax:-- ; account ACCTNAME [OPTIONALCODE]- ; [OPTIONALSUBDIRECTIVES]-- account assets:bank:checking 1110- a comment- some-tag:12345-- apply account directive- You can specify a parent account which will be prepended to all- accounts within a section of the journal. Use the apply account and+ Default parent account+ You can specify a parent account which will be prepended to all+ accounts within a section of the journal. Use the apply account and end apply account directives like so: apply account home@@ -753,7 +841,7 @@ home:food $10 home:cash $-10 - If end apply account is omitted, the effect lasts to the end of the+ If end apply account is omitted, the effect lasts to the end of the file. Included files are also affected, eg: apply account business@@ -762,129 +850,58 @@ apply account personal include personal.journal - Prior to hledger 1.0, legacy account and end spellings were also sup-+ Prior to hledger 1.0, legacy account and end spellings were also sup- ported. - Multi-line comments- A line containing just comment starts a multi-line comment, and a line- containing just end comment ends it. See comments.-- commodity directive- The commodity directive predefines commodities (currently this is just- informational), and also it may define the display format for amounts- in this commodity (overriding the automatically inferred format).-- It may be written on a single line, like this:-- ; commodity EXAMPLEAMOUNT-- ; display AAAA amounts with the symbol on the right, space-separated,- ; using period as decimal point, with four decimal places, and- ; separating thousands with comma.- commodity 1,000.0000 AAAA-- or on multiple lines, using the "format" subdirective. In this case- the commodity symbol appears twice and should be the same in both- places:-- ; commodity SYMBOL- ; format EXAMPLEAMOUNT-- ; display indian rupees with currency name on the left,- ; thousands, lakhs and crores comma-separated,- ; period as decimal point, and two decimal places.- commodity INR- format INR 9,99,99,999.00-- Default commodity- The D directive sets a default commodity (and display format), to be- used for amounts without a commodity symbol (ie, plain numbers). (Note- this differs from Ledger's default commodity directive.) The commodity- and display format will be applied to all subsequent commodity-less- amounts, or until the next D directive.-- # commodity-less amounts should be treated as dollars- # (and displayed with symbol on the left, thousands separators and two decimal places)- D $1,000.00-- 1/1- a 5 ; <- commodity-less amount, becomes $1- b-- Default year- You can set a default year to be used for subsequent dates which don't- specify a year. This is a line beginning with Y followed by the year.- Eg:-- Y2009 ; set default year to 2009-- 12/15 ; equivalent to 2009/12/15- expenses 1- assets-- Y2010 ; change default year to 2010-- 2009/1/30 ; specifies the year, not affected- expenses 1- assets-- 1/31 ; equivalent to 2010/1/31- expenses 1- assets-- Including other files- You can pull in the content of additional journal files by writing an- include directive, like this:-- include path/to/file.journal-- If the path does not begin with a slash, it is relative to the current- file. Glob patterns (*) are not currently supported.-- The include directive can only be used in journal files. It can- include journal, timeclock or timedot files, but not CSV files.--Periodic transactions- Periodic transactions are a kind of rule with a dual purpose: they can- specify recurring future transactions (with --forecast), or budget- goals (with --budget). They look a bit like a transaction, except the- first line is a tilde (~) followed by a period expression:+ Periodic transactions+ Periodic transaction rules (enabled by --forecast or --budget) describe+ recurring transactions. They look like a transaction where the first+ line is a tilde (~) followed by a period expression (mnemonic: ~ is+ like a recurring sine wave): ~ weekly assets:bank:checking $400 ; paycheck income:acme inc - With --forecast, each periodic transaction rule generates recurring- "forecast" transactions at the specified interval, beginning the day- after the latest recorded journal transaction (or today, if there are- no transactions) and ending 6 months from today (or at the report end- date, if specified).+ Periodic transactions have a dual purpose: - With balance --budget, each periodic transaction declares recurring- budget goals for the specified accounts. Eg the example above declares- the goal of receiving $400 from income:acme inc (and also, depositing- $400 into assets:bank:checking) every week.+ o With --forecast, each periodic transaction rule generates future+ transactions, recurring at the specified interval, which can be seen+ in reports. Forecast transactions begin the day after the latest+ recorded journal transaction (or today, if there are no transactions)+ and end 6 months from today (or at the report end date, if speci-+ fied). - For more details, see: balance: Budgeting and Budgeting and Forecast-- ing.+ o With --budget (supported by the balance command), each periodic+ transaction rule declares recurring budget goals for the specified+ accounts, which can be seen in budget reports. Eg the example above+ declares the goal of receiving $400 from income:acme inc (and also,+ depositing $400 into assets:bank:checking) every week. -Automated postings- Automated postings are postings added automatically by rule to certain- transactions (with --auto). An automated posting rule looks like a- transaction where the first line is an equal sign (=) followed by a- query:+ (Actually, you can generate one-off transactions too, by writing a+ period expression with no report interval.) + For more details, see: balance: Budget report and Cookbook: Budgeting+ and Forecasting.++ Automated postings+ Automated postings (enabled by --auto) are postings added automatically+ by rule to certain transactions. An automated posting rule looks like+ a transaction where the first line is an equal sign (=) followed by a+ query (mnemonic: = tests for matching transactions, and also looks like+ posting lines):+ = expenses:gifts budget:gifts *-1 assets:budget *1 - The posting amounts can be of the form *N, which means "the amount of- the matched transaction's first posting, multiplied by N". They can+ The posting amounts can be of the form *N, which means "the amount of+ the matched transaction's first posting, multiplied by N". They can also be ordinary fixed amounts. Fixed amounts with no commodity symbol- will be given the same commodity as the matched transaction's first+ will be given the same commodity as the matched transaction's first posting. - This example adds a corresponding (unbalanced) budget posting to every+ This example adds a corresponding (unbalanced) budget posting to every transaction involving the expenses:gifts account: = expenses:gifts@@ -897,16 +914,19 @@ $ hledger print --auto 2017/12/14 expenses:gifts $20- assets (budget:gifts) $-20+ assets + Like postings recorded by hand, automated postings participate in+ transaction balancing, missing amount inference and balance assertions.+ EDITOR SUPPORT Add-on modes exist for various text editors, to make working with jour-- nal files easier. They add colour, navigation aids and helpful com-- mands. For hledger users who edit the journal file directly (the+ nal files easier. They add colour, navigation aids and helpful com-+ mands. For hledger users who edit the journal file directly (the majority), using one of these modes is quite recommended. - These were written with Ledger in mind, but also work with hledger+ These were written with Ledger in mind, but also work with hledger files: @@ -925,7 +945,7 @@ REPORTING BUGS- Report bugs at http://bugs.hledger.org (or on the #hledger IRC channel+ Report bugs at http://bugs.hledger.org (or on the #hledger IRC channel or hledger mail list) @@ -939,7 +959,7 @@ SEE ALSO- hledger(1), hledger-ui(1), hledger-web(1), hledger-api(1),+ hledger(1), hledger-ui(1), hledger-web(1), hledger-api(1), hledger_csv(5), hledger_journal(5), hledger_timeclock(5), hledger_time- dot(5), ledger(1) @@ -947,4 +967,4 @@ -hledger 1.9 March 2018 hledger_journal(5)+hledger 1.9.1 April 2018 hledger_journal(5)
hledger_timeclock.5 view
@@ -1,5 +1,5 @@ -.TH "hledger_timeclock" "5" "March 2018" "hledger 1.9" "hledger User Manuals"+.TH "hledger_timeclock" "5" "April 2018" "hledger 1.9.1" "hledger User Manuals"
hledger_timeclock.info view
@@ -4,8 +4,8 @@ File: hledger_timeclock.info, Node: Top, Up: (dir) -hledger_timeclock(5) hledger 1.9-********************************+hledger_timeclock(5) hledger 1.9.1+********************************** hledger can read timeclock files. As with Ledger, these are (a subset of) timeclock.el's format, containing clock-in and clock-out entries as
hledger_timeclock.txt view
@@ -77,4 +77,4 @@ -hledger 1.9 March 2018 hledger_timeclock(5)+hledger 1.9.1 April 2018 hledger_timeclock(5)
hledger_timedot.5 view
@@ -1,5 +1,5 @@ -.TH "hledger_timedot" "5" "March 2018" "hledger 1.9" "hledger User Manuals"+.TH "hledger_timedot" "5" "April 2018" "hledger 1.9.1" "hledger User Manuals"
hledger_timedot.info view
@@ -4,8 +4,8 @@ File: hledger_timedot.info, Node: Top, Next: FILE FORMAT, Up: (dir) -hledger_timedot(5) hledger 1.9-******************************+hledger_timedot(5) hledger 1.9.1+******************************** Timedot is a plain text format for logging dated, categorised quantities (of time, usually), supported by hledger. It is convenient for@@ -110,7 +110,7 @@ Tag Table: Node: Top76-Node: FILE FORMAT805-Ref: #file-format906+Node: FILE FORMAT809+Ref: #file-format910 End Tag Table
hledger_timedot.txt view
@@ -124,4 +124,4 @@ -hledger 1.9 March 2018 hledger_timedot(5)+hledger 1.9.1 April 2018 hledger_timedot(5)