imp: timeclock: support comments and tags (fix #1220)

Breaking change: previously timeclock descriptions could contain
semicolons. Now a semicolon in the description will end it and
start a comment (which may contain tags).
This commit is contained in:
Simon Michael 2023-05-02 23:35:16 -10:00
parent f7f86a709b
commit 50349f81f7
6 changed files with 48 additions and 28 deletions

View File

@ -2,5 +2,5 @@ i 2009/03/27 09:00:00 projects:a
o 2009/03/27 17:00:34 o 2009/03/27 17:00:34
i 2009/03/31 22:21:45 personal:reading:online i 2009/03/31 22:21:45 personal:reading:online
o 2009/04/01 02:00:34 o 2009/04/01 02:00:34
i 2009/04/02 09:00:00 projects:b i 2009/04/02 09:00:00 projects:b ; a comment, with tag:
o 2009/04/02 17:00:34 o 2009/04/02 17:00:34

View File

@ -57,7 +57,7 @@ timeclockEntriesToTransactions now [i]
| odate > idate = entryFromTimeclockInOut i o' : timeclockEntriesToTransactions now [i',o] | odate > idate = entryFromTimeclockInOut i o' : timeclockEntriesToTransactions now [i',o]
| otherwise = [entryFromTimeclockInOut i o] | otherwise = [entryFromTimeclockInOut i o]
where where
o = TimeclockEntry (tlsourcepos i) Out end "" "" o = TimeclockEntry (tlsourcepos i) Out end "" "" "" []
end = if itime > now then itime else now end = if itime > now then itime else now
(itime,otime) = (tldatetime i,tldatetime o) (itime,otime) = (tldatetime i,tldatetime o)
(idate,odate) = (localDay itime,localDay otime) (idate,odate) = (localDay itime,localDay otime)
@ -120,8 +120,8 @@ entryFromTimeclockInOut i o
tstatus = Cleared, tstatus = Cleared,
tcode = "", tcode = "",
tdescription = desc, tdescription = desc,
tcomment = "", tcomment = tlcomment i,
ttags = [], ttags = tltags i,
tpostings = ps, tpostings = ps,
tprecedingcomment="" tprecedingcomment=""
} }
@ -162,11 +162,11 @@ tests_Timeclock = testGroup "Timeclock" [
future = utcToLocalTime tz $ addUTCTime 100 now' future = utcToLocalTime tz $ addUTCTime 100 now'
futurestr = showtime future futurestr = showtime future
step "started yesterday, split session at midnight" step "started yesterday, split session at midnight"
txndescs [clockin (mktime yesterday "23:00:00") "" ""] @?= ["23:00-23:59","00:00-"++nowstr] txndescs [clockin (mktime yesterday "23:00:00") "" "" "" []] @?= ["23:00-23:59","00:00-"++nowstr]
step "split multi-day sessions at each midnight" step "split multi-day sessions at each midnight"
txndescs [clockin (mktime (addDays (-2) today) "23:00:00") "" ""] @?= ["23:00-23:59","00:00-23:59","00:00-"++nowstr] txndescs [clockin (mktime (addDays (-2) today) "23:00:00") "" "" "" []] @?= ["23:00-23:59","00:00-23:59","00:00-"++nowstr]
step "auto-clock-out if needed" step "auto-clock-out if needed"
txndescs [clockin (mktime today "00:00:00") "" ""] @?= ["00:00-"++nowstr] txndescs [clockin (mktime today "00:00:00") "" "" "" []] @?= ["00:00-"++nowstr]
step "use the clockin time for auto-clockout if it's in the future" step "use the clockin time for auto-clockout if it's in the future"
txndescs [clockin future "" ""] @?= [printf "%s-%s" futurestr futurestr] txndescs [clockin future "" "" "" []] @?= [printf "%s-%s" futurestr futurestr]
] ]

View File

@ -504,7 +504,9 @@ data TimeclockEntry = TimeclockEntry {
tlcode :: TimeclockCode, tlcode :: TimeclockCode,
tldatetime :: LocalTime, tldatetime :: LocalTime,
tlaccount :: AccountName, tlaccount :: AccountName,
tldescription :: Text tldescription :: Text,
tlcomment :: Text,
tltags :: [Tag]
} deriving (Eq,Ord,Generic) } deriving (Eq,Ord,Generic)
-- | A market price declaration made by the journal format's P directive. -- | A market price declaration made by the journal format's P directive.

View File

