{-# LANGUAGE CPP #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE QuasiQuotes #-}
{-# LANGUAGE TemplateHaskell #-}
module Hledger.Cli.Commands (
findCommand
,testcmd
,builtinCommands
,builtinCommandNames
,printCommandsList
,tests_Hledger_Cli
,module Hledger.Cli.Commands.Accounts
,module Hledger.Cli.Commands.Activity
,module Hledger.Cli.Commands.Add
,module Hledger.Cli.Commands.Balance
,module Hledger.Cli.Commands.Balancesheet
,module Hledger.Cli.Commands.Balancesheetequity
,module Hledger.Cli.Commands.Cashflow
,module Hledger.Cli.Commands.Checkdates
,module Hledger.Cli.Commands.Checkdupes
,module Hledger.Cli.Commands.Close
,module Hledger.Cli.Commands.Commodities
,module Hledger.Cli.Commands.Descriptions
,module Hledger.Cli.Commands.Diff
,module Hledger.Cli.Commands.Help
,module Hledger.Cli.Commands.Import
,module Hledger.Cli.Commands.Incomestatement
,module Hledger.Cli.Commands.Notes
,module Hledger.Cli.Commands.Payees
,module Hledger.Cli.Commands.Prices
,module Hledger.Cli.Commands.Print
,module Hledger.Cli.Commands.Printunique
,module Hledger.Cli.Commands.Register
,module Hledger.Cli.Commands.Registermatch
,module Hledger.Cli.Commands.Rewrite
,module Hledger.Cli.Commands.Stats
,module Hledger.Cli.Commands.Tags
)
where
import Data.Char (isSpace)
import Data.Default
import Data.List
#if !(MIN_VERSION_base(4,11,0))
import Data.Monoid ((<>))
#endif
import Data.Text (Text)
import qualified Data.Text as T
import Data.Time.Calendar
import System.Environment (withArgs)
import System.Console.CmdArgs.Explicit as C
import Test.Tasty (defaultMain)
import Hledger
import Hledger.Cli.CliOptions
import Hledger.Cli.Version
import Hledger.Cli.Commands.Accounts
import Hledger.Cli.Commands.Activity
import Hledger.Cli.Commands.Add
import Hledger.Cli.Commands.Balance
import Hledger.Cli.Commands.Balancesheet
import Hledger.Cli.Commands.Balancesheetequity
import Hledger.Cli.Commands.Cashflow
import Hledger.Cli.Commands.Checkdates
import Hledger.Cli.Commands.Checkdupes
import Hledger.Cli.Commands.Close
import Hledger.Cli.Commands.Commodities
import Hledger.Cli.Commands.Descriptions
import Hledger.Cli.Commands.Diff
import Hledger.Cli.Commands.Files
import Hledger.Cli.Commands.Help
import Hledger.Cli.Commands.Import
import Hledger.Cli.Commands.Incomestatement
import Hledger.Cli.Commands.Notes
import Hledger.Cli.Commands.Payees
import Hledger.Cli.Commands.Prices
import Hledger.Cli.Commands.Print
import Hledger.Cli.Commands.Printunique
import Hledger.Cli.Commands.Register
import Hledger.Cli.Commands.Registermatch
import Hledger.Cli.Commands.Rewrite
import Hledger.Cli.Commands.Roi
import Hledger.Cli.Commands.Stats
import Hledger.Cli.Commands.Tags
import Hledger.Cli.Utils (tests_Cli_Utils)
builtinCommands :: [(Mode RawOpts, CliOpts -> Journal -> IO ())]
builtinCommands :: [(Mode RawOpts, CliOpts -> Journal -> IO ())]
builtinCommands = [
(Mode RawOpts
accountsmode , CliOpts -> Journal -> IO ()
accounts)
,(Mode RawOpts
activitymode , CliOpts -> Journal -> IO ()
activity)
,(Mode RawOpts
addmode , CliOpts -> Journal -> IO ()
add)
,(Mode RawOpts
balancemode , CliOpts -> Journal -> IO ()
balance)
,(Mode RawOpts
balancesheetequitymode , CliOpts -> Journal -> IO ()
balancesheetequity)
,(Mode RawOpts
balancesheetmode , CliOpts -> Journal -> IO ()
balancesheet)
,(Mode RawOpts
cashflowmode , CliOpts -> Journal -> IO ()
cashflow)
,(Mode RawOpts
checkdatesmode , CliOpts -> Journal -> IO ()
checkdates)
,(Mode RawOpts
checkdupesmode , CliOpts -> Journal -> IO ()
forall p. p -> Journal -> IO ()
checkdupes)
,(Mode RawOpts
closemode , CliOpts -> Journal -> IO ()
close)
,(Mode RawOpts
commoditiesmode , CliOpts -> Journal -> IO ()
commodities)
,(Mode RawOpts
descriptionsmode , CliOpts -> Journal -> IO ()
descriptions)
,(Mode RawOpts
diffmode , CliOpts -> Journal -> IO ()
diff)
,(Mode RawOpts
filesmode , CliOpts -> Journal -> IO ()
files)
,(Mode RawOpts
helpmode , CliOpts -> Journal -> IO ()
help')
,(Mode RawOpts
importmode , CliOpts -> Journal -> IO ()
importcmd)
,(Mode RawOpts
incomestatementmode , CliOpts -> Journal -> IO ()
incomestatement)
,(Mode RawOpts
notesmode , CliOpts -> Journal -> IO ()
notes)
,(Mode RawOpts
payeesmode , CliOpts -> Journal -> IO ()
payees)
,(Mode RawOpts
pricesmode , CliOpts -> Journal -> IO ()
prices)
,(Mode RawOpts
printmode , CliOpts -> Journal -> IO ()
print')
,(Mode RawOpts
printuniquemode , CliOpts -> Journal -> IO ()
printunique)
,(Mode RawOpts
registermatchmode , CliOpts -> Journal -> IO ()
registermatch)
,(Mode RawOpts
registermode , CliOpts -> Journal -> IO ()
register)
,(Mode RawOpts
rewritemode , CliOpts -> Journal -> IO ()
rewrite)
,(Mode RawOpts
roimode , CliOpts -> Journal -> IO ()
roi)
,(Mode RawOpts
statsmode , CliOpts -> Journal -> IO ()
stats)
,(Mode RawOpts
tagsmode , CliOpts -> Journal -> IO ()
tags)
,(Mode RawOpts
testmode , CliOpts -> Journal -> IO ()
testcmd)
]
commandsList :: String
commandsList :: String
commandsList = [String] -> String
unlines [
"-------------------------------------------------------------------------------"
,"PROGVERSION"
,"Usage: hledger COMMAND [OPTIONS] [-- ADDONCMDOPTIONS]"
,"Commands (+ addons found in $PATH):"
,""
,"Data entry (these commands modify the journal file):"
," add add transactions using guided prompts"
,"+iadd add transactions using curses ui"
," import add any new transactions from other files (eg csv)"
,""
,"Data management:"
,"+autosync download/deduplicate/convert OFX data"
,"+check check more powerful balance assertions"
," check-dates check transactions are ordered by date"
," check-dupes check for accounts with the same leaf name"
," close (equity) generate balance-resetting transactions"
," diff compare account transactions in two journal files"
,"+interest generate interest transactions"
," rewrite generate automated postings/diffs (old, use --auto)"
,""
,"Financial reports:"
," balancesheet (bs) show assets, liabilities and net worth"
," balancesheetequity (bse) show assets, liabilities and equity"
," cashflow (cf) show changes in liquid assets"
," incomestatement (is) show revenues and expenses"
,"+irr calculate internal rate of return (old, use roi)"
," roi show return on investments"
,""
,"Low-level reports:"
," accounts (a) show account names"
," activity show postings-per-interval bar charts"
," balance (b, bal) show balance changes/end balances/budgets in accounts"
," commodities show commodity/currency symbols"
," descriptions show unique transaction descriptions"
," files show input file paths"
," notes show unique note segments of transaction descriptions"
," payees show unique payee segments of transaction descriptions"
," prices show market price records"
," print (p, txns) show transactions (journal entries)"
," print-unique show only transactions with unique descriptions"
," register (r, reg) show postings in one or more accounts & running total"
," register-match show a recent posting that best matches a description"
," stats show journal statistics"
," tags show tag names"
," test run self tests"
,""
,"Alternate user interfaces:"
,"+ui run curses ui"
,"+web run web ui"
,"+api run http api server"
,""
,"Other:"
,"OTHER"
,"Help:"
," (no arguments) show this commands list"
," -h show general flags"
," COMMAND -h show flags & docs for COMMAND"
," help [MANUAL] show hledger manuals in various formats"
,""
]
builtinCommandNames :: [String]
builtinCommandNames :: [String]
builtinCommandNames = ((Mode RawOpts, CliOpts -> Journal -> IO ()) -> [String])
-> [(Mode RawOpts, CliOpts -> Journal -> IO ())] -> [String]
forall (t :: * -> *) a b. Foldable t => (a -> [b]) -> t a -> [b]
concatMap (Mode RawOpts -> [String]
forall a. Mode a -> [String]
modeNames (Mode RawOpts -> [String])
-> ((Mode RawOpts, CliOpts -> Journal -> IO ()) -> Mode RawOpts)
-> (Mode RawOpts, CliOpts -> Journal -> IO ())
-> [String]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Mode RawOpts, CliOpts -> Journal -> IO ()) -> Mode RawOpts
forall a b. (a, b) -> a
fst) [(Mode RawOpts, CliOpts -> Journal -> IO ())]
builtinCommands
findCommand :: String -> Maybe (Mode RawOpts, CliOpts -> Journal -> IO ())
findCommand :: String -> Maybe (Mode RawOpts, CliOpts -> Journal -> IO ())
findCommand cmdname :: String
cmdname = ((Mode RawOpts, CliOpts -> Journal -> IO ()) -> Bool)
-> [(Mode RawOpts, CliOpts -> Journal -> IO ())]
-> Maybe (Mode RawOpts, CliOpts -> Journal -> IO ())
forall (t :: * -> *) a. Foldable t => (a -> Bool) -> t a -> Maybe a
find (String -> [String] -> Bool
forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
elem String
cmdname ([String] -> Bool)
-> ((Mode RawOpts, CliOpts -> Journal -> IO ()) -> [String])
-> (Mode RawOpts, CliOpts -> Journal -> IO ())
-> Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Mode RawOpts -> [String]
forall a. Mode a -> [String]
modeNames (Mode RawOpts -> [String])
-> ((Mode RawOpts, CliOpts -> Journal -> IO ()) -> Mode RawOpts)
-> (Mode RawOpts, CliOpts -> Journal -> IO ())
-> [String]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Mode RawOpts, CliOpts -> Journal -> IO ()) -> Mode RawOpts
forall a b. (a, b) -> a
fst) [(Mode RawOpts, CliOpts -> Journal -> IO ())]
builtinCommands
commandsFromCommandsList :: String -> [String]
commandsFromCommandsList :: String -> [String]
commandsFromCommandsList s :: String
s =
[String
w | c :: Char
c:l :: String
l <- String -> [String]
lines String
s, Char
c Char -> String -> Bool
forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
`elem` [' ','+'], let w :: String
w:_ = String -> [String]
words String
l]
knownCommands :: [String]
knownCommands :: [String]
knownCommands = [String] -> [String]
forall a. Ord a => [a] -> [a]
sort ([String] -> [String]) -> [String] -> [String]
forall a b. (a -> b) -> a -> b
$ String -> [String]
commandsFromCommandsList String
commandsList
printCommandsList :: [String] -> IO ()
printCommandsList :: [String] -> IO ()
printCommandsList addonsFound :: [String]
addonsFound =
String -> IO ()
putStr (String -> IO ()) -> String -> IO ()
forall a b. (a -> b) -> a -> b
$
String -> String -> String -> String
regexReplace "PROGVERSION" (String
prognameandversion) (String -> String) -> String -> String
forall a b. (a -> b) -> a -> b
$
String -> String -> String -> String
regexReplace "OTHER" ([String] -> String
unlines ([String] -> String) -> [String] -> String
forall a b. (a -> b) -> a -> b
$ ((String -> String) -> [String] -> [String]
forall a b. (a -> b) -> [a] -> [b]
map ('+'Char -> String -> String
forall a. a -> [a] -> [a]
:) [String]
unknownCommandsFound)) (String -> String) -> String -> String
forall a b. (a -> b) -> a -> b
$
[String] -> String
unlines ([String] -> String) -> [String] -> String
forall a b. (a -> b) -> a -> b
$ (String -> [String]) -> [String] -> [String]
forall (t :: * -> *) a b. Foldable t => (a -> [b]) -> t a -> [b]
concatMap String -> [String]
adjustline ([String] -> [String]) -> [String] -> [String]
forall a b. (a -> b) -> a -> b
$ String -> [String]
lines (String -> [String]) -> String -> [String]
forall a b. (a -> b) -> a -> b
$
String
cmdlist
where
cmdlist :: String
cmdlist = String
commandsList
commandsFound :: [String]
commandsFound = (String -> String) -> [String] -> [String]
forall a b. (a -> b) -> [a] -> [b]
map (' 'Char -> String -> String
forall a. a -> [a] -> [a]
:) [String]
builtinCommandNames [String] -> [String] -> [String]
forall a. [a] -> [a] -> [a]
++ (String -> String) -> [String] -> [String]
forall a b. (a -> b) -> [a] -> [b]
map ('+'Char -> String -> String
forall a. a -> [a] -> [a]
:) [String]
addonsFound
unknownCommandsFound :: [String]
unknownCommandsFound = [String]
addonsFound [String] -> [String] -> [String]
forall a. Eq a => [a] -> [a] -> [a]
\\ [String]
knownCommands
adjustline :: String -> [String]
adjustline l :: String
l | " hledger " String -> String -> Bool
forall a. Eq a => [a] -> [a] -> Bool
`isPrefixOf` String
l = [String
l]
adjustline l :: String
l@('+':_) | String
cmd String -> [String] -> Bool
forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
`notElem` [String]
commandsFound = []
where
cmd :: String
cmd = (Char -> Bool) -> String -> String
forall a. (a -> Bool) -> [a] -> [a]
takeWhile (Bool -> Bool
not (Bool -> Bool) -> (Char -> Bool) -> Char -> Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Char -> Bool
isSpace) String
l
adjustline l :: String
l = [String
l]
testmode :: Mode RawOpts
testmode = String
-> [Flag RawOpts]
-> [(String, [Flag RawOpts])]
-> [Flag RawOpts]
-> ([Arg RawOpts], Maybe (Arg RawOpts))
-> Mode RawOpts
hledgerCommandMode
$(embedFileRelative "Hledger/Cli/Commands/Test.txt")
[]
[(String, [Flag RawOpts])
generalflagsgroup3]
[]
([], 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
$ String -> Arg RawOpts
argsFlag "[-- TASTYOPTS]")
testcmd :: CliOpts -> Journal -> IO ()
testcmd :: CliOpts -> Journal -> IO ()
testcmd opts :: CliOpts
opts _undefined :: Journal
_undefined = do
[String] -> IO () -> IO ()
forall a. [String] -> IO a -> IO a
withArgs (String -> [String]
words' (String -> [String]) -> String -> [String]
forall a b. (a -> b) -> a -> b
$ ReportOpts -> String
query_ (ReportOpts -> String) -> ReportOpts -> String
forall a b. (a -> b) -> a -> b
$ CliOpts -> ReportOpts
reportopts_ CliOpts
opts) (IO () -> IO ()) -> IO () -> IO ()
forall a b. (a -> b) -> a -> b
$
TestTree -> IO ()
Test.Tasty.defaultMain (TestTree -> IO ()) -> TestTree -> IO ()
forall a b. (a -> b) -> a -> b
$ String -> [TestTree] -> TestTree
tests "hledger" [
TestTree
tests_Hledger
,TestTree
tests_Hledger_Cli
]
tests_Hledger_Cli :: TestTree
tests_Hledger_Cli = String -> [TestTree] -> TestTree
tests "Hledger.Cli" [
TestTree
tests_Cli_Utils
,TestTree
tests_Commands
]
tests_Commands :: TestTree
tests_Commands = String -> [TestTree] -> TestTree
tests "Commands" [
TestTree
tests_Balance
,TestTree
tests_Register
,String -> [TestTree] -> TestTree
tests "apply account directive" [
String -> IO () -> TestTree
test "works" (IO () -> TestTree) -> IO () -> TestTree
forall a b. (a -> b) -> a -> b
$ do
let
ignoresourcepos :: Journal -> Journal
ignoresourcepos j :: Journal
j = Journal
j{jtxns :: [Transaction]
jtxns=(Transaction -> Transaction) -> [Transaction] -> [Transaction]
forall a b. (a -> b) -> [a] -> [b]
map (\t :: Transaction
t -> Transaction
t{tsourcepos :: GenericSourcePos
tsourcepos=GenericSourcePos
nullsourcepos}) (Journal -> [Transaction]
jtxns Journal
j)}
sameParse :: Text -> Text -> IO ()
sameParse str1 :: Text
str1 str2 :: Text
str2 = do
Journal
j1 <- InputOpts -> Maybe String -> Text -> IO (Either String Journal)
readJournal InputOpts
forall a. Default a => a
def Maybe String
forall a. Maybe a
Nothing Text
str1 IO (Either String Journal)
-> (Either String Journal -> IO Journal) -> IO Journal
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= (String -> IO Journal)
-> (Journal -> IO Journal) -> Either String Journal -> IO Journal
forall a c b. (a -> c) -> (b -> c) -> Either a b -> c
either String -> IO Journal
forall a. String -> a
error' (Journal -> IO Journal
forall (m :: * -> *) a. Monad m => a -> m a
return (Journal -> IO Journal)
-> (Journal -> Journal) -> Journal -> IO Journal
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Journal -> Journal
ignoresourcepos)
Journal
j2 <- InputOpts -> Maybe String -> Text -> IO (Either String Journal)
readJournal InputOpts
forall a. Default a => a
def Maybe String
forall a. Maybe a
Nothing Text
str2 IO (Either String Journal)
-> (Either String Journal -> IO Journal) -> IO Journal
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= (String -> IO Journal)
-> (Journal -> IO Journal) -> Either String Journal -> IO Journal
forall a c b. (a -> c) -> (b -> c) -> Either a b -> c
either String -> IO Journal
forall a. String -> a
error' (Journal -> IO Journal
forall (m :: * -> *) a. Monad m => a -> m a
return (Journal -> IO Journal)
-> (Journal -> Journal) -> Journal -> IO Journal
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Journal -> Journal
ignoresourcepos)
Journal
j1 Journal -> Journal -> IO ()
forall a. (Eq a, Show a, HasCallStack) => a -> a -> IO ()
@?= Journal
j2{jlastreadtime :: ClockTime
jlastreadtime=Journal -> ClockTime
jlastreadtime Journal
j1, jfiles :: [(String, Text)]
jfiles=Journal -> [(String, Text)]
jfiles Journal
j1}
Text -> Text -> IO ()
sameParse
("2008/12/07 One\n alpha $-1\n beta $1\n" Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<>
"apply account outer\n2008/12/07 Two\n aigh $-2\n bee $2\n" Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<>
"apply account inner\n2008/12/07 Three\n gamma $-3\n delta $3\n" Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<>
"end apply account\n2008/12/07 Four\n why $-4\n zed $4\n" Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<>
"end apply account\n2008/12/07 Five\n foo $-5\n bar $5\n"
)
("2008/12/07 One\n alpha $-1\n beta $1\n" Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<>
"2008/12/07 Two\n outer:aigh $-2\n outer:bee $2\n" Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<>
"2008/12/07 Three\n outer:inner:gamma $-3\n outer:inner:delta $3\n" Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<>
"2008/12/07 Four\n outer:why $-4\n outer:zed $4\n" Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<>
"2008/12/07 Five\n foo $-5\n bar $5\n"
)
,String -> IO () -> TestTree
test "preserves \"virtual\" posting type" (IO () -> TestTree) -> IO () -> TestTree
forall a b. (a -> b) -> a -> b
$ do
Journal
j <- InputOpts -> Maybe String -> Text -> IO (Either String Journal)
readJournal InputOpts
forall a. Default a => a
def Maybe String
forall a. Maybe a
Nothing "apply account test\n2008/12/07 One\n (from) $-1\n (to) $1\n" IO (Either String Journal)
-> (Either String Journal -> IO Journal) -> IO Journal
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= (String -> IO Journal)
-> (Journal -> IO Journal) -> Either String Journal -> IO Journal
forall a c b. (a -> c) -> (b -> c) -> Either a b -> c
either String -> IO Journal
forall a. String -> a
error' Journal -> IO Journal
forall (m :: * -> *) a. Monad m => a -> m a
return
let p :: Posting
p = [Posting] -> Posting
forall a. [a] -> a
head ([Posting] -> Posting) -> [Posting] -> Posting
forall a b. (a -> b) -> a -> b
$ Transaction -> [Posting]
tpostings (Transaction -> [Posting]) -> Transaction -> [Posting]
forall a b. (a -> b) -> a -> b
$ [Transaction] -> Transaction
forall a. [a] -> a
head ([Transaction] -> Transaction) -> [Transaction] -> Transaction
forall a b. (a -> b) -> a -> b
$ Journal -> [Transaction]
jtxns Journal
j
Posting -> Text
paccount Posting
p Text -> Text -> IO ()
forall a. (Eq a, Show a, HasCallStack) => a -> a -> IO ()
@?= "test:from"
Posting -> PostingType
ptype Posting
p PostingType -> PostingType -> IO ()
forall a. (Eq a, Show a, HasCallStack) => a -> a -> IO ()
@?= PostingType
VirtualPosting
]
,String -> IO () -> TestTree
test "alias directive" (IO () -> TestTree) -> IO () -> TestTree
forall a b. (a -> b) -> a -> b
$ do
Journal
j <- InputOpts -> Maybe String -> Text -> IO (Either String Journal)
readJournal InputOpts
forall a. Default a => a
def Maybe String
forall a. Maybe a
Nothing "!alias expenses = equity:draw:personal\n1/1\n (expenses:food) 1\n" IO (Either String Journal)
-> (Either String Journal -> IO Journal) -> IO Journal
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= (String -> IO Journal)
-> (Journal -> IO Journal) -> Either String Journal -> IO Journal
forall a c b. (a -> c) -> (b -> c) -> Either a b -> c
either String -> IO Journal
forall a. String -> a
error' Journal -> IO Journal
forall (m :: * -> *) a. Monad m => a -> m a
return
let p :: Posting
p = [Posting] -> Posting
forall a. [a] -> a
head ([Posting] -> Posting) -> [Posting] -> Posting
forall a b. (a -> b) -> a -> b
$ Transaction -> [Posting]
tpostings (Transaction -> [Posting]) -> Transaction -> [Posting]
forall a b. (a -> b) -> a -> b
$ [Transaction] -> Transaction
forall a. [a] -> a
head ([Transaction] -> Transaction) -> [Transaction] -> Transaction
forall a b. (a -> b) -> a -> b
$ Journal -> [Transaction]
jtxns Journal
j
Posting -> Text
paccount Posting
p Text -> Text -> IO ()
forall a. (Eq a, Show a, HasCallStack) => a -> a -> IO ()
@?= "equity:draw:personal:food"
,String -> IO () -> TestTree
test "Y default year directive" (IO () -> TestTree) -> IO () -> TestTree
forall a b. (a -> b) -> a -> b
$ do
Journal
j <- InputOpts -> Maybe String -> Text -> IO (Either String Journal)
readJournal InputOpts
forall a. Default a => a
def Maybe String
forall a. Maybe a
Nothing Text
defaultyear_journal_txt IO (Either String Journal)
-> (Either String Journal -> IO Journal) -> IO Journal
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= (String -> IO Journal)
-> (Journal -> IO Journal) -> Either String Journal -> IO Journal
forall a c b. (a -> c) -> (b -> c) -> Either a b -> c
either String -> IO Journal
forall a. String -> a
error' Journal -> IO Journal
forall (m :: * -> *) a. Monad m => a -> m a
return
Transaction -> Day
tdate ([Transaction] -> Transaction
forall a. [a] -> a
head ([Transaction] -> Transaction) -> [Transaction] -> Transaction
forall a b. (a -> b) -> a -> b
$ Journal -> [Transaction]
jtxns Journal
j) Day -> Day -> IO ()
forall a. (Eq a, Show a, HasCallStack) => a -> a -> IO ()
@?= Integer -> Int -> Int -> Day
fromGregorian 2009 1 1
,String -> IO () -> TestTree
test "ledgerAccountNames" (IO () -> TestTree) -> IO () -> TestTree
forall a b. (a -> b) -> a -> b
$
(Ledger -> [Text]
ledgerAccountNames Ledger
ledger7)
[Text] -> [Text] -> IO ()
forall a. (Eq a, Show a, HasCallStack) => a -> a -> IO ()
@?=
["assets","assets:cash","assets:checking","assets:saving","equity","equity:opening balances",
"expenses","expenses:food","expenses:food:dining","expenses:phone","expenses:vacation",
"liabilities","liabilities:credit cards","liabilities:credit cards:discover"]
,String -> IO () -> TestTree
test "show dollars" (IO () -> TestTree) -> IO () -> TestTree
forall a b. (a -> b) -> a -> b
$ Amount -> String
showAmount (DecimalRaw Integer -> Amount
usd 1) String -> String -> IO ()
forall a. (Eq a, Show a, HasCallStack) => a -> a -> IO ()
@?= "$1.00"
,String -> IO () -> TestTree
test "show hours" (IO () -> TestTree) -> IO () -> TestTree
forall a b. (a -> b) -> a -> b
$ Amount -> String
showAmount (DecimalRaw Integer -> Amount
hrs 1) String -> String -> IO ()
forall a. (Eq a, Show a, HasCallStack) => a -> a -> IO ()
@?= "1.00h"
]
defaultyear_journal_txt :: Text
defaultyear_journal_txt :: Text
defaultyear_journal_txt = [Text] -> Text
T.unlines
["Y2009"
,""
,"01/01 A"
," a $1"
," b"
]
journal7 :: Journal
journal7 :: Journal
journal7 = Journal
nulljournal {jtxns :: [Transaction]
jtxns =
[
Transaction -> Transaction
txnTieKnot Transaction :: Integer
-> Text
-> GenericSourcePos
-> Day
-> Maybe Day
-> Status
-> Text
-> Text
-> Text
-> [Tag]
-> [Posting]
-> Transaction
Transaction {
tindex :: Integer
tindex=0,
tsourcepos :: GenericSourcePos
tsourcepos=GenericSourcePos
nullsourcepos,
tdate :: Day
tdate=String -> Day
parsedate "2007/01/01",
tdate2 :: Maybe Day
tdate2=Maybe Day
forall a. Maybe a
Nothing,
tstatus :: Status
tstatus=Status
Unmarked,
tcode :: Text
tcode="*",
tdescription :: Text
tdescription="opening balance",
tcomment :: Text
tcomment="",
ttags :: [Tag]
ttags=[],
tpostings :: [Posting]
tpostings=
["assets:cash" Text -> Amount -> Posting
`post` DecimalRaw Integer -> Amount
usd 4.82
,"equity:opening balances" Text -> Amount -> Posting
`post` DecimalRaw Integer -> Amount
usd (-4.82)
],
tprecedingcomment :: Text
tprecedingcomment=""
}
,
Transaction -> Transaction
txnTieKnot Transaction :: Integer
-> Text
-> GenericSourcePos
-> Day
-> Maybe Day
-> Status
-> Text
-> Text
-> Text
-> [Tag]
-> [Posting]
-> Transaction
Transaction {
tindex :: Integer
tindex=0,
tsourcepos :: GenericSourcePos
tsourcepos=GenericSourcePos
nullsourcepos,
tdate :: Day
tdate=String -> Day
parsedate "2007/02/01",
tdate2 :: Maybe Day
tdate2=Maybe Day
forall a. Maybe a
Nothing,
tstatus :: Status
tstatus=Status
Unmarked,
tcode :: Text
tcode="*",
tdescription :: Text
tdescription="ayres suites",
tcomment :: Text
tcomment="",
ttags :: [Tag]
ttags=[],
tpostings :: [Posting]
tpostings=
["expenses:vacation" Text -> Amount -> Posting
`post` DecimalRaw Integer -> Amount
usd 179.92
,"assets:checking" Text -> Amount -> Posting
`post` DecimalRaw Integer -> Amount
usd (-179.92)
],
tprecedingcomment :: Text
tprecedingcomment=""
}
,
Transaction -> Transaction
txnTieKnot Transaction :: Integer
-> Text
-> GenericSourcePos
-> Day
-> Maybe Day
-> Status
-> Text
-> Text
-> Text
-> [Tag]
-> [Posting]
-> Transaction
Transaction {
tindex :: Integer
tindex=0,
tsourcepos :: GenericSourcePos
tsourcepos=GenericSourcePos
nullsourcepos,
tdate :: Day
tdate=String -> Day
parsedate "2007/01/02",
tdate2 :: Maybe Day
tdate2=Maybe Day
forall a. Maybe a
Nothing,
tstatus :: Status
tstatus=Status
Unmarked,
tcode :: Text
tcode="*",
tdescription :: Text
tdescription="auto transfer to savings",
tcomment :: Text
tcomment="",
ttags :: [Tag]
ttags=[],
tpostings :: [Posting]
tpostings=
["assets:saving" Text -> Amount -> Posting
`post` DecimalRaw Integer -> Amount
usd 200
,"assets:checking" Text -> Amount -> Posting
`post` DecimalRaw Integer -> Amount
usd (-200)
],
tprecedingcomment :: Text
tprecedingcomment=""
}
,
Transaction -> Transaction
txnTieKnot Transaction :: Integer
-> Text
-> GenericSourcePos
-> Day
-> Maybe Day
-> Status
-> Text
-> Text
-> Text
-> [Tag]
-> [Posting]
-> Transaction
Transaction {
tindex :: Integer
tindex=0,
tsourcepos :: GenericSourcePos
tsourcepos=GenericSourcePos
nullsourcepos,
tdate :: Day
tdate=String -> Day
parsedate "2007/01/03",
tdate2 :: Maybe Day
tdate2=Maybe Day
forall a. Maybe a
Nothing,
tstatus :: Status
tstatus=Status
Unmarked,
tcode :: Text
tcode="*",
tdescription :: Text
tdescription="poquito mas",
tcomment :: Text
tcomment="",
ttags :: [Tag]
ttags=[],
tpostings :: [Posting]
tpostings=
["expenses:food:dining" Text -> Amount -> Posting
`post` DecimalRaw Integer -> Amount
usd 4.82
,"assets:cash" Text -> Amount -> Posting
`post` DecimalRaw Integer -> Amount
usd (-4.82)
],
tprecedingcomment :: Text
tprecedingcomment=""
}
,
Transaction -> Transaction
txnTieKnot Transaction :: Integer
-> Text
-> GenericSourcePos
-> Day
-> Maybe Day
-> Status
-> Text
-> Text
-> Text
-> [Tag]
-> [Posting]
-> Transaction
Transaction {
tindex :: Integer
tindex=0,
tsourcepos :: GenericSourcePos
tsourcepos=GenericSourcePos
nullsourcepos,
tdate :: Day
tdate=String -> Day
parsedate "2007/01/03",
tdate2 :: Maybe Day
tdate2=Maybe Day
forall a. Maybe a
Nothing,
tstatus :: Status
tstatus=Status
Unmarked,
tcode :: Text
tcode="*",
tdescription :: Text
tdescription="verizon",
tcomment :: Text
tcomment="",
ttags :: [Tag]
ttags=[],
tpostings :: [Posting]
tpostings=
["expenses:phone" Text -> Amount -> Posting
`post` DecimalRaw Integer -> Amount
usd 95.11
,"assets:checking" Text -> Amount -> Posting
`post` DecimalRaw Integer -> Amount
usd (-95.11)
],
tprecedingcomment :: Text
tprecedingcomment=""
}
,
Transaction -> Transaction
txnTieKnot Transaction :: Integer
-> Text
-> GenericSourcePos
-> Day
-> Maybe Day
-> Status
-> Text
-> Text
-> Text
-> [Tag]
-> [Posting]
-> Transaction
Transaction {
tindex :: Integer
tindex=0,
tsourcepos :: GenericSourcePos
tsourcepos=GenericSourcePos
nullsourcepos,
tdate :: Day
tdate=String -> Day
parsedate "2007/01/03",
tdate2 :: Maybe Day
tdate2=Maybe Day
forall a. Maybe a
Nothing,
tstatus :: Status
tstatus=Status
Unmarked,
tcode :: Text
tcode="*",
tdescription :: Text
tdescription="discover",
tcomment :: Text
tcomment="",
ttags :: [Tag]
ttags=[],
tpostings :: [Posting]
tpostings=
["liabilities:credit cards:discover" Text -> Amount -> Posting
`post` DecimalRaw Integer -> Amount
usd 80
,"assets:checking" Text -> Amount -> Posting
`post` DecimalRaw Integer -> Amount
usd (-80)
],
tprecedingcomment :: Text
tprecedingcomment=""
}
]
}
ledger7 :: Ledger
ledger7 :: Ledger
ledger7 = Query -> Journal -> Ledger
ledgerFromJournal Query
Any Journal
journal7