    {-|

    The @payees@ command lists all unique payees (description part before a |) seen in transactions, sorted alphabetically.

    -}

    {-# LANGUAGE MultiWayIf          #-}
    {-# LANGUAGE OverloadedStrings   #-}
    {-# LANGUAGE ScopedTypeVariables #-}
    {-# LANGUAGE TemplateHaskell     #-}

    module Hledger.Cli.Commands.Payees (
      payeesmode
     ,payees
    ) where

    import Data.Text.IO qualified as T
    import System.Console.CmdArgs.Explicit

    import Hledger
    import Hledger.Cli.CliOptions
    import Data.List ((\\))
    import Data.List.Extra (nubSort)

    -- | Command line options for this command.
    payeesmode :: Mode RawOpts
    payeesmode = CommandHelpStr
    -> [Flag RawOpts]
    -> [(CommandHelpStr, [Flag RawOpts])]
    -> [Flag RawOpts]
    -> ([Arg RawOpts], Maybe (Arg RawOpts))
    -> Mode RawOpts
    hledgerCommandMode
      $(embedFileRelative "Hledger/Cli/Commands/Payees.txt")
      [[CommandHelpStr]
    -> (RawOpts -> RawOpts) -> CommandHelpStr -> Flag RawOpts
    forall a. [CommandHelpStr] -> (a -> a) -> CommandHelpStr -> Flag a
    flagNone [CommandHelpStr
    "used"]         (CommandHelpStr -> RawOpts -> RawOpts
    setboolopt CommandHelpStr
    "used")       CommandHelpStr
    "list payees used"
      ,[CommandHelpStr]
    -> (RawOpts -> RawOpts) -> CommandHelpStr -> Flag RawOpts
    forall a. [CommandHelpStr] -> (a -> a) -> CommandHelpStr -> Flag a
    flagNone [CommandHelpStr
    "declared"]     (CommandHelpStr -> RawOpts -> RawOpts
    setboolopt CommandHelpStr
    "declared")   CommandHelpStr
    "list payees declared"
      ,[CommandHelpStr]
    -> (RawOpts -> RawOpts) -> CommandHelpStr -> Flag RawOpts
    forall a. [CommandHelpStr] -> (a -> a) -> CommandHelpStr -> Flag a
    flagNone [CommandHelpStr
    "undeclared"]   (CommandHelpStr -> RawOpts -> RawOpts
    setboolopt CommandHelpStr
    "undeclared") CommandHelpStr
    "list payees used but not declared"
      ,[CommandHelpStr]
    -> (RawOpts -> RawOpts) -> CommandHelpStr -> Flag RawOpts
    forall a. [CommandHelpStr] -> (a -> a) -> CommandHelpStr -> Flag a
    flagNone [CommandHelpStr
    "unused"]       (CommandHelpStr -> RawOpts -> RawOpts
    setboolopt CommandHelpStr
    "unused")     CommandHelpStr
    "list payees declared but not used"
      ,[CommandHelpStr]
    -> (RawOpts -> RawOpts) -> CommandHelpStr -> Flag RawOpts
    forall a. [CommandHelpStr] -> (a -> a) -> CommandHelpStr -> Flag a
    flagNone [CommandHelpStr
    "find"]         (CommandHelpStr -> RawOpts -> RawOpts
    setboolopt CommandHelpStr
    "find")       CommandHelpStr
    "list the first payee matched by the first argument (a case-insensitive infix regexp)"
      ]
      [(CommandHelpStr, [Flag RawOpts])]
    cligeneralflagsgroups1
      [Flag RawOpts]
    hiddenflags
      ([], Arg RawOpts -> Maybe (Arg RawOpts)
    forall a. a -> Maybe a
    Just (Arg RawOpts -> Maybe (Arg RawOpts))
    -> Arg RawOpts -> Maybe (Arg RawOpts)
    forall a b. (a -> b) -> a -> b
    $ CommandHelpStr -> Arg RawOpts
    argsFlag CommandHelpStr
    "[QUERY..]")

    -- | The payees command.
    payees :: CliOpts -> Journal -> IO ()
    payees :: CliOpts -> Journal -> IO ()
    payees opts :: CliOpts
    opts@CliOpts{rawopts_ :: CliOpts -> RawOpts
    rawopts_=RawOpts
    rawopts, reportspec_ :: CliOpts -> ReportSpec
    reportspec_=ReportSpec{_rsQuery :: ReportSpec -> Query
    _rsQuery=Query
    query}} Journal
    j = do
      let
        -- XXX matchesPayeeWIP is currently an alias for matchesDescription, not sure if it matters
        matchedused :: [Text]
    matchedused       = CommandHelpStr -> [Text] -> [Text]
    forall a. Show a => CommandHelpStr -> a -> a
    dbg5 CommandHelpStr
    "matchedused"       ([Text] -> [Text]) -> [Text] -> [Text]
    forall a b. (a -> b) -> a -> b
    $ [Text] -> [Text]
    forall a. Ord a => [a] -> [a]
    nubSort ([Text] -> [Text]) -> [Text] -> [Text]
    forall a b. (a -> b) -> a -> b
    $ (Transaction -> Text) -> [Transaction] -> [Text]
    forall a b. (a -> b) -> [a] -> [b]
    map Transaction -> Text
    transactionPayee ([Transaction] -> [Text]) -> [Transaction] -> [Text]
    forall a b. (a -> b) -> a -> b
    $ (Transaction -> Bool) -> [Transaction] -> [Transaction]
    forall a. (a -> Bool) -> [a] -> [a]
    filter (Query -> Transaction -> Bool
    matchesTransaction Query
    query) ([Transaction] -> [Transaction]) -> [Transaction] -> [Transaction]
    forall a b. (a -> b) -> a -> b
    $ Journal -> [Transaction]
    jtxns Journal
    j
        matcheddeclared :: [Text]
    matcheddeclared   = CommandHelpStr -> [Text] -> [Text]
    forall a. Show a => CommandHelpStr -> a -> a
    dbg5 CommandHelpStr
    "matcheddeclared"   ([Text] -> [Text]) -> [Text] -> [Text]
    forall a b. (a -> b) -> a -> b
    $ [Text] -> [Text]
    forall a. Ord a => [a] -> [a]
    nubSort ([Text] -> [Text]) -> [Text] -> [Text]
    forall a b. (a -> b) -> a -> b
    $ (Text -> Bool) -> [Text] -> [Text]
    forall a. (a -> Bool) -> [a] -> [a]
    filter (Query -> Text -> Bool
    matchesPayeeWIP Query
    query) ([Text] -> [Text]) -> [Text] -> [Text]
    forall a b. (a -> b) -> a -> b
    $ Journal -> [Text]
    journalPayeesDeclared Journal
    j
        matchedunused :: [Text]
    matchedunused     = CommandHelpStr -> [Text] -> [Text]
    forall a. Show a => CommandHelpStr -> a -> a
    dbg5 CommandHelpStr
    "matchedunused"     ([Text] -> [Text]) -> [Text] -> [Text]
    forall a b. (a -> b) -> a -> b
    $ [Text] -> [Text]
    forall a. Ord a => [a] -> [a]
    nubSort ([Text] -> [Text]) -> [Text] -> [Text]
    forall a b. (a -> b) -> a -> b
    $ [Text]
    matcheddeclared [Text] -> [Text] -> [Text]
    forall a. Eq a => [a] -> [a] -> [a]
    \\ [Text]
    matchedused
        matchedundeclared :: [Text]
    matchedundeclared = CommandHelpStr -> [Text] -> [Text]
    forall a. Show a => CommandHelpStr -> a -> a
    dbg5 CommandHelpStr
    "matchedundeclared" ([Text] -> [Text]) -> [Text] -> [Text]
    forall a b. (a -> b) -> a -> b
    $ [Text] -> [Text]
    forall a. Ord a => [a] -> [a]
    nubSort ([Text] -> [Text]) -> [Text] -> [Text]
    forall a b. (a -> b) -> a -> b
    $ [Text]
    matchedused     [Text] -> [Text] -> [Text]
    forall a. Eq a => [a] -> [a] -> [a]
    \\ [Text]
    matcheddeclared
        matchedall :: [Text]
    matchedall        = CommandHelpStr -> [Text] -> [Text]
    forall a. Show a => CommandHelpStr -> a -> a
    dbg5 CommandHelpStr
    "matchedall"        ([Text] -> [Text]) -> [Text] -> [Text]
    forall a b. (a -> b) -> a -> b
    $ [Text] -> [Text]
    forall a. Ord a => [a] -> [a]
    nubSort ([Text] -> [Text]) -> [Text] -> [Text]
    forall a b. (a -> b) -> a -> b
    $ [Text]
    matcheddeclared [Text] -> [Text] -> [Text]
    forall a. [a] -> [a] -> [a]
    ++ [Text]
    matchedused
        found :: Text
    found             = CommandHelpStr -> Text -> Text
    forall a. Show a => CommandHelpStr -> a -> a
    dbg5 CommandHelpStr
    "found"             (Text -> Text) -> Text -> Text
    forall a b. (a -> b) -> a -> b
    $ RawOpts -> CommandHelpStr -> [Text] -> Text
    findMatchedByArgument RawOpts
    rawopts CommandHelpStr
    "payee" [Text]
    all'
          where all' :: [Text]
    all' = [Text] -> [Text]
    forall a. Ord a => [a] -> [a]
    nubSort ([Text] -> [Text]) -> [Text] -> [Text]
    forall a b. (a -> b) -> a -> b
    $ (Transaction -> Text) -> [Transaction] -> [Text]
    forall a b. (a -> b) -> [a] -> [b]
    map Transaction -> Text
    transactionPayee (Journal -> [Transaction]
    jtxns Journal
    j) [Text] -> [Text] -> [Text]
    forall a. Semigroup a => a -> a -> a
    <> Journal -> [Text]
    journalPayeesDeclared Journal
    j
      (Text -> IO ()) -> [Text] -> IO ()
    forall (t :: * -> *) (m :: * -> *) a b.
    (Foldable t, Monad m) =>
    (a -> m b) -> t a -> m ()
    mapM_ Text -> IO ()
    T.putStrLn ([Text] -> IO ()) -> [Text] -> IO ()
    forall a b. (a -> b) -> a -> b
    $ case CliOpts -> Maybe DeclarablesSelector
    declarablesSelectorFromOpts CliOpts
    opts of
        Maybe DeclarablesSelector
    Nothing         -> [Text]
    matchedall
        Just DeclarablesSelector
    Used       -> [Text]
    matchedused
        Just DeclarablesSelector
    Declared   -> [Text]
    matcheddeclared
        Just DeclarablesSelector
    Undeclared -> [Text]
    matchedundeclared
        Just DeclarablesSelector
    Unused     -> [Text]
    matchedunused
        Just DeclarablesSelector
    Find       -> [Text
    found]