imp:timeclock: more informative error output for clashing sessions [#2417]

This commit is contained in:
Simon Michael 2025-08-31 17:26:15 +01:00
parent 539a876e7a
commit 04e6c140c0
4 changed files with 38 additions and 17 deletions

View File

@ -106,21 +106,28 @@ pairClockEntries (entry : rest) actives sessions
(idate, odate) = (localDay itime, localDay otime)
omidnight = entry {tldatetime = itime {localDay = idate, localTimeOfDay = TimeOfDay 23 59 59}}
imidnight = inentry {tldatetime = itime {localDay = addDays 1 idate, localTimeOfDay = midnight}}
(sessions', actives', rest') =
if odate > idate
then (Session {in' = inentry, out = omidnight} : sessions, imidnight : newactive, entry : rest)
else (Session {in' = inentry, out = entry} : sessions, newactive, rest)
l = show $ unPos $ sourceLine $ tlsourcepos entry
c = unPos $ sourceColumn $ tlsourcepos entry
inentries =
if any (\e -> tlaccount e == tlaccount entry) actives
then error' $ printf
"%s:\n%s\n%s\n\nEncountered clockin entry for session \"%s\" that is already active."
(sourcePosPretty $ tlsourcepos entry)
(l ++ " | " ++ show entry)
(replicate (length l) ' ' ++ " |" ++ replicate c ' ' ++ "^")
(tlaccount entry)
else entry : actives
(sessions', actives', rest')
| odate > idate = (Session {in' = inentry, out = omidnight} : sessions, imidnight : newactive, entry : rest)
| otherwise = (Session {in' = inentry, out = entry} : sessions, newactive, rest)
inentries = case filter ((== tlaccount entry) . tlaccount) actives of
[] -> entry : actives
activesinthisacct -> error' $ T.unpack $ makeTimeClockErrorExcerpt entry $ T.unlines $ [
"Simultaneous sessions with the same account name are not supported."
,"This clockin overlaps with:"
] <> map (flip makeTimeClockErrorExcerpt "") activesinthisacct
-- XXX better to show full session(s)
-- <> map T.show (filter ((`elem` activesinthisacct).in') sessions)
makeTimeClockErrorExcerpt :: TimeclockEntry -> T.Text -> T.Text
makeTimeClockErrorExcerpt e@TimeclockEntry{tlsourcepos=pos} msg = T.unlines [
T.pack (sourcePosPretty pos) <> ":"
,l <> " | " <> T.show e
-- ,T.replicate (T.length l) " " <> " |" -- <> T.replicate c " " <> "^")
,""
] <> msg
where
l = T.show $ unPos $ sourceLine $ tlsourcepos e
-- c = unPos $ sourceColumn $ tlsourcepos e
-- | Convert time log entries to journal transactions, allowing multiple clocked-in sessions at once.
-- This is the new, default behaviour.

View File

@ -4804,6 +4804,9 @@ $ hledger -f t.timeclock print
```
Note, you can have overlapping sessions (multiple sessions open simultaneously), but they must have different account names.
Overlapping sessions with the same account name are currently not supported currently.
Here is a
[sample.timeclock](https://raw.github.com/simonmichael/hledger/master/examples/sample.timeclock) to
download and some queries to try:

View File

@ -1,9 +1,9 @@
$$$ hledger check -f tcorderedactions.timeclock
>>>2 /Error: .*tcorderedactions.timeclock:8:1:
8 \| i 2022-01-01 00:01:00 a
\| \^
Encountered clockin entry for session "a" that is already active.
Simultaneous sessions with the same account name are not supported.
This clockin overlaps with:
/
>>>= 1

View File

@ -192,6 +192,17 @@ $ hledger -f timeclock:- print
>=
# ** 14. Sessions with the same account name may not overlap (#2417).
<
i 2024-01-01 13:00:00 a
o 2024-01-01 15:00:00
i 2024-01-01 14:00:00 a
o 2024-01-01 15:00:00
$ hledger -f timeclock:- print
>2 /Simultaneous sessions with the same account name are not supported./
>=!0
# ** OLD:
## multi-day sessions get a new transaction for each day