]> git.walde.dev - punch/commitdiff
Add improved listing and querying
authorDustin Walde <redacted>
Fri, 20 Jan 2023 05:40:37 +0000 (21:40 -0800)
committerDustin Walde <redacted>
Fri, 20 Jan 2023 05:40:37 +0000 (21:40 -0800)
- Query time totals since date
- List current state of categories
- Other minor improvements

tt.py

diff --git a/tt.py b/tt.py
index 362bcdedc7c5eff8c29cce56850cf811f14dfaad..741269d1f675b8d682b49d3a02b043b578d057a7 100755 (executable)
--- a/tt.py
+++ b/tt.py
@@ -65,6 +65,34 @@ def list_entries(entries: TimeEntries):
         list_category(entries, cat)
 
 
+def list_status(entries: TimeEntries):
+    '''
+    Print each punched in category, followed by the rest.
+    '''
+    cats = list(entries.keys())
+    cats.sort()
+
+    outs = []
+    print("In:")
+    for cat in cats:
+        if entries[cat][-1][0] == 'in':
+            list_category(entries, cat)
+        else:
+            outs.append(cat)
+
+    if len(cats) == len(outs):
+        print("No categories punched in.")
+
+    if len(outs) > 0:
+        print("")
+        print("Out:")
+        print(f"({outs[0]}: {entries[outs[0]][0][1]})", end="")
+    for i in range(len(outs)):
+        cat = outs[i]
+        print(f", ({outs[i]}: {entries[outs[i]][0][1]})", end="")
+    print("")
+
+
 def load_file():
     '''
     Loads the current state of the time sheet into memory.
@@ -105,7 +133,7 @@ def new_category(entries: TimeEntries, category_id: str, category_name: str):
     append_entry([category_id, 'category', category_name])
 
 
-def punch(entries: TimeEntries, dir: str, category: str):
+def punch(entries: TimeEntries, dir: str, category: str, args: List[str] = []):
     '''
     Attempt to add and entry to punch a category in or out.
     _dir_ is the string 'in' or 'out'.
@@ -124,14 +152,21 @@ def punch(entries: TimeEntries, dir: str, category: str):
         exit(3)
 
     now = datetime.datetime.now()
-    now = datetime.datetime.now(now.astimezone().tzinfo)
-    entry = [category, dir, now.isoformat()]
+    if len(args) < 2 or args[0] != "at":
+        time = datetime.datetime.now(now.astimezone().tzinfo)
+    else:
+        time = datetime.datetime.combine(datetime.date.today(),
+                                         datetime.time(
+                                             hour=int(args[1].split(':')[0]),
+                                             minute=int(args[1].split(':')[1]),
+                                             tzinfo=now.astimezone().tzinfo))
+    entry = [category, dir, time.isoformat()]
     append_entry(entry)
     entries[category].append(entry[1:])
     list_category(entries, category)
 
 
-def try_punch_out(entries: TimeEntries):
+def try_punch_out(entries: TimeEntries) -> bool:
     '''
     Checks if exactly one category is currently punched in and punches it out.
     '''
@@ -146,9 +181,54 @@ def try_punch_out(entries: TimeEntries):
 
     if category is None:
         print('No categories punched in.')
-        exit(2)
+        return False
 
     punch(entries, 'out', category)
+    return True
+
+
+# Query options
+
+def query_data(entries: TimeEntries, args: List[str]):
+    categories = []
+    i = 0
+    arg = None
+    start = None
+
+    while i < len(args):
+        if arg == 'total':
+            if args[i] == 'all':
+                categories.extend(entries.keys())
+            else:
+                categories.append(args[i])
+            arg = None
+
+        elif arg == 'from':
+            start = datetime.datetime.fromisoformat(args[i]).astimezone()
+            arg = None
+
+        else:
+            if args[i] in { 'total', 'from' }:
+                arg = args[i]
+
+        i += 1
+
+    for cat in categories:
+        td = datetime.timedelta(seconds=0)
+        punch_in = None
+
+        for entry in entries[cat]:
+            if punch_in is None and entry[0] == 'in':
+                time = datetime.datetime.fromisoformat(entry[1])
+                if start is None or time >= start:
+                    punch_in = time
+
+            elif punch_in is not None and entry[0] == 'out':
+                time = datetime.datetime.fromisoformat(entry[1])
+                td += time - punch_in
+                punch_in = None
+
+        print(f"{cat}:\t{td}")
 
 
 # Service specific
@@ -172,7 +252,7 @@ def run_service():
                     if now - last_notify[cat] > datetime.timedelta(minutes=30):
                         clock = now - punch
                         hours = int(clock.seconds/60/60)
-                        minutes = int(clock.seconds/60)
+                        minutes = int(clock.seconds/60%60)
                         if hours > 0:
                             timestr = f'{hours}h {minutes}m'
                         else:
@@ -208,32 +288,29 @@ def main(args):
         if len(args) < 3:
             try_punch_out(entries)
         else:
-            punch(entries, 'out', args[2])
+            punch(entries, 'out', args[2], args[3:])
 
     elif args[1] == 'in':
         if len(args) < 3:
             print(f'Missing arg for punch in: <category>')
             exit(1)
-        punch(entries, 'in', args[2])
+        punch(entries, 'in', args[2], args[3:])
 
     elif args[1] == 'pop':
         if len(args) < 3:
-            print(f'Missing arg for pop {args[1]}: <category>')
+            print(f'Missing arg for pop {args[2]}: <category>')
             exit(1)
         if args[2] not in entries:
             print(f'Category does not exist {args[2]}.')
             exit(2)
         last_entry = entries[args[2]][-1]
-        resp = input(f"Remove entry {last_entry} [y/N]?")
+        resp = input(f"Remove entry {last_entry} [y/N]? ")
         if resp.lower() == 'y':
             entries[args[2]].pop()
             save_file(entries)
             list_category(entries, args[2])
 
     elif args[1] == 'print':
-        print(entries)
-
-    elif args[1] == 'list':
         if len(args) > 2:
             if args[2] not in entries:
                 print(f'Category does not exist {args[2]}.')
@@ -242,8 +319,18 @@ def main(args):
         else:
             list_entries(entries)
 
+    elif args[1] == 'to':
+        if len(args) < 3:
+            print(f'Missing category to punch in to.')
+            exit(1)
+        try_punch_out(entries)
+        punch(entries, 'in', args[2])
+
+    elif args[1] == 'list':
+        list_status(entries)
+
     elif args[1] == 'query':
-        pass
+        query_data(entries, args[2:])
 
 
 if __name__ == "__main__":