diff --git a/hledger-lib/Hledger/Data/Timeclock.hs b/hledger-lib/Hledger/Data/Timeclock.hs index b0a9fb821..09fb0407a 100644 --- a/hledger-lib/Hledger/Data/Timeclock.hs +++ b/hledger-lib/Hledger/Data/Timeclock.hs @@ -28,7 +28,6 @@ import Hledger.Data.Types import Hledger.Data.Dates import Hledger.Data.Amount import Hledger.Data.Posting -import Hledger.Data.Transaction instance Show TimeclockEntry where show t = printf "%s %s %s %s" (show $ tlcode t) (show $ tldatetime t) (tlaccount t) (tldescription t) @@ -65,10 +64,10 @@ timeclockEntriesToTransactions now [i] o' = o{tldatetime=itime{localDay=idate, localTimeOfDay=TimeOfDay 23 59 59}} i' = i{tldatetime=itime{localDay=addDays 1 idate, localTimeOfDay=midnight}} timeclockEntriesToTransactions now (i:o:rest) - | tlcode i /= In = errorExpectedCodeButGot In i - | tlcode o /= Out =errorExpectedCodeButGot Out o - | odate > idate = entryFromTimeclockInOut i o' : timeclockEntriesToTransactions now (i':o:rest) - | otherwise = entryFromTimeclockInOut i o : timeclockEntriesToTransactions now rest + | tlcode i /= In = errorExpectedCodeButGot In i + | tlcode o /= Out = errorExpectedCodeButGot Out o + | odate > idate = entryFromTimeclockInOut i o' : timeclockEntriesToTransactions now (i':o:rest) + | otherwise = entryFromTimeclockInOut i o : timeclockEntriesToTransactions now rest where (itime,otime) = (tldatetime i,tldatetime o) (idate,odate) = (localDay itime,localDay otime) @@ -76,10 +75,16 @@ timeclockEntriesToTransactions now (i:o:rest) i' = i{tldatetime=itime{localDay=addDays 1 idate, localTimeOfDay=midnight}} {- HLINT ignore timeclockEntriesToTransactions -} -errorExpectedCodeButGot expected actual = errorWithSourceLine line $ "expected timeclock code " ++ (show expected) ++ " but got " ++ show (tlcode actual) - where line = unPos . sourceLine $ tlsourcepos actual - -errorWithSourceLine line msg = error $ "line " ++ show line ++ ": " ++ msg +errorExpectedCodeButGot :: TimeclockCode -> TimeclockEntry -> a +errorExpectedCodeButGot expected actual = error' $ printf + ("%s:\n%s\n\nExpected timeclock %s entry but got %s.\n" + ++"Only one session may be clocked in at a time, so please alternate i and o.") + (sourcePosPretty $ tlsourcepos actual) + (show l ++ " | " ++ show actual) + (show expected) + (show $ tlcode actual) + where + l = unPos $ sourceLine $ tlsourcepos actual -- | Convert a timeclock clockin and clockout entry to an equivalent journal -- transaction, representing the time expenditure. Note this entry is not balanced, @@ -87,9 +92,18 @@ errorWithSourceLine line msg = error $ "line " ++ show line ++ ": " ++ msg entryFromTimeclockInOut :: TimeclockEntry -> TimeclockEntry -> Transaction entryFromTimeclockInOut i o | otime >= itime = t - | otherwise = error' . T.unpack $ - "clock-out time less than clock-in time in:\n" <> showTransaction t -- PARTIAL: + | otherwise = + -- Clockout time earlier than clockin is an error. + -- (Clockin earlier than preceding clockin/clockout is allowed.) + error' $ printf + ("%s:\n%s\nThis clockout time (%s) is earlier than the previous clockin.\n" + ++"Please adjust it to be later than %s.") + (sourcePosPretty $ tlsourcepos o) + (unlines [replicate (length l) ' '++ " | " ++ show i, l ++ " | " ++ show o]) + (show $ tldatetime o) + (show $ tldatetime i) where + l = show $ unPos $ sourceLine $ tlsourcepos o t = Transaction { tindex = 0, tsourcepos = (tlsourcepos i, tlsourcepos i), diff --git a/hledger/test/errors/tcclockouttime.timeclock b/hledger/test/errors/tcclockouttime.timeclock new file mode 100755 index 000000000..c59585d94 --- /dev/null +++ b/hledger/test/errors/tcclockouttime.timeclock @@ -0,0 +1,5 @@ +#!/usr/bin/env -S hledger check -f +# Clockout time before previous clockin. + +i 2022/01/01 00:01:00 +o 2022/01/01 00:00:00 diff --git a/hledger/test/errors/tcorderedactions.timeclock b/hledger/test/errors/tcorderedactions.timeclock new file mode 100755 index 000000000..7998291ea --- /dev/null +++ b/hledger/test/errors/tcorderedactions.timeclock @@ -0,0 +1,8 @@ +#!/usr/bin/env -S hledger check -f +# Clockin/clockout out of order: +# two clockins without intervening clockout, +# two clockouts without intervening clockin, +# or an initial clockout with no preceding clockin. + +i 2022/01/01 00:00:00 +i 2022/01/01 00:01:00