{-# 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.Aregister
,module Hledger.Cli.Commands.Balance
,module Hledger.Cli.Commands.Balancesheet
,module Hledger.Cli.Commands.Balancesheetequity
,module Hledger.Cli.Commands.Cashflow
,module Hledger.Cli.Commands.Close
,module Hledger.Cli.Commands.Codes
,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.Register
,module Hledger.Cli.Commands.Rewrite
,module Hledger.Cli.Commands.Stats
,module Hledger.Cli.Commands.Tags
)
where
import Data.Char (isSpace)
import Data.List
import Data.Text (Text)
import qualified Data.Text as T
import Data.Time.Calendar
import String.ANSI
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.Aregister
import Hledger.Cli.Commands.Balance
import Hledger.Cli.Commands.Balancesheet
import Hledger.Cli.Commands.Balancesheetequity
import Hledger.Cli.Commands.Cashflow
import Hledger.Cli.Commands.Check
import Hledger.Cli.Commands.Close
import Hledger.Cli.Commands.Codes
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.Register
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)
import Data.List.Extra (chunksOf)
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
aregistermode , CliOpts -> Journal -> IO ()
aregister)
,(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
checkmode , CliOpts -> Journal -> IO ()
check)
,(Mode RawOpts
closemode , CliOpts -> Journal -> IO ()
close)
,(Mode RawOpts
codesmode , CliOpts -> Journal -> IO ()
codes)
,(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
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)
]
_banner_slant :: [[Char]]
_banner_slant = forall a. Int -> [a] -> [a]
drop Int
1 [[Char]
""
,[Char]
" __ __ __ "
,[Char]
" / /_ / /__ ____/ /___ ____ _____"
,[Char]
" / __ \\/ / _ \\/ __ / __ `/ _ \\/ ___/"
,[Char]
" / / / / / __/ /_/ / /_/ / __/ / "
,[Char]
"/_/ /_/_/\\___/\\__,_/\\__, /\\___/_/ "
,[Char]
" /____/ "
]
_banner_smslant :: [[Char]]
_banner_smslant = forall a. Int -> [a] -> [a]
drop Int
1 [[Char]
""
,[Char]
" __ __ __ "
,[Char]
" / / / /__ ___/ /__ ____ ____"
,[Char]
" / _ \\/ / -_) _ / _ `/ -_) __/"
,[Char]
"/_//_/_/\\__/\\_,_/\\_, /\\__/_/ "
,[Char]
" /___/ "
]
_banner_speed :: [[Char]]
_banner_speed = forall a. Int -> [a] -> [a]
drop Int
1 [[Char]
""
,[Char]
"______ ______ _________ "
,[Char]
"___ /____ /__________ /______ _____________"
,[Char]
"__ __ \\_ /_ _ \\ __ /__ __ `/ _ \\_ ___/"
,[Char]
"_ / / / / / __/ /_/ / _ /_/ // __/ / "
,[Char]
"/_/ /_//_/ \\___/\\__,_/ _\\__, / \\___//_/ "
,[Char]
" /____/ "
]
accent :: String -> String
accent :: [Char] -> [Char]
accent
| Bool -> Bool
not Bool
useColorOnStdout = forall a. a -> a
id
| Maybe Bool
terminalIsLight forall a. Eq a => a -> a -> Bool
== forall a. a -> Maybe a
Just Bool
False = [Char] -> [Char]
brightWhite
| Maybe Bool
terminalIsLight forall a. Eq a => a -> a -> Bool
== forall a. a -> Maybe a
Just Bool
True = [Char] -> [Char]
brightBlack
| Bool
otherwise = forall a. a -> a
id
highlightAddon :: a -> a
highlightAddon = forall a. a -> a
id
bold' :: [Char] -> [Char]
bold' = if Bool
useColorOnStdout then [Char] -> [Char]
bold else forall a. a -> a
id
commandsList :: String -> [String] -> Bool -> [String]
commandsList :: [Char] -> [[Char]] -> Bool -> [[Char]]
commandsList [Char]
progversion [[Char]]
othercmds Bool
highlight0 =
let highlight :: Bool
highlight = Bool
highlight0 Bool -> Bool -> Bool
&& Bool
useColorOnStdout in
(if Bool
highlight then (forall a b. (a -> b) -> [a] -> [b]
map (\[Char]
s -> if [Char]
"+" forall a. Eq a => [a] -> [a] -> Bool
`isPrefixOf` [Char]
s then forall a. a -> a
highlightAddon (Char
' ' forall a. a -> [a] -> [a]
: forall a. Int -> [a] -> [a]
drop Int
1 [Char]
s) else [Char]
s)) else forall a. a -> a
id) forall a b. (a -> b) -> a -> b
$
forall a b. (a -> b) -> [a] -> [b]
map ([Char] -> [Char]
bold'forall b c a. (b -> c) -> (a -> b) -> a -> c
.[Char] -> [Char]
accent) [[Char]]
_banner_smslant forall a. [a] -> [a] -> [a]
++
[
[Char]
"-------------------------------------------------------------------------------"
,[Char]
progversion
,[Char]
"Usage: hledger COMMAND [OPTIONS] [-- ADDONCMDOPTIONS]"
,[Char]
"Commands (+ addons found in $PATH):"
,[Char]
""
,[Char]
"Usage: " forall a. [a] -> [a] -> [a]
++ [Char] -> [Char]
bold' [Char]
"hledger CMD [OPTS] [-- ADDONCMDOPTS]"
,[Char]
""
,[Char]
"Commands:"
,[Char] -> [Char]
bold' [Char]
"DATA ENTRY: add or edit entries in the journal file"
,[Char]
" add add transactions using terminal prompts"
,[Char]
"+edit edit a subset of transactions"
,[Char]
"+iadd add transactions using a TUI"
,[Char]
" import add new transactions from other files, eg CSV files"
,[Char]
""
,[Char] -> [Char]
bold' [Char]
"DATA CREATION: create or convert entries to be added to the journal file"
,[Char]
"+autosync download/deduplicate/convert OFX data"
,[Char]
" close generate balance-zeroing/restoring transactions"
,[Char]
"+fifo sell generate a lot-selling transaction, using FIFO"
,[Char]
"+interest generate interest transactions"
,[Char]
" rewrite generate auto postings, like print --auto"
,[Char]
"+stockquotes download market prices from AlphaVantage"
,[Char]
""
,[Char] -> [Char]
bold' [Char]
"DATA MANAGEMENT: help validate or manage journal files"
,[Char]
" check check for various kinds of error in the data"
,[Char]
"+check-fancyassertions check more powerful balance assertions"
,[Char]
"+check-tagfiles check file paths in tag values exist"
,[Char]
" diff compare account transactions in two journal files"
,[Char]
"+git record/status/log journal changes easily with git"
,[Char]
"+pijul record/status/log journal changes easily with pijul"
,[Char]
""
,[Char] -> [Char]
bold' [Char]
"REPORTS, FINANCIAL: standard financial reports"
,[Char]
" aregister (areg) show transactions in a particular account"
,[Char]
" balancesheet (bs) show assets, liabilities and net worth"
,[Char]
" balancesheetequity (bse) show assets, liabilities and equity"
,[Char]
" cashflow (cf) show changes in liquid assets"
,[Char]
" incomestatement (is) show revenues and expenses"
,[Char]
""
,[Char] -> [Char]
bold' [Char]
"REPORTS, VERSATILE: more complex/versatile reporting commands"
,[Char]
" balance (bal) show balance changes, end balances, budgets, gains.."
,[Char]
"+fifo lots show a commodity's remaining lots, using FIFO"
,[Char]
"+plot create charts from balance reports, in terminal or GUI"
,[Char]
" print show transactions or export journal data"
,[Char]
" register (reg) show postings in one or more accounts & running total"
,[Char]
" roi show return on investments"
,[Char]
""
,[Char] -> [Char]
bold' [Char]
"REPORTS, BASIC: simple reports"
,[Char]
" accounts show account names"
,[Char]
" activity show bar charts of posting counts per period"
,[Char]
" codes show transaction codes"
,[Char]
" commodities show commodity/currency symbols"
,[Char]
" descriptions show transaction descriptions"
,[Char]
" files show input file paths"
,[Char]
" notes show note parts of transaction descriptions"
,[Char]
" payees show payee parts of transaction descriptions"
,[Char]
" prices show market prices"
,[Char]
" stats show journal statistics"
,[Char]
" tags show tag names"
,[Char]
" test run self tests"
,[Char]
""
,[Char] -> [Char]
bold' [Char]
"UIS: other user interfaces"
,[Char]
"+ui run terminal UI"
,[Char]
"+web run web UI"
,[Char]
""
,[Char] -> [Char]
bold' [Char]
"OTHER: other hledger-* addon commands found in PATH"
] forall a. [a] -> [a] -> [a]
++
Int -> [[Char]] -> [[Char]]
multicol Int
80 (forall a b. (a -> b) -> [a] -> [b]
map (forall a. a -> a
highlightAddon forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Char
' 'forall a. a -> [a] -> [a]
:) forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a. Int -> [a] -> [a]
drop Int
1) [[Char]]
othercmds)
forall a. [a] -> [a] -> [a]
++
[[Char]
""
,[Char] -> [Char]
bold' [Char]
"HELP: command-line help and more docs"
,[Char]
" hledger show this commands list"
,[Char]
" hledger -h show hledger's general help"
,[Char]
" hledger COMMAND -h show COMMAND's help"
,[Char]
" hledger help [-i|-m|-p] [TOPIC] show the hledger manual with info/man/pager"
,[Char]
" https://hledger.org html manuals, tutorials, support.."
,[Char]
""
]
multicol :: Int -> [String] -> [String]
multicol :: Int -> [[Char]] -> [[Char]]
multicol Int
_ [] = []
multicol Int
width [[Char]]
strs =
let
maxwidth :: Int
maxwidth = forall a. Integral a => [a] -> a
maximum' forall a b. (a -> b) -> a -> b
$ forall a b. (a -> b) -> [a] -> [b]
map forall (t :: * -> *) a. Foldable t => t a -> Int
length [[Char]]
strs
numcols :: Int
numcols = forall a. Ord a => a -> a -> a
min (forall (t :: * -> *) a. Foldable t => t a -> Int
length [[Char]]
strs) (Int
width forall a. Integral a => a -> a -> a
`div` (Int
maxwidthforall a. Num a => a -> a -> a
+Int
2))
itemspercol :: Int
itemspercol = forall (t :: * -> *) a. Foldable t => t a -> Int
length [[Char]]
strs forall a. Integral a => a -> a -> a
`div` Int
numcols
colitems :: [[[Char]]]
colitems = forall a. Partial => Int -> [a] -> [[a]]
chunksOf Int
itemspercol [[Char]]
strs
cols :: [[Char]]
cols = forall a b. (a -> b) -> [a] -> [b]
map [[Char]] -> [Char]
unlines [[[Char]]]
colitems
sep :: [Char]
sep = [Char]
" "
in
[Char] -> [[Char]]
lines forall a b. (a -> b) -> a -> b
$ Text -> [Char]
T.unpack forall a b. (a -> b) -> a -> b
$ [Text] -> Text
textConcatBottomPadded forall a b. (a -> b) -> a -> b
$ forall a b. (a -> b) -> [a] -> [b]
map [Char] -> Text
T.pack forall a b. (a -> b) -> a -> b
$ forall a. a -> [a] -> [a]
intersperse [Char]
sep [[Char]]
cols
builtinCommandNames :: [String]
builtinCommandNames :: [[Char]]
builtinCommandNames = forall (t :: * -> *) a b. Foldable t => (a -> [b]) -> t a -> [b]
concatMap (forall a. Mode a -> [[Char]]
modeNames forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a b. (a, b) -> a
fst) [(Mode RawOpts, CliOpts -> Journal -> IO ())]
builtinCommands
findCommand :: String -> Maybe (Mode RawOpts, CliOpts -> Journal -> IO ())
findCommand :: [Char] -> Maybe (Mode RawOpts, CliOpts -> Journal -> IO ())
findCommand [Char]
cmdname = forall (t :: * -> *) a. Foldable t => (a -> Bool) -> t a -> Maybe a
find (forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
elem [Char]
cmdname forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a. Mode a -> [[Char]]
modeNames forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a b. (a, b) -> a
fst) [(Mode RawOpts, CliOpts -> Journal -> IO ())]
builtinCommands
commandsFromCommandsList :: [String] -> [String]
commandsFromCommandsList :: [[Char]] -> [[Char]]
commandsFromCommandsList [[Char]]
s = [[Char]
w | Char
c:[Char]
l <- [[Char]]
s, Char
c forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
`elem` [Char
' ',Char
'+'], let [Char]
w:[[Char]]
_ = [Char] -> [[Char]]
words [Char]
l]
knownCommands :: [String]
knownCommands :: [[Char]]
knownCommands = forall a. Ord a => [a] -> [a]
sort forall b c a. (b -> c) -> (a -> b) -> a -> c
. [[Char]] -> [[Char]]
commandsFromCommandsList forall a b. (a -> b) -> a -> b
$ [Char] -> [[Char]] -> Bool -> [[Char]]
commandsList [Char]
progname [] Bool
False
printCommandsList :: String -> [String] -> IO ()
printCommandsList :: [Char] -> [[Char]] -> IO ()
printCommandsList [Char]
progversion [[Char]]
addonsFound =
[Char] -> IO ()
pager forall b c a. (b -> c) -> (a -> b) -> a -> c
. [[Char]] -> [Char]
unlines forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall (t :: * -> *) a b. Foldable t => (a -> [b]) -> t a -> [b]
concatMap [Char] -> [[Char]]
adjustline forall a b. (a -> b) -> a -> b
$
[Char] -> [[Char]] -> Bool -> [[Char]]
commandsList [Char]
progversion (forall a b. (a -> b) -> [a] -> [b]
map (Char
'+'forall a. a -> [a] -> [a]
:) [[Char]]
unknownCommandsFound) Bool
True
where
commandsFound :: [[Char]]
commandsFound = forall a b. (a -> b) -> [a] -> [b]
map (Char
' 'forall a. a -> [a] -> [a]
:) [[Char]]
builtinCommandNames forall a. [a] -> [a] -> [a]
++ forall a b. (a -> b) -> [a] -> [b]
map (Char
'+'forall a. a -> [a] -> [a]
:) [[Char]]
addonsFound
unknownCommandsFound :: [[Char]]
unknownCommandsFound = [[Char]]
addonsFound forall a. Eq a => [a] -> [a] -> [a]
\\ [[Char]]
knownCommands
adjustline :: [Char] -> [[Char]]
adjustline [Char]
l | [Char]
" hledger " forall a. Eq a => [a] -> [a] -> Bool
`isPrefixOf` [Char]
l = [[Char]
l]
adjustline l :: [Char]
l@(Char
'+':[Char]
_) | [Char]
cmd forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
`notElem` [[Char]]
commandsFound = []
where
cmd :: [Char]
cmd = forall a. (a -> Bool) -> [a] -> [a]
takeWhile (Bool -> Bool
not forall b c a. (b -> c) -> (a -> b) -> a -> c
. Char -> Bool
isSpace) [Char]
l
adjustline [Char]
l = [[Char]
l]
testmode :: Mode RawOpts
testmode = [Char]
-> [Flag RawOpts]
-> [([Char], [Flag RawOpts])]
-> [Flag RawOpts]
-> ([Arg RawOpts], Maybe (Arg RawOpts))
-> Mode RawOpts
hledgerCommandMode
$(embedFileRelative "Hledger/Cli/Commands/Test.txt")
[]
[([Char], [Flag RawOpts])
generalflagsgroup3]
[]
([], forall a. a -> Maybe a
Just forall a b. (a -> b) -> a -> b
$ [Char] -> Arg RawOpts
argsFlag [Char]
"[-- TASTYOPTS]")
testcmd :: CliOpts -> Journal -> IO ()
testcmd :: CliOpts -> Journal -> IO ()
testcmd CliOpts
opts Journal
_undefined = do
forall a. [[Char]] -> IO a -> IO a
withArgs ([Char] -> RawOpts -> [[Char]]
listofstringopt [Char]
"args" forall a b. (a -> b) -> a -> b
$ CliOpts -> RawOpts
rawopts_ CliOpts
opts) forall a b. (a -> b) -> a -> b
$
TestTree -> IO ()
Test.Tasty.defaultMain forall a b. (a -> b) -> a -> b
$ [Char] -> [TestTree] -> TestTree
testGroup [Char]
"hledger" [
TestTree
tests_Hledger
,TestTree
tests_Hledger_Cli
]
tests_Hledger_Cli :: TestTree
tests_Hledger_Cli = [Char] -> [TestTree] -> TestTree
testGroup [Char]
"Hledger.Cli" [
TestTree
tests_Cli_Utils
,TestTree
tests_Commands
]
tests_Commands :: TestTree
tests_Commands = [Char] -> [TestTree] -> TestTree
testGroup [Char]
"Commands" [
TestTree
tests_Balance
,TestTree
tests_Register
,TestTree
tests_Aregister
,[Char] -> [TestTree] -> TestTree
testGroup [Char]
"apply account directive" [
[Char] -> IO () -> TestTree
testCase [Char]
"works" forall a b. (a -> b) -> a -> b
$ do
let
ignoresourcepos :: Journal -> Journal
ignoresourcepos Journal
j = Journal
j{jtxns :: [Transaction]
jtxns=forall a b. (a -> b) -> [a] -> [b]
map (\Transaction
t -> Transaction
t{tsourcepos :: (SourcePos, SourcePos)
tsourcepos=(SourcePos, SourcePos)
nullsourcepos}) (Journal -> [Transaction]
jtxns Journal
j)}
sameParse :: Text -> Text -> IO ()
sameParse Text
str1 Text
str2 = do
Journal
j1 <- Journal -> Journal
ignoresourcepos forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Text -> IO Journal
readJournal' Text
str1
Journal
j2 <- Journal -> Journal
ignoresourcepos forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Text -> IO Journal
readJournal' Text
str2
Journal
j1 forall a. (Eq a, Show a, Partial) => a -> a -> IO ()
@?= Journal
j2{jlastreadtime :: POSIXTime
jlastreadtime=Journal -> POSIXTime
jlastreadtime Journal
j1, jfiles :: [([Char], Text)]
jfiles=Journal -> [([Char], Text)]
jfiles Journal
j1}
Text -> Text -> IO ()
sameParse
(Text
"2008/12/07 One\n alpha $-1\n beta $1\n" forall a. Semigroup a => a -> a -> a
<>
Text
"apply account outer\n2008/12/07 Two\n aigh $-2\n bee $2\n" forall a. Semigroup a => a -> a -> a
<>
Text
"apply account inner\n2008/12/07 Three\n gamma $-3\n delta $3\n" forall a. Semigroup a => a -> a -> a
<>
Text
"end apply account\n2008/12/07 Four\n why $-4\n zed $4\n" forall a. Semigroup a => a -> a -> a
<>
Text
"end apply account\n2008/12/07 Five\n foo $-5\n bar $5\n"
)
(Text
"2008/12/07 One\n alpha $-1\n beta $1\n" forall a. Semigroup a => a -> a -> a
<>
Text
"2008/12/07 Two\n outer:aigh $-2\n outer:bee $2\n" forall a. Semigroup a => a -> a -> a
<>
Text
"2008/12/07 Three\n outer:inner:gamma $-3\n outer:inner:delta $3\n" forall a. Semigroup a => a -> a -> a
<>
Text
"2008/12/07 Four\n outer:why $-4\n outer:zed $4\n" forall a. Semigroup a => a -> a -> a
<>
Text
"2008/12/07 Five\n foo $-5\n bar $5\n"
)
,[Char] -> IO () -> TestTree
testCase [Char]
"preserves \"virtual\" posting type" forall a b. (a -> b) -> a -> b
$ do
Journal
j <- Text -> IO Journal
readJournal' Text
"apply account test\n2008/12/07 One\n (from) $-1\n (to) $1\n"
let p :: Posting
p = forall a. [a] -> a
head forall a b. (a -> b) -> a -> b
$ Transaction -> [Posting]
tpostings forall a b. (a -> b) -> a -> b
$ forall a. [a] -> a
head forall a b. (a -> b) -> a -> b
$ Journal -> [Transaction]
jtxns Journal
j
Posting -> Text
paccount Posting
p forall a. (Eq a, Show a, Partial) => a -> a -> IO ()
@?= Text
"test:from"
Posting -> PostingType
ptype Posting
p forall a. (Eq a, Show a, Partial) => a -> a -> IO ()
@?= PostingType
VirtualPosting
]
,[Char] -> IO () -> TestTree
testCase [Char]
"alias directive" forall a b. (a -> b) -> a -> b
$ do
Journal
j <- Text -> IO Journal
readJournal' Text
"!alias expenses = equity:draw:personal\n1/1\n (expenses:food) 1\n"
let p :: Posting
p = forall a. [a] -> a
head forall a b. (a -> b) -> a -> b
$ Transaction -> [Posting]
tpostings forall a b. (a -> b) -> a -> b
$ forall a. [a] -> a
head forall a b. (a -> b) -> a -> b
$ Journal -> [Transaction]
jtxns Journal
j
Posting -> Text
paccount Posting
p forall a. (Eq a, Show a, Partial) => a -> a -> IO ()
@?= Text
"equity:draw:personal:food"
,[Char] -> IO () -> TestTree
testCase [Char]
"Y default year directive" forall a b. (a -> b) -> a -> b
$ do
Journal
j <- Text -> IO Journal
readJournal' Text
defaultyear_journal_txt
Transaction -> Day
tdate (forall a. [a] -> a
head forall a b. (a -> b) -> a -> b
$ Journal -> [Transaction]
jtxns Journal
j) forall a. (Eq a, Show a, Partial) => a -> a -> IO ()
@?= Integer -> Int -> Int -> Day
fromGregorian Integer
2009 Int
1 Int
1
,[Char] -> IO () -> TestTree
testCase [Char]
"ledgerAccountNames" forall a b. (a -> b) -> a -> b
$
(Ledger -> [Text]
ledgerAccountNames Ledger
ledger7)
forall a. (Eq a, Show a, Partial) => a -> a -> IO ()
@?=
[Text
"assets",Text
"assets:cash",Text
"assets:checking",Text
"assets:saving",Text
"equity",Text
"equity:opening balances",
Text
"expenses",Text
"expenses:food",Text
"expenses:food:dining",Text
"expenses:phone",Text
"expenses:vacation",
Text
"liabilities",Text
"liabilities:credit cards",Text
"liabilities:credit cards:discover"]
,[Char] -> IO () -> TestTree
testCase [Char]
"show dollars" forall a b. (a -> b) -> a -> b
$ Amount -> [Char]
showAmount (DecimalRaw Integer -> Amount
usd DecimalRaw Integer
1) forall a. (Eq a, Show a, Partial) => a -> a -> IO ()
@?= [Char]
"$1.00"
,[Char] -> IO () -> TestTree
testCase [Char]
"show hours" forall a b. (a -> b) -> a -> b
$ Amount -> [Char]
showAmount (DecimalRaw Integer -> Amount
hrs DecimalRaw Integer
1) forall a. (Eq a, Show a, Partial) => a -> a -> IO ()
@?= [Char]
"1.00h"
]
defaultyear_journal_txt :: Text
defaultyear_journal_txt :: Text
defaultyear_journal_txt = [Text] -> Text
T.unlines
[Text
"Y2009"
,Text
""
,Text
"01/01 A"
,Text
" a $1"
,Text
" b"
]
journal7 :: Journal
journal7 :: Journal
journal7 = Journal
nulljournal {jtxns :: [Transaction]
jtxns =
[
Transaction -> Transaction
txnTieKnot Transaction {
tindex :: Integer
tindex=Integer
0,
tsourcepos :: (SourcePos, SourcePos)
tsourcepos=(SourcePos, SourcePos)
nullsourcepos,
tdate :: Day
tdate=Integer -> Int -> Int -> Day
fromGregorian Integer
2007 Int
01 Int
01,
tdate2 :: Maybe Day
tdate2=forall a. Maybe a
Nothing,
tstatus :: Status
tstatus=Status
Unmarked,
tcode :: Text
tcode=Text
"*",
tdescription :: Text
tdescription=Text
"opening balance",
tcomment :: Text
tcomment=Text
"",
ttags :: [Tag]
ttags=[],
tpostings :: [Posting]
tpostings=
[Text
"assets:cash" Text -> Amount -> Posting
`post` DecimalRaw Integer -> Amount
usd DecimalRaw Integer
4.82
,Text
"equity:opening balances" Text -> Amount -> Posting
`post` DecimalRaw Integer -> Amount
usd (-DecimalRaw Integer
4.82)
],
tprecedingcomment :: Text
tprecedingcomment=Text
""
}
,
Transaction -> Transaction
txnTieKnot Transaction {
tindex :: Integer
tindex=Integer
0,
tsourcepos :: (SourcePos, SourcePos)
tsourcepos=(SourcePos, SourcePos)
nullsourcepos,
tdate :: Day
tdate=Integer -> Int -> Int -> Day
fromGregorian Integer
2007 Int
02 Int
01,
tdate2 :: Maybe Day
tdate2=forall a. Maybe a
Nothing,
tstatus :: Status
tstatus=Status
Unmarked,
tcode :: Text
tcode=Text
"*",
tdescription :: Text
tdescription=Text
"ayres suites",
tcomment :: Text
tcomment=Text
"",
ttags :: [Tag]
ttags=[],
tpostings :: [Posting]
tpostings=
[Text
"expenses:vacation" Text -> Amount -> Posting
`post` DecimalRaw Integer -> Amount
usd DecimalRaw Integer
179.92
,Text
"assets:checking" Text -> Amount -> Posting
`post` DecimalRaw Integer -> Amount
usd (-DecimalRaw Integer
179.92)
],
tprecedingcomment :: Text
tprecedingcomment=Text
""
}
,
Transaction -> Transaction
txnTieKnot Transaction {
tindex :: Integer
tindex=Integer
0,
tsourcepos :: (SourcePos, SourcePos)
tsourcepos=(SourcePos, SourcePos)
nullsourcepos,
tdate :: Day
tdate=Integer -> Int -> Int -> Day
fromGregorian Integer
2007 Int
01 Int
02,
tdate2 :: Maybe Day
tdate2=forall a. Maybe a
Nothing,
tstatus :: Status
tstatus=Status
Unmarked,
tcode :: Text
tcode=Text
"*",
tdescription :: Text
tdescription=Text
"auto transfer to savings",
tcomment :: Text
tcomment=Text
"",
ttags :: [Tag]
ttags=[],
tpostings :: [Posting]
tpostings=
[Text
"assets:saving" Text -> Amount -> Posting
`post` DecimalRaw Integer -> Amount
usd DecimalRaw Integer
200
,Text
"assets:checking" Text -> Amount -> Posting
`post` DecimalRaw Integer -> Amount
usd (-DecimalRaw Integer
200)
],
tprecedingcomment :: Text
tprecedingcomment=Text
""
}
,
Transaction -> Transaction
txnTieKnot Transaction {
tindex :: Integer
tindex=Integer
0,
tsourcepos :: (SourcePos, SourcePos)
tsourcepos=(SourcePos, SourcePos)
nullsourcepos,
tdate :: Day
tdate=Integer -> Int -> Int -> Day
fromGregorian Integer
2007 Int
01 Int
03,
tdate2 :: Maybe Day
tdate2=forall a. Maybe a
Nothing,
tstatus :: Status
tstatus=Status
Unmarked,
tcode :: Text
tcode=Text
"*",
tdescription :: Text
tdescription=Text
"poquito mas",
tcomment :: Text
tcomment=Text
"",
ttags :: [Tag]
ttags=[],
tpostings :: [Posting]
tpostings=
[Text
"expenses:food:dining" Text -> Amount -> Posting
`post` DecimalRaw Integer -> Amount
usd DecimalRaw Integer
4.82
,Text
"assets:cash" Text -> Amount -> Posting
`post` DecimalRaw Integer -> Amount
usd (-DecimalRaw Integer
4.82)
],
tprecedingcomment :: Text
tprecedingcomment=Text
""
}
,
Transaction -> Transaction
txnTieKnot Transaction {
tindex :: Integer
tindex=Integer
0,
tsourcepos :: (SourcePos, SourcePos)
tsourcepos=(SourcePos, SourcePos)
nullsourcepos,
tdate :: Day
tdate=Integer -> Int -> Int -> Day
fromGregorian Integer
2007 Int
01 Int
03,
tdate2 :: Maybe Day
tdate2=forall a. Maybe a
Nothing,
tstatus :: Status
tstatus=Status
Unmarked,
tcode :: Text
tcode=Text
"*",
tdescription :: Text
tdescription=Text
"verizon",
tcomment :: Text
tcomment=Text
"",
ttags :: [Tag]
ttags=[],
tpostings :: [Posting]
tpostings=
[Text
"expenses:phone" Text -> Amount -> Posting
`post` DecimalRaw Integer -> Amount
usd DecimalRaw Integer
95.11
,Text
"assets:checking" Text -> Amount -> Posting
`post` DecimalRaw Integer -> Amount
usd (-DecimalRaw Integer
95.11)
],
tprecedingcomment :: Text
tprecedingcomment=Text
""
}
,
Transaction -> Transaction
txnTieKnot Transaction {
tindex :: Integer
tindex=Integer
0,
tsourcepos :: (SourcePos, SourcePos)
tsourcepos=(SourcePos, SourcePos)
nullsourcepos,
tdate :: Day
tdate=Integer -> Int -> Int -> Day
fromGregorian Integer
2007 Int
01 Int
03,
tdate2 :: Maybe Day
tdate2=forall a. Maybe a
Nothing,
tstatus :: Status
tstatus=Status
Unmarked,
tcode :: Text
tcode=Text
"*",
tdescription :: Text
tdescription=Text
"discover",
tcomment :: Text
tcomment=Text
"",
ttags :: [Tag]
ttags=[],
tpostings :: [Posting]
tpostings=
[Text
"liabilities:credit cards:discover" Text -> Amount -> Posting
`post` DecimalRaw Integer -> Amount
usd DecimalRaw Integer
80
,Text
"assets:checking" Text -> Amount -> Posting
`post` DecimalRaw Integer -> Amount
usd (-DecimalRaw Integer
80)
],
tprecedingcomment :: Text
tprecedingcomment=Text
""
}
]
}
ledger7 :: Ledger
ledger7 :: Ledger
ledger7 = Query -> Journal -> Ledger
ledgerFromJournal Query
Any Journal
journal7