imp: commodities/payees/tags: used/declared flags, like accounts
And general cleanup of options and help across the accounts, commodities, payees, tags commands.
This commit is contained in:
parent
38aadddf7b
commit
4a5775da71
@ -79,6 +79,7 @@ module Hledger.Data.Amount (
|
|||||||
amountUnstyled,
|
amountUnstyled,
|
||||||
commodityStylesFromAmounts,
|
commodityStylesFromAmounts,
|
||||||
-- canonicalStyleFrom,
|
-- canonicalStyleFrom,
|
||||||
|
getAmounts,
|
||||||
|
|
||||||
-- ** rendering
|
-- ** rendering
|
||||||
AmountFormat(..),
|
AmountFormat(..),
|
||||||
@ -566,6 +567,13 @@ instance HasAmounts Amount where
|
|||||||
olds)
|
olds)
|
||||||
Nothing -> olds
|
Nothing -> olds
|
||||||
|
|
||||||
|
-- | Get an amount and its attached cost amount if any. Returns one or two amounts.
|
||||||
|
getAmounts :: Amount -> [Amount]
|
||||||
|
getAmounts a@Amount{acost} = a : case acost of
|
||||||
|
Nothing -> []
|
||||||
|
Just (UnitCost c) -> [c]
|
||||||
|
Just (TotalCost c) -> [c]
|
||||||
|
|
||||||
-- AmountStyle helpers
|
-- AmountStyle helpers
|
||||||
|
|
||||||
-- | Replace one AmountStyle with another, but don't just replace the display precision;
|
-- | Replace one AmountStyle with another, but don't just replace the display precision;
|
||||||
@ -1094,13 +1102,17 @@ mixedAmountSetStyles = styleAmounts
|
|||||||
-- v4
|
-- v4
|
||||||
instance HasAmounts MixedAmount where
|
instance HasAmounts MixedAmount where
|
||||||
styleAmounts styles = mapMixedAmountUnsafe (styleAmounts styles)
|
styleAmounts styles = mapMixedAmountUnsafe (styleAmounts styles)
|
||||||
|
-- getAmounts = concatMap getAmounts . amounts
|
||||||
|
|
||||||
instance HasAmounts BalanceData where
|
instance HasAmounts BalanceData where
|
||||||
styleAmounts styles balance@BalanceData{bdexcludingsubs,bdincludingsubs} =
|
styleAmounts styles balance@BalanceData{bdexcludingsubs,bdincludingsubs} =
|
||||||
balance{bdexcludingsubs=styleAmounts styles bdexcludingsubs, bdincludingsubs=styleAmounts styles bdincludingsubs}
|
balance{bdexcludingsubs=styleAmounts styles bdexcludingsubs, bdincludingsubs=styleAmounts styles bdincludingsubs}
|
||||||
|
-- getAmounts BalanceData{bdexcludingsubs, bdincludingsubs} =
|
||||||
|
-- getAmounts bdexcludingsubs <> getAmounts bdincludingsubs
|
||||||
|
|
||||||
instance HasAmounts a => HasAmounts (PeriodData a) where
|
instance HasAmounts a => HasAmounts (PeriodData a) where
|
||||||
styleAmounts styles = fmap (styleAmounts styles)
|
styleAmounts styles = fmap (styleAmounts styles)
|
||||||
|
-- getAmounts
|
||||||
|
|
||||||
instance HasAmounts a => HasAmounts (Account a) where
|
instance HasAmounts a => HasAmounts (Account a) where
|
||||||
styleAmounts styles acct@Account{adata} =
|
styleAmounts styles acct@Account{adata} =
|
||||||
|
|||||||
@ -71,9 +71,14 @@ module Hledger.Data.Journal (
|
|||||||
journalTagsDeclared,
|
journalTagsDeclared,
|
||||||
journalTagsUsed,
|
journalTagsUsed,
|
||||||
journalTagsDeclaredOrUsed,
|
journalTagsDeclaredOrUsed,
|
||||||
|
journalAmounts,
|
||||||
|
journalPostingAmounts,
|
||||||
|
journalPostingAndCostAmounts,
|
||||||
journalCommoditiesDeclared,
|
journalCommoditiesDeclared,
|
||||||
journalCommoditiesUsed,
|
journalCommoditiesUsed,
|
||||||
journalCommodities,
|
journalCommodities,
|
||||||
|
journalCommoditiesFromPriceDirectives,
|
||||||
|
journalCommoditiesFromTransactions,
|
||||||
journalDateSpan,
|
journalDateSpan,
|
||||||
journalDateSpanBothDates,
|
journalDateSpanBothDates,
|
||||||
journalStartDate,
|
journalStartDate,
|
||||||
@ -86,8 +91,7 @@ module Hledger.Data.Journal (
|
|||||||
journalNextTransaction,
|
journalNextTransaction,
|
||||||
journalPrevTransaction,
|
journalPrevTransaction,
|
||||||
journalPostings,
|
journalPostings,
|
||||||
journalPostingAmounts,
|
showJournalPostingAmountsDebug,
|
||||||
showJournalAmountsDebug,
|
|
||||||
journalTransactionsSimilarTo,
|
journalTransactionsSimilarTo,
|
||||||
-- * Account types
|
-- * Account types
|
||||||
journalAccountType,
|
journalAccountType,
|
||||||
@ -395,25 +399,47 @@ journalPostings = concatMap tpostings . jtxns
|
|||||||
journalPostingAmounts :: Journal -> [MixedAmount]
|
journalPostingAmounts :: Journal -> [MixedAmount]
|
||||||
journalPostingAmounts = map pamount . journalPostings
|
journalPostingAmounts = map pamount . journalPostings
|
||||||
|
|
||||||
-- | Show the journal amounts rendered, suitable for debug logging.
|
-- | Show the journal posting amounts rendered, suitable for debug logging.
|
||||||
showJournalAmountsDebug :: Journal -> String
|
showJournalPostingAmountsDebug :: Journal -> String
|
||||||
showJournalAmountsDebug = show.map showMixedAmountOneLine.journalPostingAmounts
|
showJournalPostingAmountsDebug = show . map showMixedAmountOneLine . journalPostingAmounts
|
||||||
|
|
||||||
|
-- | All raw amounts used in this journal's postings and costs,
|
||||||
|
-- with MixedAmounts flattened, in parse order.
|
||||||
|
journalPostingAndCostAmounts :: Journal -> [Amount]
|
||||||
|
journalPostingAndCostAmounts = concatMap getAmounts . concatMap (amountsRaw . pamount) . journalPostings
|
||||||
|
|
||||||
|
-- | All raw amounts appearing in this journal, with MixedAmounts flattened, in no particular order.
|
||||||
|
-- (Including from posting amounts, cost amounts, P directives, and the last D directive.)
|
||||||
|
journalAmounts :: Journal -> S.Set Amount
|
||||||
|
journalAmounts = S.fromList . journalStyleInfluencingAmounts True
|
||||||
|
|
||||||
-- | Sorted unique commodity symbols declared by commodity directives in this journal.
|
-- | Sorted unique commodity symbols declared by commodity directives in this journal.
|
||||||
journalCommoditiesDeclared :: Journal -> [CommoditySymbol]
|
journalCommoditiesDeclared :: Journal -> [CommoditySymbol]
|
||||||
journalCommoditiesDeclared = M.keys . jdeclaredcommodities
|
journalCommoditiesDeclared = M.keys . jdeclaredcommodities
|
||||||
|
|
||||||
-- | Sorted unique commodity symbols used in this journal.
|
-- | Sorted unique commodity symbols used anywhere in this journal, including
|
||||||
|
-- commodity directives, P directives, the last D directive, posting amounts and cost amounts.
|
||||||
journalCommoditiesUsed :: Journal -> [CommoditySymbol]
|
journalCommoditiesUsed :: Journal -> [CommoditySymbol]
|
||||||
journalCommoditiesUsed = S.elems . S.fromList . concatMap (map acommodity . amounts) . journalPostingAmounts
|
journalCommoditiesUsed j = S.elems $
|
||||||
|
journalCommoditiesFromPriceDirectives j <>
|
||||||
|
(S.fromList $ map acommodity $ journalStyleInfluencingAmounts True j)
|
||||||
|
|
||||||
-- | Sorted unique commodity symbols mentioned in this journal.
|
-- | Sorted unique commodity symbols mentioned anywhere in this journal.
|
||||||
|
-- (Including commodity directives, P directives, the last D directive, posting amounts and cost amounts.)
|
||||||
journalCommodities :: Journal -> S.Set CommoditySymbol
|
journalCommodities :: Journal -> S.Set CommoditySymbol
|
||||||
journalCommodities j =
|
journalCommodities j =
|
||||||
M.keysSet (jdeclaredcommodities j)
|
M.keysSet (jdeclaredcommodities j)
|
||||||
<> M.keysSet (jinferredcommoditystyles j)
|
<> journalCommoditiesFromPriceDirectives j
|
||||||
<> S.fromList (concatMap pdcommodities $ jpricedirectives j)
|
<> S.fromList (map acommodity $ journalStyleInfluencingAmounts True j)
|
||||||
where pdcommodities pd = [pdcommodity pd, acommodity $ pdamount pd]
|
|
||||||
|
-- | Sorted unique commodity symbols mentioned in this journal's P directives.
|
||||||
|
journalCommoditiesFromPriceDirectives :: Journal -> S.Set CommoditySymbol
|
||||||
|
journalCommoditiesFromPriceDirectives = S.fromList . concatMap pdcomms . jpricedirectives
|
||||||
|
where pdcomms pd = [pdcommodity pd, acommodity $ pdamount pd]
|
||||||
|
|
||||||
|
-- | Sorted unique commodity symbols used in transactions, in either posting or cost amounts.
|
||||||
|
journalCommoditiesFromTransactions :: Journal -> S.Set CommoditySymbol
|
||||||
|
journalCommoditiesFromTransactions j = S.fromList $ map acommodity $ journalPostingAndCostAmounts j
|
||||||
|
|
||||||
-- | Unique transaction descriptions used in this journal.
|
-- | Unique transaction descriptions used in this journal.
|
||||||
journalDescriptions :: Journal -> [Text]
|
journalDescriptions :: Journal -> [Text]
|
||||||
@ -901,11 +927,11 @@ journalCommodityStylesWith :: Rounding -> Journal -> M.Map CommoditySymbol Amoun
|
|||||||
journalCommodityStylesWith r = amountStylesSetRounding r . journalCommodityStyles
|
journalCommodityStylesWith r = amountStylesSetRounding r . journalCommodityStyles
|
||||||
|
|
||||||
-- | Collect and save inferred amount styles for each commodity based on
|
-- | Collect and save inferred amount styles for each commodity based on
|
||||||
-- the posting amounts in that commodity (excluding price amounts).
|
-- P directive amounts, posting amounts but not cost amounts, and maybe the last D amount, in that commodity.
|
||||||
-- Can return an error message eg if inconsistent number formats are found.
|
-- Can return an error message eg if inconsistent number formats are found.
|
||||||
journalInferCommodityStyles :: Journal -> Either String Journal
|
journalInferCommodityStyles :: Journal -> Either String Journal
|
||||||
journalInferCommodityStyles j =
|
journalInferCommodityStyles j =
|
||||||
case commodityStylesFromAmounts $ journalStyleInfluencingAmounts j of
|
case commodityStylesFromAmounts $ journalStyleInfluencingAmounts False j of
|
||||||
Left e -> Left e
|
Left e -> Left e
|
||||||
Right cs -> Right j{jinferredcommoditystyles = dbg7 "journalInferCommodityStyles" cs}
|
Right cs -> Right j{jinferredcommoditystyles = dbg7 "journalInferCommodityStyles" cs}
|
||||||
|
|
||||||
@ -982,23 +1008,23 @@ journalInferEquityFromCosts verbosetags j =
|
|||||||
-- Just (UnitCost ma) -> c:(concatMap amountCommodities $ amounts ma)
|
-- Just (UnitCost ma) -> c:(concatMap amountCommodities $ amounts ma)
|
||||||
-- Just (TotalCost ma) -> c:(concatMap amountCommodities $ amounts ma)
|
-- Just (TotalCost ma) -> c:(concatMap amountCommodities $ amounts ma)
|
||||||
|
|
||||||
-- | Get an ordered list of amounts in this journal which can
|
-- | Get an ordered list of amounts in this journal which can influence
|
||||||
-- influence canonical amount display styles. Those amounts are, in
|
-- canonical amount display styles (excluding the ones in commodity directives).
|
||||||
-- the following order:
|
-- They are, in the following order:
|
||||||
--
|
--
|
||||||
-- * amounts in market price (P) directives (in parse order)
|
-- * amounts in market price (P) directives (in parse order)
|
||||||
-- * posting amounts in transactions (in parse order)
|
-- * posting amounts and optionally cost amounts (in parse order)
|
||||||
-- * the amount in the final default commodity (D) directive
|
-- * the amount in the final default commodity (D) directive
|
||||||
--
|
--
|
||||||
-- Transaction price amounts (posting amounts' acost field) are not included.
|
journalStyleInfluencingAmounts :: Bool -> Journal -> [Amount]
|
||||||
--
|
journalStyleInfluencingAmounts includecost j =
|
||||||
journalStyleInfluencingAmounts :: Journal -> [Amount]
|
|
||||||
journalStyleInfluencingAmounts j =
|
|
||||||
dbg7 "journalStyleInfluencingAmounts" $
|
dbg7 "journalStyleInfluencingAmounts" $
|
||||||
catMaybes $ concat [
|
catMaybes $ concat [
|
||||||
[mdefaultcommodityamt]
|
[mdefaultcommodityamt]
|
||||||
,map (Just . pdamount) $ jpricedirectives j
|
,map (Just . pdamount) $ jpricedirectives j
|
||||||
,map Just . concatMap (amountsRaw . pamount) $ journalPostings j
|
,map Just $ if includecost
|
||||||
|
then journalPostingAndCostAmounts j
|
||||||
|
else concatMap amountsRaw $ journalPostingAmounts j
|
||||||
]
|
]
|
||||||
where
|
where
|
||||||
-- D's amount style isn't actually stored as an amount, make it into one
|
-- D's amount style isn't actually stored as an amount, make it into one
|
||||||
|
|||||||
@ -435,7 +435,7 @@ postingStatus Posting{pstatus=s, ptransaction=mt} = case s of
|
|||||||
postingAllTags :: Posting -> [Tag]
|
postingAllTags :: Posting -> [Tag]
|
||||||
postingAllTags p = ptags p ++ maybe [] ttags (ptransaction p)
|
postingAllTags p = ptags p ++ maybe [] ttags (ptransaction p)
|
||||||
|
|
||||||
-- | Tags for this transaction including any from its postings.
|
-- | Tags for this transaction including any from its postings (which includes any from the postings' accounts).
|
||||||
transactionAllTags :: Transaction -> [Tag]
|
transactionAllTags :: Transaction -> [Tag]
|
||||||
transactionAllTags t = ttags t ++ concatMap ptags (tpostings t)
|
transactionAllTags t = ttags t ++ concatMap ptags (tpostings t)
|
||||||
|
|
||||||
|
|||||||
@ -67,7 +67,8 @@ module Hledger.Query (
|
|||||||
matchesMixedAmount,
|
matchesMixedAmount,
|
||||||
matchesAmount,
|
matchesAmount,
|
||||||
matchesCommodity,
|
matchesCommodity,
|
||||||
matchesTags,
|
matchesTag,
|
||||||
|
-- patternsMatchTags,
|
||||||
matchesPriceDirective,
|
matchesPriceDirective,
|
||||||
words'',
|
words'',
|
||||||
queryprefixes,
|
queryprefixes,
|
||||||
@ -883,7 +884,7 @@ matchesAccountExtra atypes atags (And qs ) a = all (\q -> matchesAccountExtra at
|
|||||||
matchesAccountExtra atypes atags (AnyPosting qs ) a = all (\q -> matchesAccountExtra atypes atags q a) qs
|
matchesAccountExtra atypes atags (AnyPosting qs ) a = all (\q -> matchesAccountExtra atypes atags q a) qs
|
||||||
matchesAccountExtra atypes atags (AllPostings qs ) a = all (\q -> matchesAccountExtra atypes atags q a) qs
|
matchesAccountExtra atypes atags (AllPostings qs ) a = all (\q -> matchesAccountExtra atypes atags q a) qs
|
||||||
matchesAccountExtra atypes _ (Type ts) a = maybe False (\t -> any (t `isAccountSubtypeOf`) ts) $ atypes a
|
matchesAccountExtra atypes _ (Type ts) a = maybe False (\t -> any (t `isAccountSubtypeOf`) ts) $ atypes a
|
||||||
matchesAccountExtra _ atags (Tag npat vpat) a = matchesTags npat vpat $ atags a
|
matchesAccountExtra _ atags (Tag npat vpat) a = patternsMatchTags npat vpat $ atags a
|
||||||
matchesAccountExtra _ _ q a = matchesAccount q a
|
matchesAccountExtra _ _ q a = matchesAccount q a
|
||||||
|
|
||||||
-- | Does the match expression match this posting ?
|
-- | Does the match expression match this posting ?
|
||||||
@ -911,7 +912,7 @@ matchesPosting (Sym r) Posting{pamount=as} = any (matchesCommodity (Sym r) . aco
|
|||||||
matchesPosting (Tag n v) p = case (reString n, v) of
|
matchesPosting (Tag n v) p = case (reString n, v) of
|
||||||
("payee", Just v') -> maybe False (regexMatchText v' . transactionPayee) $ ptransaction p
|
("payee", Just v') -> maybe False (regexMatchText v' . transactionPayee) $ ptransaction p
|
||||||
("note", Just v') -> maybe False (regexMatchText v' . transactionNote) $ ptransaction p
|
("note", Just v') -> maybe False (regexMatchText v' . transactionNote) $ ptransaction p
|
||||||
(_, mv) -> matchesTags n mv $ postingAllTags p
|
(_, mv) -> patternsMatchTags n mv $ postingAllTags p
|
||||||
matchesPosting (Type _) _ = False
|
matchesPosting (Type _) _ = False
|
||||||
|
|
||||||
-- | Like matchesPosting, but if the posting's account's type is provided,
|
-- | Like matchesPosting, but if the posting's account's type is provided,
|
||||||
@ -958,7 +959,7 @@ matchesTransaction q@(Sym _) t = any (q `matchesPosting`) $ tpostings t
|
|||||||
matchesTransaction (Tag n v) t = case (reString n, v) of
|
matchesTransaction (Tag n v) t = case (reString n, v) of
|
||||||
("payee", Just v') -> regexMatchText v' $ transactionPayee t
|
("payee", Just v') -> regexMatchText v' $ transactionPayee t
|
||||||
("note", Just v') -> regexMatchText v' $ transactionNote t
|
("note", Just v') -> regexMatchText v' $ transactionNote t
|
||||||
(_, v') -> matchesTags n v' $ transactionAllTags t
|
(_, v') -> patternsMatchTags n v' $ transactionAllTags t
|
||||||
matchesTransaction (Type _) _ = False
|
matchesTransaction (Type _) _ = False
|
||||||
|
|
||||||
-- | Like matchesTransaction, but if the journal's account types are provided,
|
-- | Like matchesTransaction, but if the journal's account types are provided,
|
||||||
@ -974,7 +975,7 @@ matchesTransactionExtra atype q@(Type _) t = any (matchesPostingExtra atype q) $
|
|||||||
matchesTransactionExtra _ q t = matchesTransaction q t
|
matchesTransactionExtra _ q t = matchesTransaction q t
|
||||||
|
|
||||||
-- | Does the query match this transaction description ?
|
-- | Does the query match this transaction description ?
|
||||||
-- Tests desc: terms, any other terms are ignored.
|
-- Non-desc: query terms are ignored (this might disrupt some boolean queries).
|
||||||
matchesDescription :: Query -> Text -> Bool
|
matchesDescription :: Query -> Text -> Bool
|
||||||
matchesDescription (Not q) d = not $ q `matchesDescription` d
|
matchesDescription (Not q) d = not $ q `matchesDescription` d
|
||||||
matchesDescription (Any) _ = True
|
matchesDescription (Any) _ = True
|
||||||
@ -994,12 +995,25 @@ matchesDescription _ _ = False
|
|||||||
matchesPayeeWIP :: Query -> Payee -> Bool
|
matchesPayeeWIP :: Query -> Payee -> Bool
|
||||||
matchesPayeeWIP = matchesDescription
|
matchesPayeeWIP = matchesDescription
|
||||||
|
|
||||||
-- | Does the query match the name and optionally the value of any of these tags ?
|
-- | Do this name regex and optional value regex match the name and value of any of these tags ?
|
||||||
matchesTags :: Regexp -> Maybe Regexp -> [Tag] -> Bool
|
patternsMatchTags :: Regexp -> Maybe Regexp -> [Tag] -> Bool
|
||||||
matchesTags namepat valuepat = any (matches namepat valuepat)
|
patternsMatchTags namepat valuepat = any (matches namepat valuepat)
|
||||||
where
|
where
|
||||||
matches npat vpat (n,v) = regexMatchText npat n && maybe (const True) regexMatchText vpat v
|
matches npat vpat (n,v) = regexMatchText npat n && maybe (const True) regexMatchText vpat v
|
||||||
|
|
||||||
|
-- | Does the query match the name and optionally the value of this tag ?
|
||||||
|
-- Non-tag: query terms are ignored (this might disrupt some boolean queries).
|
||||||
|
matchesTag :: Query -> Tag -> Bool
|
||||||
|
matchesTag (Not q) t = not $ q `matchesTag` t
|
||||||
|
matchesTag (Any) _ = True
|
||||||
|
matchesTag (None) _ = False
|
||||||
|
matchesTag (Or qs) t = any (`matchesTag` t) $ filter queryIsTag qs
|
||||||
|
matchesTag (And qs) t = all (`matchesTag` t) $ filter queryIsTag qs
|
||||||
|
matchesTag (AnyPosting qs) t = all (`matchesTag` t) $ filter queryIsTag qs
|
||||||
|
matchesTag (AllPostings qs) t = all (`matchesTag` t) $ filter queryIsTag qs
|
||||||
|
matchesTag (Tag npat mvpat) t = patternsMatchTags npat mvpat [t]
|
||||||
|
matchesTag _ _ = False
|
||||||
|
|
||||||
-- | Does the query match this market price ?
|
-- | Does the query match this market price ?
|
||||||
matchesPriceDirective :: Query -> PriceDirective -> Bool
|
matchesPriceDirective :: Query -> PriceDirective -> Bool
|
||||||
matchesPriceDirective (None) _ = False
|
matchesPriceDirective (None) _ = False
|
||||||
|
|||||||
@ -388,16 +388,16 @@ journalFinalise iopts@InputOpts{auto_,balancingopts_,infer_costs_,infer_equity_,
|
|||||||
-- XXX how to force debug output here ?
|
-- XXX how to force debug output here ?
|
||||||
-- >>= Right . dbg0With (concatMap (T.unpack.showTransaction).jtxns)
|
-- >>= Right . dbg0With (concatMap (T.unpack.showTransaction).jtxns)
|
||||||
-- >>= \j -> deepseq (concatMap (T.unpack.showTransaction).jtxns $ j) (return j)
|
-- >>= \j -> deepseq (concatMap (T.unpack.showTransaction).jtxns $ j) (return j)
|
||||||
<&> dbg9With (lbl "amounts after styling, forecasting, auto-posting".showJournalAmountsDebug)
|
<&> dbg9With (lbl "amounts after styling, forecasting, auto-posting".showJournalPostingAmountsDebug)
|
||||||
>>= (\j -> if checkordereddates then journalCheckOrdereddates j $> j else Right j) -- check ordereddates before assertions. The outer parentheses are needed.
|
>>= (\j -> if checkordereddates then journalCheckOrdereddates j $> j else Right j) -- check ordereddates before assertions. The outer parentheses are needed.
|
||||||
>>= journalBalanceTransactions balancingopts_{ignore_assertions_=not checkassertions} -- infer balance assignments and missing amounts, and maybe check balance assertions.
|
>>= journalBalanceTransactions balancingopts_{ignore_assertions_=not checkassertions} -- infer balance assignments and missing amounts, and maybe check balance assertions.
|
||||||
<&> dbg9With (lbl "amounts after transaction-balancing".showJournalAmountsDebug)
|
<&> dbg9With (lbl "amounts after transaction-balancing".showJournalPostingAmountsDebug)
|
||||||
-- <&> dbg9With (("journalFinalise amounts after styling, forecasting, auto postings, transaction balancing"<>).showJournalAmountsDebug)
|
-- <&> dbg9With (("journalFinalise amounts after styling, forecasting, auto postings, transaction balancing"<>).showJournalPostingAmountsDebug)
|
||||||
>>= journalInferCommodityStyles -- infer commodity styles once more now that all posting amounts are present
|
>>= journalInferCommodityStyles -- infer commodity styles once more now that all posting amounts are present
|
||||||
-- >>= Right . dbg0With (pshow.journalCommodityStyles)
|
-- >>= Right . dbg0With (pshow.journalCommodityStyles)
|
||||||
>>= (if infer_costs_ then journalTagCostsAndEquityAndMaybeInferCosts verbose_tags_ True else pure) -- With --infer-costs, infer costs from equity postings where possible
|
>>= (if infer_costs_ then journalTagCostsAndEquityAndMaybeInferCosts verbose_tags_ True else pure) -- With --infer-costs, infer costs from equity postings where possible
|
||||||
<&> (if infer_equity_ then journalInferEquityFromCosts verbose_tags_ else id) -- With --infer-equity, infer equity postings from costs where possible
|
<&> (if infer_equity_ then journalInferEquityFromCosts verbose_tags_ else id) -- With --infer-equity, infer equity postings from costs where possible
|
||||||
<&> dbg9With (lbl "amounts after equity-inferring".showJournalAmountsDebug)
|
<&> dbg9With (lbl "amounts after equity-inferring".showJournalPostingAmountsDebug)
|
||||||
<&> journalInferMarketPricesFromTransactions -- infer market prices from commodity-exchanging transactions
|
<&> journalInferMarketPricesFromTransactions -- infer market prices from commodity-exchanging transactions
|
||||||
-- <&> dbg6Msg fname -- debug logging
|
-- <&> dbg6Msg fname -- debug logging
|
||||||
<&> dbgJournalAcctDeclOrder (fname <> ": acct decls : ")
|
<&> dbgJournalAcctDeclOrder (fname <> ": acct decls : ")
|
||||||
|
|||||||
@ -81,6 +81,8 @@ module Hledger.Cli.CliOptions (
|
|||||||
|
|
||||||
-- * Other utils
|
-- * Other utils
|
||||||
topicForMode,
|
topicForMode,
|
||||||
|
UsedOrDeclared(..),
|
||||||
|
usedOrDeclaredFromOpts,
|
||||||
|
|
||||||
-- -- * Convenience re-exports
|
-- -- * Convenience re-exports
|
||||||
-- module Data.String.Here,
|
-- module Data.String.Here,
|
||||||
@ -815,6 +817,29 @@ registerWidthsFromOpts CliOpts{width_=Just s} =
|
|||||||
eof
|
eof
|
||||||
return (totalwidth, descwidth)
|
return (totalwidth, descwidth)
|
||||||
|
|
||||||
|
-- A common choice for filtering lists of declarable things.
|
||||||
|
data UsedOrDeclared
|
||||||
|
= Used
|
||||||
|
| Declared
|
||||||
|
| Undeclared
|
||||||
|
| Unused
|
||||||
|
deriving (Show, Eq)
|
||||||
|
|
||||||
|
-- Get the flag of this kind from opts, or raise an error if there's more than one.
|
||||||
|
usedOrDeclaredFromOpts :: CliOpts -> Maybe UsedOrDeclared
|
||||||
|
usedOrDeclaredFromOpts CliOpts{rawopts_=rawopts} =
|
||||||
|
case ( boolopt "used" rawopts
|
||||||
|
, boolopt "declared" rawopts
|
||||||
|
, boolopt "undeclared" rawopts
|
||||||
|
, boolopt "unused" rawopts
|
||||||
|
) of
|
||||||
|
(False, False, False, False) -> Nothing
|
||||||
|
(True, False, False, False) -> Just Used
|
||||||
|
(False, True, False, False) -> Just Declared
|
||||||
|
(False, False, True, False) -> Just Undeclared
|
||||||
|
(False, False, False, True) -> Just Unused
|
||||||
|
_ -> error' "please pick at most one of --used, --declared, --undeclared, --unused"
|
||||||
|
|
||||||
-- Other utils
|
-- Other utils
|
||||||
|
|
||||||
-- None of https://hackage.haskell.org/package/directory-1.3.8.1/docs/System-Directory.html#g:5
|
-- None of https://hackage.haskell.org/package/directory-1.3.8.1/docs/System-Directory.html#g:5
|
||||||
|
|||||||
@ -36,33 +36,29 @@ import Safe (headDef)
|
|||||||
accountsmode = hledgerCommandMode
|
accountsmode = hledgerCommandMode
|
||||||
$(embedFileRelative "Hledger/Cli/Commands/Accounts.txt")
|
$(embedFileRelative "Hledger/Cli/Commands/Accounts.txt")
|
||||||
(
|
(
|
||||||
[flagNone ["used","u"] (setboolopt "used") "show only accounts used by transactions"
|
[flagNone ["used","u"] (setboolopt "used") "list accounts used"
|
||||||
,flagNone ["declared","d"] (setboolopt "declared") "show only accounts declared by account directive" -- no s to avoid line wrap
|
,flagNone ["declared","d"] (setboolopt "declared") "list accounts declared"
|
||||||
,flagNone ["unused"] (setboolopt "unused") "show only accounts declared but not used"
|
,flagNone ["undeclared"] (setboolopt "undeclared") "list accounts used but not declared"
|
||||||
,flagNone ["undeclared"] (setboolopt "undeclared") "show only accounts used but not declared"
|
,flagNone ["unused"] (setboolopt "unused") "list accounts declared but not used"
|
||||||
|
,flagNone ["find"] (setboolopt "find") "list the first account matched by the first argument (a case-insensitive infix regexp)"
|
||||||
|
|
||||||
,flagNone ["types"] (setboolopt "types") "also show account types when known"
|
,flagNone ["types"] (setboolopt "types") "also show account types when known"
|
||||||
,flagNone ["positions"] (setboolopt "positions") "also show where accounts were declared"
|
,flagNone ["positions"] (setboolopt "positions") "also show where accounts were declared"
|
||||||
,flagNone ["directives"] (setboolopt "directives") "show as account directives, for use in journals"
|
,flagNone ["directives"] (setboolopt "directives") "show as account directives, for use in journals"
|
||||||
,flagNone ["find"] (setboolopt "find") "find the first account matched by the first argument (a case-insensitive infix regexp or account name)"
|
|
||||||
]
|
]
|
||||||
++ flattreeflags False ++
|
++ flattreeflags False ++
|
||||||
[flagReq ["drop"] (\s opts -> Right $ setopt "drop" s opts) "N" "flat mode: omit N leading account name parts"]
|
[flagReq ["drop"] (\s opts -> Right $ setopt "drop" s opts) "N" "flat mode: omit N leading account name parts"]
|
||||||
)
|
)
|
||||||
cligeneralflagsgroups1
|
cligeneralflagsgroups1
|
||||||
hiddenflags
|
hiddenflags
|
||||||
([], Just $ argsFlag "[QUERY]")
|
([], Just $ argsFlag "[QUERY..]")
|
||||||
|
|
||||||
-- | The accounts command.
|
-- | The accounts command.
|
||||||
accounts :: CliOpts -> Journal -> IO ()
|
accounts :: CliOpts -> Journal -> IO ()
|
||||||
accounts CliOpts{rawopts_=rawopts, reportspec_=ReportSpec{_rsQuery=query,_rsReportOpts=ropts}} j = do
|
accounts opts@CliOpts{rawopts_=rawopts, reportspec_=ReportSpec{_rsQuery=query,_rsReportOpts=ropts}} j = do
|
||||||
|
|
||||||
-- 1. identify the accounts we'll show
|
-- 1. identify the accounts we'll show
|
||||||
let tree = tree_ ropts
|
let tree = tree_ ropts
|
||||||
used = boolopt "used" rawopts
|
|
||||||
decl = boolopt "declared" rawopts
|
|
||||||
unused = boolopt "unused" rawopts
|
|
||||||
undecl = boolopt "undeclared" rawopts
|
|
||||||
find_ = boolopt "find" rawopts
|
|
||||||
types = boolopt "types" rawopts
|
types = boolopt "types" rawopts
|
||||||
positions = boolopt "positions" rawopts
|
positions = boolopt "positions" rawopts
|
||||||
directives = boolopt "directives" rawopts
|
directives = boolopt "directives" rawopts
|
||||||
@ -71,13 +67,13 @@ accounts CliOpts{rawopts_=rawopts, reportspec_=ReportSpec{_rsQuery=query,_rsRepo
|
|||||||
-- just the acct: part of the query will be reapplied later, after clipping
|
-- just the acct: part of the query will be reapplied later, after clipping
|
||||||
acctq = dbg4 "acctq" $ filterQuery queryIsAcct query
|
acctq = dbg4 "acctq" $ filterQuery queryIsAcct query
|
||||||
dep = dbg4 "depth" $ queryDepth $ filterQuery queryIsDepth query
|
dep = dbg4 "depth" $ queryDepth $ filterQuery queryIsDepth query
|
||||||
matcheddeclaredaccts = dbg5 "matcheddeclaredaccts" $
|
matchedused = dbg5 "matchedused" $ nub $ map paccount $ journalPostings $ filterJournalPostings nodepthq j
|
||||||
|
matcheddeclared = dbg5 "matcheddeclared" $
|
||||||
nub $
|
nub $
|
||||||
filter (matchesAccountExtra (journalAccountType j) (journalInheritedAccountTags j) nodepthq) $
|
filter (matchesAccountExtra (journalAccountType j) (journalInheritedAccountTags j) nodepthq) $
|
||||||
map fst $ jdeclaredaccounts j
|
map fst $ jdeclaredaccounts j
|
||||||
matchedusedaccts = dbg5 "matchedusedaccts" $ nub $ map paccount $ journalPostings $ filterJournalPostings nodepthq j
|
matchedundeclared = dbg5 "matchedundeclared" $ nub $ matchedused \\ matcheddeclared
|
||||||
matchedunusedaccts = dbg5 "matchedunusedaccts" $ nub $ matcheddeclaredaccts \\ matchedusedaccts
|
matchedunused = dbg5 "matchedunused" $ nub $ matcheddeclared \\ matchedused
|
||||||
matchedundeclaredaccts = dbg5 "matchedundeclaredaccts" $ nub $ matchedusedaccts \\ matcheddeclaredaccts
|
|
||||||
-- keep synced with aregister
|
-- keep synced with aregister
|
||||||
matchedacct = dbg5 "matchedacct" $
|
matchedacct = dbg5 "matchedacct" $
|
||||||
fromMaybe (error' $ show apat ++ " did not match any account.") -- PARTIAL:
|
fromMaybe (error' $ show apat ++ " did not match any account.") -- PARTIAL:
|
||||||
@ -89,14 +85,16 @@ accounts CliOpts{rawopts_=rawopts, reportspec_=ReportSpec{_rsQuery=query,_rsRepo
|
|||||||
apat = headDef
|
apat = headDef
|
||||||
(error' "With --find, please provide an account name or\naccount pattern (case-insensitive, infix, regexp) as first command argument.")
|
(error' "With --find, please provide an account name or\naccount pattern (case-insensitive, infix, regexp) as first command argument.")
|
||||||
$ listofstringopt "args" rawopts
|
$ listofstringopt "args" rawopts
|
||||||
|
matchedall = matcheddeclared ++ matchedused
|
||||||
accts = dbg5 "accts to show" $ if
|
accts = dbg5 "accts to show" $
|
||||||
| not decl && used -> matchedusedaccts
|
case (usedOrDeclaredFromOpts opts, boolopt "find" rawopts) of
|
||||||
| decl && not used -> matcheddeclaredaccts
|
(Nothing, False) -> matchedall
|
||||||
| unused -> matchedunusedaccts
|
(Nothing, True) -> [matchedacct]
|
||||||
| undecl -> matchedundeclaredaccts
|
(Just Used, False) -> matchedused
|
||||||
| find_ -> [matchedacct]
|
(Just Declared, False) -> matcheddeclared
|
||||||
| otherwise -> matcheddeclaredaccts ++ matchedusedaccts
|
(Just Undeclared, False) -> matchedundeclared
|
||||||
|
(Just Unused, False) -> matchedunused
|
||||||
|
_ -> error' "please pick at most one of --used, --declared, --undeclared, --unused, --find"
|
||||||
|
|
||||||
-- 2. sort them by declaration order (then undeclared accounts alphabetically)
|
-- 2. sort them by declaration order (then undeclared accounts alphabetically)
|
||||||
-- within each group of siblings
|
-- within each group of siblings
|
||||||
|
|||||||
@ -1,39 +1,34 @@
|
|||||||
## accounts
|
## accounts
|
||||||
|
|
||||||
List account names.
|
List the account names used or declared in the journal.
|
||||||
|
|
||||||
```flags
|
```flags
|
||||||
Flags:
|
Flags:
|
||||||
-u --used show only accounts used by transactions
|
-u --used list accounts used
|
||||||
-d --declared show only accounts declared by account directive
|
-d --declared list accounts declared
|
||||||
--unused show only accounts declared but not used
|
--undeclared list accounts used but not declared
|
||||||
--undeclared show only accounts used but not declared
|
--unused list accounts declared but not used
|
||||||
|
--find list the first account matched by the first
|
||||||
|
argument (a case-insensitive infix regexp)
|
||||||
--types also show account types when known
|
--types also show account types when known
|
||||||
--positions also show where accounts were declared
|
--positions also show where accounts were declared
|
||||||
--directives show as account directives, for use in journals
|
--directives show as account directives, for use in journals
|
||||||
--find find the first account matched by the first
|
|
||||||
argument (a case-insensitive infix regexp or
|
|
||||||
account name)
|
|
||||||
-l --flat list/tree mode: show accounts as a flat list
|
-l --flat list/tree mode: show accounts as a flat list
|
||||||
(default)
|
(default)
|
||||||
-t --tree list/tree mode: show accounts as a tree
|
-t --tree list/tree mode: show accounts as a tree
|
||||||
--drop=N flat mode: omit N leading account name parts
|
--drop=N flat mode: omit N leading account name parts
|
||||||
```
|
```
|
||||||
|
|
||||||
This command lists account names.
|
This command lists account names - all of them by default.
|
||||||
By default it shows all known accounts, either used in transactions or declared with account directives.
|
or just the ones which have been used in transactions,
|
||||||
|
or declared with `account` directives,
|
||||||
|
or used but not declared,
|
||||||
|
or declared but not used,
|
||||||
|
or just the first account name matched by a pattern.
|
||||||
|
|
||||||
With query arguments, only matched account names and account names referenced by matched postings are shown.
|
You can add query arguments to select a subset of transactions or accounts.
|
||||||
|
|
||||||
Or it can show just
|
It shows a flat list by default. With `--tree`, it uses indentation to show the account hierarchy.
|
||||||
the used accounts (`--used`/`-u`),
|
|
||||||
the declared accounts (`--declared`/`-d`),
|
|
||||||
the accounts declared but not used (`--unused`),
|
|
||||||
the accounts used but not declared (`--undeclared`),
|
|
||||||
or the first account matched by an account name pattern, if any (`--find`).
|
|
||||||
|
|
||||||
It shows a flat list by default. With `--tree`, it uses indentation to
|
|
||||||
show the account hierarchy.
|
|
||||||
In flat mode you can add `--drop N` to omit the first few account name components.
|
In flat mode you can add `--drop N` to omit the first few account name components.
|
||||||
Account names can be depth-clipped with `depth:N` or `--depth N` or `-N`.
|
Account names can be depth-clipped with `depth:N` or `--depth N` or `-N`.
|
||||||
|
|
||||||
@ -44,8 +39,7 @@ With `--positions`, it also shows the file and line number of each
|
|||||||
account's declaration, if any, and the account's overall declaration order;
|
account's declaration, if any, and the account's overall declaration order;
|
||||||
these may be useful when troubleshooting account display order.
|
these may be useful when troubleshooting account display order.
|
||||||
|
|
||||||
With `--directives`, it adds the `account` keyword, showing
|
With `--directives`, it shows valid account directives which could be pasted into a journal file.
|
||||||
valid account directives which can be pasted into a journal file.
|
|
||||||
This is useful together with `--undeclared` when updating your account declarations
|
This is useful together with `--undeclared` when updating your account declarations
|
||||||
to satisfy `hledger check accounts`.
|
to satisfy `hledger check accounts`.
|
||||||
|
|
||||||
|
|||||||
@ -12,22 +12,47 @@ module Hledger.Cli.Commands.Commodities (
|
|||||||
,commodities
|
,commodities
|
||||||
) where
|
) where
|
||||||
|
|
||||||
|
import qualified Data.Map as M
|
||||||
import qualified Data.Set as S
|
import qualified Data.Set as S
|
||||||
import qualified Data.Text.IO as T
|
import qualified Data.Text.IO as T
|
||||||
|
import System.Console.CmdArgs.Explicit
|
||||||
|
|
||||||
import Hledger
|
import Hledger
|
||||||
import Hledger.Cli.CliOptions
|
import Hledger.Cli.CliOptions
|
||||||
|
import Data.List.Extra (nubSort)
|
||||||
|
import Data.List ((\\))
|
||||||
|
|
||||||
|
|
||||||
-- | Command line options for this command.
|
-- | Command line options for this command.
|
||||||
commoditiesmode = hledgerCommandMode
|
commoditiesmode = hledgerCommandMode
|
||||||
$(embedFileRelative "Hledger/Cli/Commands/Commodities.txt")
|
$(embedFileRelative "Hledger/Cli/Commands/Commodities.txt")
|
||||||
[]
|
[flagNone ["used"] (setboolopt "used") "list commodities used"
|
||||||
|
,flagNone ["declared"] (setboolopt "declared") "list commodities declared"
|
||||||
|
,flagNone ["undeclared"] (setboolopt "undeclared") "list commodities used but not declared"
|
||||||
|
,flagNone ["unused"] (setboolopt "unused") "list commodities declared but not used"
|
||||||
|
]
|
||||||
[generalflagsgroup2]
|
[generalflagsgroup2]
|
||||||
[]
|
[]
|
||||||
([], Nothing)
|
([], Just $ argsFlag "[QUERY..]")
|
||||||
|
|
||||||
commodities :: CliOpts -> Journal -> IO ()
|
commodities :: CliOpts -> Journal -> IO ()
|
||||||
commodities _copts =
|
commodities opts@CliOpts{reportspec_ = ReportSpec{_rsQuery = query}} j = do
|
||||||
-- TODO support --declared/--used like accounts, payees
|
let
|
||||||
mapM_ T.putStrLn . S.filter (/= "AUTO") . journalCommodities
|
used = dbg5 "used" $
|
||||||
|
S.toList $ journalCommoditiesFromPriceDirectives j <> journalCommoditiesFromTransactions j
|
||||||
|
declared' = dbg5 "declared" $ M.keys $ jdeclaredcommodities j
|
||||||
|
unused = dbg5 "unused" $ declared' \\ used
|
||||||
|
undeclared = dbg5 "undeclared" $ used \\ declared'
|
||||||
|
all' = dbg5 "all" $ nubSort $ concat [
|
||||||
|
journalCommoditiesDeclared j
|
||||||
|
,map pdcommodity $ jpricedirectives j -- gets the first symbol from P directives
|
||||||
|
,map acommodity (S.toList $ journalAmounts j) -- includes the second symbol from P directives
|
||||||
|
]
|
||||||
|
|
||||||
|
mapM_ T.putStrLn $ filter (matchesCommodity query) $
|
||||||
|
case usedOrDeclaredFromOpts opts of
|
||||||
|
Nothing -> all'
|
||||||
|
Just Used -> used
|
||||||
|
Just Declared -> declared'
|
||||||
|
Just Undeclared -> undeclared
|
||||||
|
Just Unused -> unused
|
||||||
|
|||||||
@ -1,9 +1,19 @@
|
|||||||
## commodities
|
## commodities
|
||||||
|
|
||||||
List all commodity/currency symbols used or declared in the journal.
|
List the commodity symbols used or declared in the journal.
|
||||||
|
|
||||||
```flags
|
```flags
|
||||||
Flags:
|
Flags:
|
||||||
no command-specific flags
|
--used list commodities used
|
||||||
|
--declared list commodities declared
|
||||||
|
--undeclared list commodities used but not declared
|
||||||
|
--unused list commodities declared but not used
|
||||||
```
|
```
|
||||||
|
|
||||||
|
This command lists commodity symbols/names - all of them by default,
|
||||||
|
or just the ones which have been used in transactions or `P` directives,
|
||||||
|
or declared with `commodity` directives,
|
||||||
|
or used but not declared,
|
||||||
|
or declared but not used.
|
||||||
|
|
||||||
|
You can add cur: query arguments to further limit the commodities.
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
## descriptions
|
## descriptions
|
||||||
|
|
||||||
List the unique descriptions that appear in transactions.
|
List the unique descriptions used in transactions.
|
||||||
|
|
||||||
```flags
|
```flags
|
||||||
Flags:
|
Flags:
|
||||||
|
|||||||
@ -14,35 +14,41 @@ module Hledger.Cli.Commands.Payees (
|
|||||||
,payees
|
,payees
|
||||||
) where
|
) where
|
||||||
|
|
||||||
import qualified Data.Set as S
|
|
||||||
import qualified Data.Text.IO as T
|
import qualified Data.Text.IO as T
|
||||||
import System.Console.CmdArgs.Explicit as C
|
import System.Console.CmdArgs.Explicit
|
||||||
|
|
||||||
import Hledger
|
import Hledger
|
||||||
import Hledger.Cli.CliOptions
|
import Hledger.Cli.CliOptions
|
||||||
|
import Data.List ((\\))
|
||||||
|
import Data.List.Extra (nubSort)
|
||||||
|
|
||||||
|
|
||||||
-- | Command line options for this command.
|
-- | Command line options for this command.
|
||||||
payeesmode = hledgerCommandMode
|
payeesmode = hledgerCommandMode
|
||||||
$(embedFileRelative "Hledger/Cli/Commands/Payees.txt")
|
$(embedFileRelative "Hledger/Cli/Commands/Payees.txt")
|
||||||
[flagNone ["declared"] (setboolopt "declared") "show payees declared with payee directives"
|
[flagNone ["used"] (setboolopt "used") "list payees used"
|
||||||
,flagNone ["used"] (setboolopt "used") "show payees referenced by transactions"
|
,flagNone ["declared"] (setboolopt "declared") "list payees declared"
|
||||||
|
,flagNone ["undeclared"] (setboolopt "undeclared") "list payees used but not declared"
|
||||||
|
,flagNone ["unused"] (setboolopt "unused") "list payees declared but not used"
|
||||||
]
|
]
|
||||||
cligeneralflagsgroups1
|
cligeneralflagsgroups1
|
||||||
hiddenflags
|
hiddenflags
|
||||||
([], Just $ argsFlag "[QUERY]")
|
([], Just $ argsFlag "[QUERY..]")
|
||||||
|
|
||||||
-- | The payees command.
|
-- | The payees command.
|
||||||
payees :: CliOpts -> Journal -> IO ()
|
payees :: CliOpts -> Journal -> IO ()
|
||||||
payees CliOpts{rawopts_=rawopts, reportspec_=ReportSpec{_rsQuery=query}} j = do
|
payees opts@CliOpts{reportspec_=ReportSpec{_rsQuery=query}} j = do
|
||||||
let
|
let
|
||||||
decl = boolopt "declared" rawopts
|
-- XXX matchesPayeeWIP is currently an alias for matchesDescription, not sure if it matters
|
||||||
used = boolopt "used" rawopts
|
matchedused = dbg5 "matchedused" $ nubSort $ map transactionPayee $ filter (matchesTransaction query) $ jtxns j
|
||||||
-- XXX matchesPayee is currently an alias for matchesDescription, not sure if it matters
|
matcheddeclared = dbg5 "matcheddeclared" $ nubSort $ filter (matchesPayeeWIP query) $ journalPayeesDeclared j
|
||||||
matcheddeclaredpayees = S.fromList . filter (matchesPayeeWIP query) $ journalPayeesDeclared j
|
matchedunused = dbg5 "matchedunused" $ nubSort $ matcheddeclared \\ matchedused
|
||||||
matchedusedpayees = S.fromList . map transactionPayee $ filter (matchesTransaction query) $ jtxns j
|
matchedundeclared = dbg5 "matchedundeclared" $ nubSort $ matchedused \\ matcheddeclared
|
||||||
payees' =
|
matchedall = dbg5 "matchedall" $ nubSort $ matcheddeclared ++ matchedused
|
||||||
if | decl && not used -> matcheddeclaredpayees
|
mapM_ T.putStrLn $ case usedOrDeclaredFromOpts opts of
|
||||||
| not decl && used -> matchedusedpayees
|
Nothing -> matchedall
|
||||||
| otherwise -> matcheddeclaredpayees <> matchedusedpayees
|
Just Used -> matchedused
|
||||||
mapM_ T.putStrLn payees'
|
Just Declared -> matcheddeclared
|
||||||
|
Just Undeclared -> matchedundeclared
|
||||||
|
Just Unused -> matchedunused
|
||||||
|
|
||||||
|
|||||||
@ -1,23 +1,25 @@
|
|||||||
## payees
|
## payees
|
||||||
|
|
||||||
List the unique payee/payer names that appear in transactions.
|
List the payee/payer names used or declared in the journal.
|
||||||
|
|
||||||
```flags
|
```flags
|
||||||
Flags:
|
Flags:
|
||||||
--declared show payees declared with payee directives
|
--used list payees used
|
||||||
--used show payees referenced by transactions
|
--declared list payees declared
|
||||||
|
--undeclared list payees used but not declared
|
||||||
|
--unused list payees declared but not used
|
||||||
```
|
```
|
||||||
|
|
||||||
This command lists unique payee/payer names which have been
|
This command lists unique payee/payer names - all of them by default,
|
||||||
declared with payee directives (--declared),
|
or just the ones which have been used in transaction descriptions,
|
||||||
used in transaction descriptions (--used),
|
or declared with `payee` directives,
|
||||||
or both (the default).
|
or used but not declared,
|
||||||
|
or declared but not used.
|
||||||
|
|
||||||
The payee/payer is the part of the transaction description before a | character
|
The payee/payer name is the part of the transaction description before a | character
|
||||||
(or if there is no |, the whole description).
|
(or if there is no |, the whole description).
|
||||||
|
|
||||||
You can add query arguments to select a subset of transactions. This implies --used.
|
You can add query arguments to select a subset of transactions or payees.
|
||||||
|
|
||||||
|
|
||||||
Example:
|
Example:
|
||||||
```cli
|
```cli
|
||||||
|
|||||||
@ -60,7 +60,7 @@ printmode = hledgerCommandMode
|
|||||||
flagReq ["match","m"] (\s opts -> Right $ setopt "match" s opts) arg
|
flagReq ["match","m"] (\s opts -> Right $ setopt "match" s opts) arg
|
||||||
("fuzzy search for one recent transaction with description closest to "++arg)
|
("fuzzy search for one recent transaction with description closest to "++arg)
|
||||||
,flagReq ["base-url"] (\s opts -> Right $ setopt "base-url" s opts) "URLPREFIX" "in html output, generate links to hledger-web, with this prefix. (Usually the base url shown by hledger-web; can also be relative.)"
|
,flagReq ["base-url"] (\s opts -> Right $ setopt "base-url" s opts) "URLPREFIX" "in html output, generate links to hledger-web, with this prefix. (Usually the base url shown by hledger-web; can also be relative.)"
|
||||||
,flagNone ["location"] (setboolopt "location") "add file/line number tags to print output"
|
,flagNone ["location"] (setboolopt "location") "add tags showing file paths and line numbers"
|
||||||
,outputFormatFlag ["txt","beancount","csv","tsv","html","fods","json","sql"]
|
,outputFormatFlag ["txt","beancount","csv","tsv","html","fods","json","sql"]
|
||||||
,outputFileFlag
|
,outputFileFlag
|
||||||
])
|
])
|
||||||
@ -113,9 +113,9 @@ print' opts@CliOpts{rawopts_=rawopts} j = do
|
|||||||
let
|
let
|
||||||
-- lbl = lbl_ "print'"
|
-- lbl = lbl_ "print'"
|
||||||
j' = j
|
j' = j
|
||||||
-- & dbg9With (lbl "amounts before setting full precision".showJournalAmountsDebug)
|
-- & dbg9With (lbl "amounts before setting full precision".showJournalPostingAmountsDebug)
|
||||||
& journalMapPostingAmounts mixedAmountSetFullPrecision
|
& journalMapPostingAmounts mixedAmountSetFullPrecision
|
||||||
-- & dbg9With (lbl "amounts after setting full precision: ".showJournalAmountsDebug)
|
-- & dbg9With (lbl "amounts after setting full precision: ".showJournalPostingAmountsDebug)
|
||||||
& if boolopt "location" rawopts then journalMapTransactions addLocationTag else id
|
& if boolopt "location" rawopts then journalMapTransactions addLocationTag else id
|
||||||
|
|
||||||
case maybestringopt "match" $ rawopts_ opts of
|
case maybestringopt "match" $ rawopts_ opts of
|
||||||
|
|||||||
@ -1,5 +1,6 @@
|
|||||||
{-# LANGUAGE OverloadedStrings #-}
|
{-# LANGUAGE OverloadedStrings #-}
|
||||||
{-# LANGUAGE TemplateHaskell #-}
|
{-# LANGUAGE TemplateHaskell #-}
|
||||||
|
{-# LANGUAGE TupleSections #-}
|
||||||
|
|
||||||
module Hledger.Cli.Commands.Tags (
|
module Hledger.Cli.Commands.Tags (
|
||||||
tagsmode
|
tagsmode
|
||||||
@ -12,47 +13,73 @@ import Data.List.Extra (nubSort)
|
|||||||
import qualified Data.Text as T
|
import qualified Data.Text as T
|
||||||
import qualified Data.Text.IO as T
|
import qualified Data.Text.IO as T
|
||||||
import Safe
|
import Safe
|
||||||
import System.Console.CmdArgs.Explicit as C
|
import System.Console.CmdArgs.Explicit
|
||||||
|
|
||||||
import Hledger
|
import Hledger
|
||||||
import Hledger.Cli.CliOptions
|
import Hledger.Cli.CliOptions
|
||||||
|
|
||||||
|
|
||||||
tagsmode = hledgerCommandMode
|
tagsmode = hledgerCommandMode
|
||||||
$(embedFileRelative "Hledger/Cli/Commands/Tags.txt")
|
$(embedFileRelative "Hledger/Cli/Commands/Tags.txt")
|
||||||
[flagNone ["values"] (setboolopt "values") "list tag values instead of tag names"
|
[
|
||||||
,flagNone ["parsed"] (setboolopt "parsed") "show tags/values in the order they were parsed, including duplicates"
|
flagNone ["used"] (setboolopt "used") "list tags used"
|
||||||
|
,flagNone ["declared"] (setboolopt "declared") "list tags declared"
|
||||||
|
,flagNone ["undeclared"] (setboolopt "undeclared") "list tags used but not declared"
|
||||||
|
,flagNone ["unused"] (setboolopt "unused") "list tags declared but not used"
|
||||||
|
,flagNone ["values"] (setboolopt "values") "list tag values instead of tag names"
|
||||||
|
,flagNone ["parsed"] (setboolopt "parsed") "show them in the order they were parsed (mostly), including duplicates"
|
||||||
]
|
]
|
||||||
cligeneralflagsgroups1
|
cligeneralflagsgroups1
|
||||||
hiddenflags
|
hiddenflags
|
||||||
([], Just $ argsFlag "[TAGREGEX [QUERY...]]")
|
([], Just $ argsFlag "[TAGREGEX [QUERY..]]")
|
||||||
|
|
||||||
tags :: CliOpts -> Journal -> IO ()
|
tags :: CliOpts -> Journal -> IO ()
|
||||||
tags CliOpts{rawopts_=rawopts,reportspec_=rspec} j = do
|
tags opts@CliOpts{rawopts_=rawopts, reportspec_=rspec@ReportSpec{_rsQuery=_q, _rsReportOpts=ropts}} j = do
|
||||||
let today = _rsDay rspec
|
let today = _rsDay rspec
|
||||||
args = listofstringopt "args" rawopts
|
args = listofstringopt "args" rawopts
|
||||||
-- first argument is a tag name pattern, others are a hledger query: hledger tags [TAGREGEX [QUERYARGS..]]
|
-- For convenience/power, the first argument is a tag name regex,
|
||||||
|
-- separate from the main query arguments: hledger tags [TAGREGEX [QUERYARGS..]]
|
||||||
|
-- So we have to re-parse the query here. Overcomplicated ?
|
||||||
mtagpat <- mapM (either Fail.fail pure . toRegexCI . T.pack) $ headMay args
|
mtagpat <- mapM (either Fail.fail pure . toRegexCI . T.pack) $ headMay args
|
||||||
let
|
let
|
||||||
querystr = map T.pack $ drop 1 args
|
|
||||||
values = boolopt "values" rawopts
|
values = boolopt "values" rawopts
|
||||||
parsed = boolopt "parsed" rawopts
|
parsed = boolopt "parsed" rawopts
|
||||||
empty = empty_ $ _rsReportOpts rspec
|
empty = empty_ ropts
|
||||||
|
querystr = map T.pack $ drop 1 args
|
||||||
query <- either usageError (return . fst) $ parseQueryList today querystr
|
query <- either usageError (return . fst) $ parseQueryList today querystr
|
||||||
let
|
let
|
||||||
q = simplifyQuery $ And [queryFromFlags $ _rsReportOpts rspec, query]
|
q = simplifyQuery $ And [queryFromFlags ropts, query]
|
||||||
matchedtxns = filter (q `matchesTransaction`) $ jtxns $ journalApplyValuationFromOpts rspec j
|
txns = filter (q `matchesTransaction`) $ jtxns $ journalApplyValuationFromOpts rspec j
|
||||||
-- also list tags from matched account declarations, but not if there is
|
accts =
|
||||||
-- a query for something transaction-related, like date: or amt:.
|
-- also search for tags in matched account declarations,
|
||||||
matchedaccts = dbg4 "accts" $
|
-- unless there is a query for something transaction-specific, like date: or amt:.
|
||||||
if dbg4 "queryIsTransactionRelated" $ queryIsTransactionRelated $ dbg4 "q" q
|
if dbg5 "queryIsTransactionRelated" $ queryIsTransactionRelated $ dbg4 "q" q
|
||||||
then []
|
then []
|
||||||
else filter (matchesAccountExtra (journalAccountType j) (journalInheritedAccountTags j) q) $
|
else filter (matchesAccountExtra (journalAccountType j) (journalInheritedAccountTags j) q) $
|
||||||
map fst $ jdeclaredaccounts j
|
map fst $ jdeclaredaccounts j
|
||||||
tagsorvalues =
|
|
||||||
|
used = dbg5 "used" $ concatMap (journalAccountTags j) accts ++ concatMap transactionAllTags txns
|
||||||
|
declared' = dbg5 "declared" $ filter (q `matchesTag`) $ map (,"") $ journalTagsDeclared j
|
||||||
|
(usednames, declarednames) = (map fst used, map fst declared')
|
||||||
|
unused = dbg5 "unused" $ filter (not . (`elem` usednames) . fst) declared'
|
||||||
|
undeclared = dbg5 "undeclared" $ filter (not . (`elem` declarednames) . fst) used
|
||||||
|
all' = dbg5 "all" $ declared' <> used
|
||||||
|
|
||||||
|
tags' =
|
||||||
|
case usedOrDeclaredFromOpts opts of
|
||||||
|
Nothing -> all'
|
||||||
|
Just Used -> used
|
||||||
|
Just Declared -> declared'
|
||||||
|
Just Undeclared -> undeclared
|
||||||
|
Just Unused -> unused
|
||||||
|
|
||||||
|
results =
|
||||||
(if parsed then id else nubSort)
|
(if parsed then id else nubSort)
|
||||||
[ r
|
[ r
|
||||||
| (t,v) <- concatMap (journalAccountTags j) matchedaccts ++ concatMap transactionAllTags matchedtxns
|
| (t,v) <- tags'
|
||||||
, maybe True (`regexMatchText` t) mtagpat
|
, maybe True (`regexMatchText` t) mtagpat
|
||||||
, let r = if values then v else t
|
, let r = if values then v else t
|
||||||
, not (values && T.null v && not empty)
|
, not (values && T.null v && not empty)
|
||||||
]
|
]
|
||||||
mapM_ T.putStrLn tagsorvalues
|
|
||||||
|
mapM_ T.putStrLn results
|
||||||
|
|||||||
@ -1,32 +1,39 @@
|
|||||||
## tags
|
## tags
|
||||||
|
|
||||||
List the tags used in the journal, or their values.
|
List the tag names used or declared in the journal, or their values.
|
||||||
<!-- same section name as Journal > Tags; if reordering this and that, update all #tags[-1] links -->
|
<!-- This section has the same name as Journal > Tags;
|
||||||
|
if reordering this and that, update all #tags[-1] links -->
|
||||||
|
|
||||||
```flags
|
```flags
|
||||||
Flags:
|
Flags:
|
||||||
|
--used list tags used
|
||||||
|
--declared list tags declared
|
||||||
|
--undeclared list tags used but not declared
|
||||||
|
--unused list tags declared but not used
|
||||||
--values list tag values instead of tag names
|
--values list tag values instead of tag names
|
||||||
--parsed show tags/values in the order they were parsed,
|
--parsed show them in the order they were parsed (mostly),
|
||||||
including duplicates
|
including duplicates
|
||||||
```
|
```
|
||||||
|
|
||||||
This command lists the tag names used in the journal,
|
This command lists tag names - all of them by default,
|
||||||
whether on transactions, postings, or account declarations.
|
or just the ones which have been used on transactions/postings/accounts,
|
||||||
|
or declared with `tag` directives,
|
||||||
|
or used but not declared,
|
||||||
|
or declared but not used.
|
||||||
|
|
||||||
With a TAGREGEX argument, only tag names matching this regular expression
|
You can add one TAGREGEX argument, to show only tags whose name is
|
||||||
(case insensitive, infix matched) are shown.
|
matched by this case-insensitive, infix-matching regular expression.
|
||||||
|
|
||||||
With QUERY arguments, only transactions and accounts matching this query are considered.
|
After that, you can add query arguments to filter the
|
||||||
If the query involves transaction fields (date:, desc:, amt:, ...),
|
transactions, postings, or accounts providing tags.
|
||||||
the search is restricted to the matched transactions and their accounts.
|
|
||||||
|
|
||||||
With the --values flag, the tags' unique non-empty values are listed instead.
|
With `--values`, the tags' unique non-empty values are listed instead.
|
||||||
With -E/--empty, blank/empty values are also shown.
|
|
||||||
|
|
||||||
With --parsed, tags or values are shown in the order they were parsed, with duplicates included.
|
With `-E`/`--empty`, blank/empty values are also shown.
|
||||||
|
|
||||||
|
With `--parsed`, tags or values are shown in the order they were parsed, with duplicates included.
|
||||||
(Except, tags from account declarations are always shown first.)
|
(Except, tags from account declarations are always shown first.)
|
||||||
|
|
||||||
Tip: remember,
|
Remember that accounts also acquire tags from their parents;
|
||||||
accounts also acquire tags from their parents,
|
postings also acquire tags from their account and transaction;
|
||||||
postings also acquire tags from their account and transaction,
|
and transactions also acquire tags from their postings.
|
||||||
transactions also acquire tags from their postings.
|
|
||||||
|
|||||||
73
hledger/test/commodities.test
Normal file
73
hledger/test/commodities.test
Normal file
@ -0,0 +1,73 @@
|
|||||||
|
# * commodities command
|
||||||
|
# "This command lists commodity symbols/names - all of them by default,
|
||||||
|
# or just the ones which have been used in transactions or `P` directives,
|
||||||
|
# or declared with `commodity` directives,
|
||||||
|
# or used but not declared,
|
||||||
|
# or declared but not used."
|
||||||
|
|
||||||
|
# ** 1. all commodities
|
||||||
|
<
|
||||||
|
commodity 1. CA
|
||||||
|
commodity 1. CB
|
||||||
|
commodity 1. CC
|
||||||
|
commodity 1. CD
|
||||||
|
commodity 1. CE
|
||||||
|
|
||||||
|
D 1. DH
|
||||||
|
|
||||||
|
P 2025-01-01 CA 1 CB
|
||||||
|
P 2025-01-01 PI 1 PJ
|
||||||
|
|
||||||
|
2025-01-01
|
||||||
|
a 1 CC @ 1 CD
|
||||||
|
b 1 TK @ 1 TL
|
||||||
|
d
|
||||||
|
|
||||||
|
$ hledger -f - commodities
|
||||||
|
CA
|
||||||
|
CB
|
||||||
|
CC
|
||||||
|
CD
|
||||||
|
CE
|
||||||
|
DH
|
||||||
|
PI
|
||||||
|
PJ
|
||||||
|
TK
|
||||||
|
TL
|
||||||
|
|
||||||
|
# ** 2. used
|
||||||
|
$ hledger -f - commodities --used
|
||||||
|
CA
|
||||||
|
CB
|
||||||
|
CC
|
||||||
|
CD
|
||||||
|
PI
|
||||||
|
PJ
|
||||||
|
TK
|
||||||
|
TL
|
||||||
|
|
||||||
|
# ** 3. declared
|
||||||
|
$ hledger -f - commodities --declared
|
||||||
|
CA
|
||||||
|
CB
|
||||||
|
CC
|
||||||
|
CD
|
||||||
|
CE
|
||||||
|
|
||||||
|
# ** 4. undeclared
|
||||||
|
$ hledger -f - commodities --undeclared
|
||||||
|
PI
|
||||||
|
PJ
|
||||||
|
TK
|
||||||
|
TL
|
||||||
|
|
||||||
|
# ** 5. unused
|
||||||
|
$ hledger -f - commodities --unused
|
||||||
|
CE
|
||||||
|
|
||||||
|
# ** 6. with a query
|
||||||
|
$ hledger -f - commodities --used expr:"cur:CA or cur:'P.*'"
|
||||||
|
CA
|
||||||
|
PI
|
||||||
|
PJ
|
||||||
|
|
||||||
@ -1,5 +1,19 @@
|
|||||||
# * tags command
|
# * tags command
|
||||||
|
|
||||||
|
# ** 1. show account tags even when there are no transactions (#1857)
|
||||||
|
<
|
||||||
|
account a ; t1:
|
||||||
|
|
||||||
|
$ hledger -f- tags
|
||||||
|
t1
|
||||||
|
|
||||||
|
# ** 2. show all tags
|
||||||
|
<
|
||||||
|
tag t1
|
||||||
|
tag t3
|
||||||
|
tag t4
|
||||||
|
tag t7
|
||||||
|
|
||||||
account a ; t1:v1, an account tag
|
account a ; t1:v1, an account tag
|
||||||
account b:bb ; t2:v2, an unused account, depth 2
|
account b:bb ; t2:v2, an unused account, depth 2
|
||||||
|
|
||||||
@ -9,7 +23,6 @@ account b:bb ; t2:v2, an unused account, depth 2
|
|||||||
2000/1/2 ; t5:v4, a reused value
|
2000/1/2 ; t5:v4, a reused value
|
||||||
(c) 1 ; t6:v6, an undeclared account
|
(c) 1 ; t6:v6, an undeclared account
|
||||||
|
|
||||||
# ** 1. show all tags
|
|
||||||
$ hledger -f- tags
|
$ hledger -f- tags
|
||||||
t1
|
t1
|
||||||
t2
|
t2
|
||||||
@ -17,8 +30,35 @@ t3
|
|||||||
t4
|
t4
|
||||||
t5
|
t5
|
||||||
t6
|
t6
|
||||||
|
t7
|
||||||
|
|
||||||
# ** 2. show all tag values
|
# ** . used
|
||||||
|
$ hledger -f- tags --used
|
||||||
|
t1
|
||||||
|
t2
|
||||||
|
t3
|
||||||
|
t4
|
||||||
|
t5
|
||||||
|
t6
|
||||||
|
|
||||||
|
# ** . declared
|
||||||
|
$ hledger -f- tags --declared
|
||||||
|
t1
|
||||||
|
t3
|
||||||
|
t4
|
||||||
|
t7
|
||||||
|
|
||||||
|
# ** . undeclared
|
||||||
|
$ hledger -f- tags --undeclared
|
||||||
|
t2
|
||||||
|
t5
|
||||||
|
t6
|
||||||
|
|
||||||
|
# ** . unused
|
||||||
|
$ hledger -f- tags --unused
|
||||||
|
t7
|
||||||
|
|
||||||
|
# ** . show (non empty) values
|
||||||
$ hledger -f- tags --values
|
$ hledger -f- tags --values
|
||||||
v1
|
v1
|
||||||
v2
|
v2
|
||||||
@ -26,14 +66,14 @@ v3
|
|||||||
v4
|
v4
|
||||||
v6
|
v6
|
||||||
|
|
||||||
# ** 3. show tags matching a regex
|
# ** . show tags matching a regex
|
||||||
$ hledger -f- tags '[1-4]'
|
$ hledger -f- tags '[1-4]'
|
||||||
t1
|
t1
|
||||||
t2
|
t2
|
||||||
t3
|
t3
|
||||||
t4
|
t4
|
||||||
|
|
||||||
# ** 4. show tags matching (a regex and) a hledger query.
|
# ** . show tags matching (a regex and) a hledger query.
|
||||||
# If the query is applicable to both transactions and account declarations,
|
# If the query is applicable to both transactions and account declarations,
|
||||||
# both are searched for tags.
|
# both are searched for tags.
|
||||||
$ hledger -f- tags . b c
|
$ hledger -f- tags . b c
|
||||||
@ -41,16 +81,10 @@ t2
|
|||||||
t5
|
t5
|
||||||
t6
|
t6
|
||||||
|
|
||||||
# ** 5. If the query involves transaction attributes,
|
# ** . If the query involves transaction attributes,
|
||||||
# only accounts used by the matched transactions will contribute tags.
|
# only the matched transactions and accounts they use will contribute tags.
|
||||||
$ hledger -f- tags . date:2000/1/1
|
$ hledger -f- tags . date:2000/1/1
|
||||||
t1
|
t1
|
||||||
t3
|
t3
|
||||||
t4
|
t4
|
||||||
|
|
||||||
# ** 6. show account tags even when there are no transactions (#1857)
|
|
||||||
<
|
|
||||||
account a ; t1:
|
|
||||||
|
|
||||||
$ hledger -f- tags
|
|
||||||
t1
|
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user