2017-01-09 20:40:51 +03:00
|
|
|
#!/usr/bin/env stack
|
|
|
|
{- stack runghc --verbosity info
|
|
|
|
--package hledger-lib
|
2017-01-23 17:17:17 +03:00
|
|
|
--package here
|
2017-01-09 20:40:51 +03:00
|
|
|
--package safe
|
|
|
|
--package text
|
|
|
|
-}
|
|
|
|
|
2017-01-23 17:17:17 +03:00
|
|
|
{-# LANGUAGE QuasiQuotes #-}
|
2017-01-09 20:40:51 +03:00
|
|
|
|
|
|
|
import Hledger
|
2017-01-23 17:17:17 +03:00
|
|
|
import Hledger.Cli
|
2017-01-09 20:40:51 +03:00
|
|
|
import Text.Printf (printf)
|
|
|
|
import System.Environment (getArgs)
|
|
|
|
import Safe (headDef)
|
|
|
|
import Data.List
|
|
|
|
import Data.Function
|
2017-01-23 17:17:17 +03:00
|
|
|
import Data.String.Here
|
2017-01-09 20:40:51 +03:00
|
|
|
import qualified Data.Text as T
|
|
|
|
|
2017-01-24 19:59:22 +03:00
|
|
|
------------------------------------------------------------------------------
|
2017-01-26 04:10:10 +03:00
|
|
|
cmdmode = hledgerCommandMode
|
|
|
|
[here| dupes
|
2017-01-23 17:17:17 +03:00
|
|
|
Reports duplicates in the account tree: account names having the same leaf
|
|
|
|
but different prefixes. In other words, two or more leaves that are
|
|
|
|
categorized differently.
|
|
|
|
Reads the default journal file, or another specified as an argument.
|
2017-01-24 19:59:22 +03:00
|
|
|
|
2017-01-23 17:17:17 +03:00
|
|
|
http://stefanorodighiero.net/software/hledger-dupes.html
|
2017-01-24 19:59:22 +03:00
|
|
|
|]
|
2017-01-26 04:10:10 +03:00
|
|
|
[]
|
|
|
|
[generalflagsgroup1]
|
|
|
|
[]
|
|
|
|
([], Nothing)
|
2017-01-24 19:59:22 +03:00
|
|
|
------------------------------------------------------------------------------
|
2017-01-23 17:17:17 +03:00
|
|
|
|
2017-01-24 19:59:22 +03:00
|
|
|
main = do
|
|
|
|
opts <- getHledgerCliOpts cmdmode
|
|
|
|
withJournalDo opts $ \CliOpts{rawopts_=opts,reportopts_=ropts} j -> do
|
|
|
|
mapM_ render $ dupes $ accountsNames j
|
2017-01-23 17:17:17 +03:00
|
|
|
|
2017-01-09 20:40:51 +03:00
|
|
|
accountsNames :: Journal -> [(String, AccountName)]
|
|
|
|
accountsNames j = map leafAndAccountName as
|
|
|
|
where leafAndAccountName a = (T.unpack $ accountLeafName a, a)
|
|
|
|
ps = journalPostings j
|
|
|
|
as = nub $ sort $ map paccount ps
|
|
|
|
|
|
|
|
|
|
|
|
dupes :: (Ord k, Eq k) => [(k, v)] -> [(k, [v])]
|
|
|
|
dupes l = zip dupLeafs dupAccountNames
|
|
|
|
where dupLeafs = map (fst . head) d
|
|
|
|
dupAccountNames = map (map snd) d
|
|
|
|
d = dupes' l
|
|
|
|
dupes' = filter ((> 1) . length)
|
|
|
|
. groupBy ((==) `on` fst)
|
|
|
|
. sortBy (compare `on` fst)
|
|
|
|
|
|
|
|
render :: (String, [AccountName]) -> IO ()
|
|
|
|
render (leafName, accountNameL) = printf "%s as %s\n" leafName (concat $ intersperse ", " (map T.unpack accountNameL))
|