add: add default commodity to commodity-less amounts (#26), misc. defaults fixes
This commit is contained in:
parent
18fd5fe482
commit
37378d6b97
@ -390,12 +390,26 @@ The following commands can alter your journal file.
|
|||||||
##### add
|
##### add
|
||||||
|
|
||||||
The add command prompts interactively for new transactions, and adds them
|
The add command prompts interactively for new transactions, and adds them
|
||||||
to the journal. It is experimental.
|
to the journal, with assistance:
|
||||||
|
|
||||||
|
- During data entry, the usual console editing keys should work
|
||||||
|
|
||||||
|
- If there are earlier transactions approximately matching the description
|
||||||
|
you enter, the best match will provide defaults for the other fields.
|
||||||
|
|
||||||
|
- If you specify [account pattern(s)](#filter-patterns) on the command
|
||||||
|
line, only matching transactions will be considered for defaults.
|
||||||
|
|
||||||
|
- While entering account names, the tab key will auto-complete up to the
|
||||||
|
next : separator
|
||||||
|
|
||||||
|
- If a [default commodity](#default-commodity) is defined, it will be used
|
||||||
|
for any commodity-less amounts entered.
|
||||||
|
|
||||||
Examples:
|
Examples:
|
||||||
|
|
||||||
$ hledger add
|
$ hledger add
|
||||||
$ hledger add accounts:personal:bob
|
$ hledger -f home.journal add equity:bob
|
||||||
|
|
||||||
##### web
|
##### web
|
||||||
|
|
||||||
|
|||||||
@ -27,6 +27,8 @@ import System.Console.Haskeline (
|
|||||||
import Control.Monad.Trans (liftIO)
|
import Control.Monad.Trans (liftIO)
|
||||||
import System.Console.Haskeline.Completion
|
import System.Console.Haskeline.Completion
|
||||||
import qualified Data.Set as Set
|
import qualified Data.Set as Set
|
||||||
|
import Safe (headMay)
|
||||||
|
|
||||||
|
|
||||||
-- | Read transactions from the terminal, prompting for each field,
|
-- | Read transactions from the terminal, prompting for each field,
|
||||||
-- and append them to the journal file. If the journal came from stdin, this
|
-- and append them to the journal file. If the journal came from stdin, this
|
||||||
@ -74,7 +76,7 @@ getTransaction j opts args defaultDate = do
|
|||||||
else True
|
else True
|
||||||
where (ant,_,_,_) = groupPostings $ journalPostings j
|
where (ant,_,_,_) = groupPostings $ journalPostings j
|
||||||
getpostingsandvalidate = do
|
getpostingsandvalidate = do
|
||||||
ps <- getPostings accept bestmatchpostings []
|
ps <- getPostings (jContext j) accept bestmatchpostings []
|
||||||
let t = nulltransaction{tdate=date
|
let t = nulltransaction{tdate=date
|
||||||
,tstatus=False
|
,tstatus=False
|
||||||
,tdescription=description
|
,tdescription=description
|
||||||
@ -90,37 +92,51 @@ getTransaction j opts args defaultDate = do
|
|||||||
hPutStr stderr $ concatMap (\(n,t) -> printf "[%3d%%] %s" (round $ n*100 :: Int) (show t)) $ take 3 historymatches)
|
hPutStr stderr $ concatMap (\(n,t) -> printf "[%3d%%] %s" (round $ n*100 :: Int) (show t)) $ take 3 historymatches)
|
||||||
getpostingsandvalidate
|
getpostingsandvalidate
|
||||||
|
|
||||||
-- | Read postings from the command line until . is entered, using the
|
-- | Read postings from the command line until . is entered, using any
|
||||||
-- provided historical postings, if any, to guess defaults.
|
-- provided historical postings and the journal context to guess defaults.
|
||||||
getPostings :: (AccountName -> Bool) -> Maybe [Posting] -> [Posting] -> InputT IO [Posting]
|
getPostings :: JournalContext -> (AccountName -> Bool) -> Maybe [Posting] -> [Posting] -> InputT IO [Posting]
|
||||||
getPostings accept historicalps enteredps = do
|
getPostings ctx accept historicalps enteredps = do
|
||||||
account <- askFor (printf "account %d" n) defaultaccount (Just accept)
|
let bestmatch | isNothing historicalps = Nothing
|
||||||
if account=="."
|
|
||||||
then return enteredps
|
|
||||||
else do
|
|
||||||
amountstr <- askFor (printf "amount %d" n) defaultamount validateamount
|
|
||||||
let amount = fromparse $ parse (someamount <|> return missingamt) "" amountstr
|
|
||||||
let p = nullposting{paccount=stripbrackets account,
|
|
||||||
pamount=amount,
|
|
||||||
ptype=postingtype account}
|
|
||||||
getPostings accept historicalps $ enteredps ++ [p]
|
|
||||||
where
|
|
||||||
n = length enteredps + 1
|
|
||||||
enteredrealps = filter isReal enteredps
|
|
||||||
bestmatch | isNothing historicalps = Nothing
|
|
||||||
| n <= length ps = Just $ ps !! (n-1)
|
| n <= length ps = Just $ ps !! (n-1)
|
||||||
| otherwise = Nothing
|
| otherwise = Nothing
|
||||||
where Just ps = historicalps
|
where Just ps = historicalps
|
||||||
defaultaccount = maybe Nothing (Just . showacctname) bestmatch
|
defaultaccount = maybe Nothing (Just . showacctname) bestmatch
|
||||||
|
account <- askFor (printf "account %d" n) defaultaccount (Just accept)
|
||||||
|
if account=="."
|
||||||
|
then return enteredps
|
||||||
|
else do
|
||||||
|
let defaultacctused = Just account == defaultaccount
|
||||||
|
historicalps' = if defaultacctused then historicalps else Nothing
|
||||||
|
bestmatch' | isNothing historicalps' = Nothing
|
||||||
|
| n <= length ps = Just $ ps !! (n-1)
|
||||||
|
| otherwise = Nothing
|
||||||
|
where Just ps = historicalps'
|
||||||
|
defaultamountstr | isJust bestmatch' = Just $ showMixedAmountWithPrecision maxprecision $ pamount $ fromJust bestmatch'
|
||||||
|
| n > 1 = Just balancingamountstr
|
||||||
|
| otherwise = Nothing
|
||||||
|
where balancingamountstr = showMixedAmountWithPrecision maxprecision $ negate $ sumMixedAmountsPreservingHighestPrecision $ map pamount enteredrealps
|
||||||
|
amountstr <- askFor (printf "amount %d" n) defaultamountstr validateamount
|
||||||
|
let amount = setMixedAmountPrecision maxprecision $ fromparse $ runParser (someamount <|> return missingamt) ctx "" amountstr
|
||||||
|
defaultamtused = Just (showMixedAmount amount) == defaultamountstr
|
||||||
|
historicalps'' = if defaultamtused then historicalps' else Nothing
|
||||||
|
commodityadded | showMixedAmountWithPrecision maxprecision amount == amountstr = Nothing
|
||||||
|
| otherwise = maybe Nothing (Just . commodity) $ headMay $ amounts amount
|
||||||
|
p = nullposting{paccount=stripbrackets account,
|
||||||
|
pamount=amount,
|
||||||
|
ptype=postingtype account}
|
||||||
|
when (isJust commodityadded) $
|
||||||
|
liftIO $ hPutStrLn stderr $ printf "using default commodity (%s)" (symbol $ fromJust commodityadded)
|
||||||
|
getPostings ctx accept historicalps'' $ enteredps ++ [p]
|
||||||
|
where
|
||||||
|
n = length enteredps + 1
|
||||||
|
enteredrealps = filter isReal enteredps
|
||||||
showacctname p = showAccountName Nothing (ptype p) $ paccount p
|
showacctname p = showAccountName Nothing (ptype p) $ paccount p
|
||||||
defaultamount = maybe balancingamount (Just . show . pamount) bestmatch
|
|
||||||
where balancingamount = Just $ show $ negate $ sumMixedAmountsPreservingHighestPrecision $ map pamount enteredrealps
|
|
||||||
postingtype ('[':_) = BalancedVirtualPosting
|
postingtype ('[':_) = BalancedVirtualPosting
|
||||||
postingtype ('(':_) = VirtualPosting
|
postingtype ('(':_) = VirtualPosting
|
||||||
postingtype _ = RegularPosting
|
postingtype _ = RegularPosting
|
||||||
stripbrackets = dropWhile (`elem` "([") . reverse . dropWhile (`elem` "])") . reverse
|
stripbrackets = dropWhile (`elem` "([") . reverse . dropWhile (`elem` "])") . reverse
|
||||||
validateamount = Just $ \s -> (null s && not (null enteredrealps))
|
validateamount = Just $ \s -> (null s && not (null enteredrealps))
|
||||||
|| isRight (parse (someamount>>many spacenonewline>>eof) "" s)
|
|| isRight (runParser (someamount>>many spacenonewline>>eof) ctx "" s)
|
||||||
|
|
||||||
-- | Prompt for and read a string value, optionally with a default value
|
-- | Prompt for and read a string value, optionally with a default value
|
||||||
-- and a validator. A validator causes the prompt to repeat until the
|
-- and a validator. A validator causes the prompt to repeat until the
|
||||||
|
|||||||
@ -9,6 +9,7 @@ import Hledger.Cli.Version (versionstr)
|
|||||||
import Hledger.Data.Types (Journal,AccountName,Transaction(..),Posting(..),PostingType(..))
|
import Hledger.Data.Types (Journal,AccountName,Transaction(..),Posting(..),PostingType(..))
|
||||||
import Hledger.Data.Utils (strip, spacenonewline, restofline, parseWithCtx, assertParse, assertParseEqual, error')
|
import Hledger.Data.Utils (strip, spacenonewline, restofline, parseWithCtx, assertParse, assertParseEqual, error')
|
||||||
import Hledger.Read.Journal (someamount,ledgeraccountname)
|
import Hledger.Read.Journal (someamount,ledgeraccountname)
|
||||||
|
import Hledger.Data.Journal (nullctx)
|
||||||
import Hledger.Data.Amount (nullmixedamt)
|
import Hledger.Data.Amount (nullmixedamt)
|
||||||
import Safe (atDef, maximumDef)
|
import Safe (atDef, maximumDef)
|
||||||
import System.IO (stderr)
|
import System.IO (stderr)
|
||||||
@ -281,7 +282,7 @@ transactionFromCsvRecord rules fields =
|
|||||||
strnegate s = '-':s
|
strnegate s = '-':s
|
||||||
currency = maybe (fromMaybe "" $ baseCurrency rules) (atDef "" fields) (currencyField rules)
|
currency = maybe (fromMaybe "" $ baseCurrency rules) (atDef "" fields) (currencyField rules)
|
||||||
amountstr'' = currency ++ amountstr'
|
amountstr'' = currency ++ amountstr'
|
||||||
amountparse = parse someamount "" amountstr''
|
amountparse = runParser someamount nullctx "" amountstr''
|
||||||
amount = either (const nullmixedamt) id amountparse
|
amount = either (const nullmixedamt) id amountparse
|
||||||
unknownacct | (readDef 0 amountstr' :: Double) < 0 = "income:unknown"
|
unknownacct | (readDef 0 amountstr' :: Double) < 0 = "income:unknown"
|
||||||
| otherwise = "expenses:unknown"
|
| otherwise = "expenses:unknown"
|
||||||
|
|||||||
15
tests/add-default-commodity.test
Normal file
15
tests/add-default-commodity.test
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
# add should use the (final) default commodity if any
|
||||||
|
# disabled as add currently requires ctrl-c to terminate
|
||||||
|
#
|
||||||
|
# printf 'D £1000.00\n' >add-default-commodity-$$.j; hledger -fadd-default-commodity-$$.j add; rm -f add-default-commodity-$$.j
|
||||||
|
# <<<
|
||||||
|
# 2010/1/1
|
||||||
|
|
||||||
|
# a
|
||||||
|
# 1000
|
||||||
|
# b
|
||||||
|
# >>>
|
||||||
|
# 2010/01/01 y
|
||||||
|
# a £1000.00
|
||||||
|
# b £-1000.00
|
||||||
|
|
||||||
Loading…
Reference in New Issue
Block a user