2016-05-20 02:29:39 +03:00
|
|
|
#!/usr/bin/env stack
|
|
|
|
{- stack runghc --verbosity info
|
|
|
|
--package hledger-lib
|
|
|
|
--package hledger
|
2017-01-23 17:17:17 +03:00
|
|
|
--package here
|
2016-05-20 02:29:39 +03:00
|
|
|
-}
|
|
|
|
|
2017-01-23 17:17:17 +03:00
|
|
|
{-# LANGUAGE QuasiQuotes #-}
|
|
|
|
|
|
|
|
import Data.String.Here
|
|
|
|
import Hledger
|
|
|
|
import Hledger.Cli
|
|
|
|
import Text.Printf
|
|
|
|
|
|
|
|
------------------------------------------------------------------------------
|
2017-01-24 19:59:22 +03:00
|
|
|
cmdmode =
|
|
|
|
let m = defAddonCommandMode "check-dates"
|
|
|
|
in m {
|
|
|
|
modeHelp = [here|
|
|
|
|
Check that transactions' dates are monotonically increasing.
|
|
|
|
With --date2, checks secondary dates instead.
|
2017-01-08 21:24:33 +03:00
|
|
|
With --strict, dates must also be unique.
|
2017-01-24 19:59:22 +03:00
|
|
|
With a query, only matched transactions' dates are checked.
|
2017-01-08 21:24:33 +03:00
|
|
|
Reads the default journal file, or another specified with -f.
|
2017-01-24 19:59:22 +03:00
|
|
|
|]
|
|
|
|
,modeHelpSuffix=lines [here|
|
|
|
|
|]
|
|
|
|
,modeGroupFlags = (modeGroupFlags m) {
|
|
|
|
groupUnnamed = [
|
2016-05-20 02:29:39 +03:00
|
|
|
flagNone ["strict"] (\opts -> setboolopt "strict" opts) "makes date comparing strict"
|
|
|
|
]
|
|
|
|
}
|
2017-01-24 19:59:22 +03:00
|
|
|
}
|
|
|
|
------------------------------------------------------------------------------
|
2014-11-03 09:37:57 +03:00
|
|
|
|
|
|
|
main :: IO ()
|
|
|
|
main = do
|
2017-01-24 19:59:22 +03:00
|
|
|
opts <- getHledgerCliOpts cmdmode
|
2016-05-20 02:29:39 +03:00
|
|
|
withJournalDo opts $
|
|
|
|
\CliOpts{rawopts_=opts,reportopts_=ropts} j -> do
|
|
|
|
d <- getCurrentDay
|
|
|
|
let ropts_ = ropts{accountlistmode_=ALFlat}
|
|
|
|
let q = queryFromOpts d ropts_
|
|
|
|
let ts = filter (q `matchesTransaction`) $
|
|
|
|
jtxns $ journalSelectingAmountFromOpts ropts j
|
|
|
|
let strict = boolopt "strict" opts
|
|
|
|
let date = transactionDateFn ropts
|
|
|
|
let compare a b =
|
|
|
|
if strict
|
|
|
|
then date a < date b
|
|
|
|
else date a <= date b
|
|
|
|
case checkTransactions compare ts of
|
|
|
|
FoldAcc{fa_previous=Nothing} -> putStrLn "ok (empty journal)"
|
|
|
|
FoldAcc{fa_error=Nothing} -> putStrLn "ok"
|
|
|
|
FoldAcc{fa_error=Just error, fa_previous=Just previous} ->
|
|
|
|
putStrLn $ printf ("ERROR: transaction out of%s date order"
|
|
|
|
++ "\nPrevious date: %s"
|
|
|
|
++ "\nDate: %s"
|
|
|
|
++ "\nLocation: %s"
|
|
|
|
++ "\nTransaction:\n\n%s")
|
|
|
|
(if strict then " STRICT" else "")
|
|
|
|
(show $ date previous)
|
|
|
|
(show $ date error)
|
|
|
|
(show $ tsourcepos error)
|
|
|
|
(showTransactionUnelided error)
|
2017-01-24 19:59:22 +03:00
|
|
|
|
|
|
|
data FoldAcc a b = FoldAcc
|
|
|
|
{ fa_error :: Maybe a
|
|
|
|
, fa_previous :: Maybe b
|
|
|
|
}
|
|
|
|
|
|
|
|
foldWhile :: (a -> FoldAcc a b -> FoldAcc a b) -> FoldAcc a b -> [a] -> FoldAcc a b
|
|
|
|
foldWhile _ acc [] = acc
|
|
|
|
foldWhile fold acc (a:as) =
|
|
|
|
case fold a acc of
|
|
|
|
acc@FoldAcc{fa_error=Just _} -> acc
|
|
|
|
acc -> foldWhile fold acc as
|
|
|
|
|
|
|
|
checkTransactions :: (Transaction -> Transaction -> Bool)
|
|
|
|
-> [Transaction] -> FoldAcc Transaction Transaction
|
|
|
|
checkTransactions compare ts =
|
|
|
|
foldWhile fold FoldAcc{fa_error=Nothing, fa_previous=Nothing} ts
|
|
|
|
where
|
|
|
|
fold current acc@FoldAcc{fa_previous=Nothing} = acc{fa_previous=Just current}
|
|
|
|
fold current acc@FoldAcc{fa_previous=Just previous} =
|
|
|
|
if compare previous current
|
|
|
|
then acc{fa_previous=Just current}
|
|
|
|
else acc{fa_error=Just current}
|
|
|
|
|