@ -45,7 +45,6 @@ i, o or O. The meanings of the codes are:
--- ** language --- ** language
{-# LANGUAGE OverloadedStrings #-} {-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE PackageImports #-}
--- ** exports --- ** exports
module Hledger.Read.TimeclockReader ( module Hledger.Read.TimeclockReader (
@ -62,13 +61,13 @@ import Control.Monad.Except (ExceptT, liftEither)
import Control.Monad.State.Strict import Control.Monad.State.Strict
import Data.Maybe (fromMaybe) import Data.Maybe (fromMaybe)
import Data.Text (Text) import Data.Text (Text)
import qualified Data.Text as T
import Text.Megaparsec hiding (parse) import Text.Megaparsec hiding (parse)
import Hledger.Data import Hledger.Data
-- XXX too much reuse ? -- XXX too much reuse ?
import Hledger.Read.Common import Hledger.Read.Common
import Hledger.Utils import Hledger.Utils
import Data.Text as T (strip)
--- ** doctest setup --- ** doctest setup
-- $setup -- $setup
@ -119,10 +118,11 @@ timeclockfilep = do many timeclockitemp
-- | Parse a timeclock entry. -- | Parse a timeclock entry.
timeclockentryp :: JournalParser m TimeclockEntry timeclockentryp :: JournalParser m TimeclockEntry
timeclockentryp = do timeclockentryp = do
sourcepos <- getSourcePos pos <- getSourcePos
code <- oneOf ("bhioO" :: [Char]) code <- oneOf ("bhioO" :: [Char])
lift skipNonNewlineSpaces1 lift skipNonNewlineSpaces1
datetime <- datetimep datetime <- datetimep
account <- fromMaybe "" <$> optional (lift skipNonNewlineSpaces1 >> modifiedaccountnamep) account <- fmap (fromMaybe "") $ optional $ lift skipNonNewlineSpaces1 >> modifiedaccountnamep
description <- T.pack . fromMaybe "" <$> lift (optional (skipNonNewlineSpaces1 >> restofline)) description <- fmap (maybe "" T.strip) $ optional $ lift $ skipNonNewlineSpaces1 >> descriptionp
return $ TimeclockEntry sourcepos (read [code]) datetime account description (comment, tags) <- lift transactioncommentp
return $ TimeclockEntry pos (read [code]) datetime account description comment tags

View File

@ -4111,9 +4111,9 @@ The timezone, if present, must be four digits and is ignored
Lines beginning with `#` or `;` or `*`, and blank lines, are ignored. Lines beginning with `#` or `;` or `*`, and blank lines, are ignored.
```timeclock ```timeclock
i 2015/03/30 09:00:00 some:account name optional description after two spaces i 2015/03/30 09:00:00 some account optional description after 2 spaces ; optional comment, tags:
o 2015/03/30 09:20:00 o 2015/03/30 09:20:00
i 2015/03/31 22:21:45 another account i 2015/03/31 22:21:45 another:account
o 2015/04/01 02:00:34 o 2015/04/01 02:00:34
``` ```
@ -4124,14 +4124,14 @@ the above time log, `hledger print` generates these journal entries:
``` shell ``` shell
$ hledger -f t.timeclock print $ hledger -f t.timeclock print
2015-03-30 * optional description after two spaces 2015-03-30 * optional description after 2 spaces ; optional comment, tags:
(some:account name) 0.33h (some account) 0.33h
2015-03-31 * 22:21-23:59 2015-03-31 * 22:21-23:59
(another account) 1.64h (another:account) 1.64h
2015-04-01 * 00:00-02:00 2015-04-01 * 00:00-02:00
(another account) 2.01h (another:account) 2.01h
``` ```

View File

@ -1,5 +1,4 @@
# 1. a timeclock session is parsed as a similarly-named transaction with one virtual posting. # 1. a timeclock session is parsed as a similarly-named transaction with one virtual posting.
# Note since 1.17 we need to specify stdin's format explicitly.
< <
i 2009/1/1 08:00:00 i 2009/1/1 08:00:00
o 2009/1/1 09:00:00 stuff on checkout record is ignored o 2009/1/1 09:00:00 stuff on checkout record is ignored
@ -8,6 +7,7 @@ i 2009/1/2 08:00:00 account name
o 2009/1/2 09:00:00 o 2009/1/2 09:00:00
i 2009/1/3 08:00:00 some:account name and a description i 2009/1/3 08:00:00 some:account name and a description
o 2009/1/3 09:00:00 o 2009/1/3 09:00:00
$ hledger -f timeclock:- print $ hledger -f timeclock:- print
> >
2009-01-01 * 08:00-09:00 2009-01-01 * 08:00-09:00
@ -19,8 +19,7 @@ $ hledger -f timeclock:- print
2009-01-03 * and a description 2009-01-03 * and a description
(some:account name) 1.00h (some:account name) 1.00h
>2 >=
>= 0
# 2. Command-line account aliases are applied. # 2. Command-line account aliases are applied.
$ hledger -ftimeclock:- print --alias '/account/=FOO' $ hledger -ftimeclock:- print --alias '/account/=FOO'
@ -33,14 +32,14 @@ $ hledger -ftimeclock:- print --alias '/account/=FOO'
2009-01-03 * and a description 2009-01-03 * and a description
(some:FOO name) 1.00h (some:FOO name) 1.00h
>= 0 >=
# 3. For a missing clock-out, now is implied # 3. For a missing clock-out, now is implied
< <
i 2020/1/1 08:00 i 2020/1/1 08:00
$ hledger -f timeclock:- balance $ hledger -f timeclock:- balance
> /./ > /./
>= 0 >=
# 4. For a log not starting with clock-out, print error # 4. For a log not starting with clock-out, print error
< <
@ -60,14 +59,33 @@ $ hledger -f timeclock:- balance
# 6. Timeclock amounts are always rounded to two decimal places, # 6. Timeclock amounts are always rounded to two decimal places,
# even when displayed by print (#1527). # even when displayed by print (#1527).
< <
i 2020-01-30 08:38:35 a i 2020-01-30 08:38:35 acct
o 2020-01-30 09:03:35 o 2020-01-30 09:03:35
$ hledger -f timeclock:- print $ hledger -f timeclock:- print
2020-01-30 * 08:38-09:03 2020-01-30 * 08:38-09:03
(a) 0.42h (acct) 0.42h
>= >=
# 7. Comments and tags are supported. Double space is required between account name
# and description or comment. It is not required between description and comment.
<
i 2023-05-01 08:00:00 acct 1 description ; a comment with tag:
o 2023-05-01 09:00:00
i 2023-05-02 08:00:00 acct 2 ; another comment
o 2023-05-02 09:00:00
$ hledger -f timeclock:- print tag:tag
2023-05-01 * description ; a comment with tag:
(acct 1) 1.00h
>=
# 8.
$ hledger -f timeclock:- accounts
acct 1
acct 2
## TODO ## TODO
## multi-day sessions get a new transaction for each day ## multi-day sessions get a new transaction for each day
#hledger -ftimeclock:- print #hledger -ftimeclock:- print