1 {-| 2 3 A 'TimeLogEntry' is a clock-in, clock-out, or other directive in a timelog 4 file (see timeclock.el or the command-line version). These can be 5 converted to 'LedgerTransactions' and queried like a ledger. 6 7 -} 8 9 module Ledger.TimeLog 10 where 11 import Ledger.Utils 12 import Ledger.Types 13 import Ledger.Dates 14 import Ledger.Commodity 15 import Ledger.Amount 16 import Ledger.LedgerTransaction 17 18 instance Show TimeLogEntry where 19 show t = printf "%s %s %s" (show $ tlcode t) (show $ tldatetime t) (tlcomment t) 20 21 instance Show TimeLogCode where 22 show SetBalance = "b" 23 show SetRequiredHours = "h" 24 show In = "i" 25 show Out = "o" 26 show FinalOut = "O" 27 28 instance Read TimeLogCode where 29 readsPrec _ ('b' : xs) = [(SetBalance, xs)] 30 readsPrec _ ('h' : xs) = [(SetRequiredHours, xs)] 31 readsPrec _ ('i' : xs) = [(In, xs)] 32 readsPrec _ ('o' : xs) = [(Out, xs)] 33 readsPrec _ ('O' : xs) = [(FinalOut, xs)] 34 readsPrec _ _ = [] 35 36 -- | Convert time log entries to ledger transactions. When there is no 37 -- clockout, add one with the provided current time. Sessions crossing 38 -- midnight are split into days to give accurate per-day totals. 39 entriesFromTimeLogEntries :: LocalTime -> [TimeLogEntry] -> [LedgerTransaction] 40 entriesFromTimeLogEntries _ [] = [] 41 entriesFromTimeLogEntries now [i] 42 | odate > idate = [entryFromTimeLogInOut i o'] ++ entriesFromTimeLogEntries now [i',o] 43 | otherwise = [entryFromTimeLogInOut i o] 44 where 45 o = TimeLogEntry Out end "" 46 end = if itime > now then itime else now 47 (itime,otime) = (tldatetime i,tldatetime o) 48 (idate,odate) = (localDay itime,localDay otime) 49 o' = o{tldatetime=itime{localDay=idate, localTimeOfDay=TimeOfDay 23 59 59}} 50 i' = i{tldatetime=itime{localDay=addDays 1 idate, localTimeOfDay=midnight}} 51 entriesFromTimeLogEntries now (i:o:rest) 52 | odate > idate = [entryFromTimeLogInOut i o'] ++ entriesFromTimeLogEntries now (i':o:rest) 53 | otherwise = [entryFromTimeLogInOut i o] ++ entriesFromTimeLogEntries now rest 54 where 55 (itime,otime) = (tldatetime i,tldatetime o) 56 (idate,odate) = (localDay itime,localDay otime) 57 o' = o{tldatetime=itime{localDay=idate, localTimeOfDay=TimeOfDay 23 59 59}} 58 i' = i{tldatetime=itime{localDay=addDays 1 idate, localTimeOfDay=midnight}} 59 60 -- | Convert a timelog clockin and clockout entry to an equivalent ledger 61 -- entry, representing the time expenditure. Note this entry is not balanced, 62 -- since we omit the \"assets:time\" transaction for simpler output. 63 entryFromTimeLogInOut :: TimeLogEntry -> TimeLogEntry -> LedgerTransaction 64 entryFromTimeLogInOut i o 65 | otime >= itime = t 66 | otherwise = 67 error $ "clock-out time less than clock-in time in:\n" ++ showLedgerTransaction t 68 where 69 t = LedgerTransaction { 70 ltdate = idate, 71 ltstatus = True, 72 ltcode = "", 73 ltdescription = showtime itod ++ "-" ++ showtime otod, 74 ltcomment = "", 75 ltpostings = ps, 76 ltpreceding_comment_lines="" 77 } 78 showtime = take 5 . show 79 acctname = tlcomment i 80 itime = tldatetime i 81 otime = tldatetime o 82 itod = localTimeOfDay itime 83 otod = localTimeOfDay otime 84 idate = localDay itime 85 odate = localDay otime 86 hrs = elapsedSeconds (toutc otime) (toutc itime) / 3600 where toutc = localTimeToUTC utc 87 amount = Mixed [hours hrs] 88 ps = [Posting False acctname amount "" RegularPosting 89 --,Posting "assets:time" (-amount) "" RegularPosting 90 ]