]> git.walde.dev - punch/commitdiff
Add groups
authorDustin Walde <redacted>
Tue, 25 Apr 2023 17:15:08 +0000 (10:15 -0700)
committerDustin Walde <redacted>
Tue, 25 Apr 2023 17:15:08 +0000 (10:15 -0700)
tt.py

diff --git a/tt.py b/tt.py
index c0cdbfb6ef3b458209a4c2ff4b5aa6f3011cf749..62e1f47a68523bcbb98f2244864b4ad57d08829a 100755 (executable)
--- a/tt.py
+++ b/tt.py
@@ -12,10 +12,15 @@ import time
 
 from typing import (
     Dict,
+    Iterable,
     List,
+    Optional,
+    Tuple,
+    Union,
     )
 
-TimeEntries = Dict[str,List[List[str]]]
+GroupNode = Tuple[str,List[Iterable['GroupNode']]]
+TimeEntries = Dict[str,List[Union[List[str],GroupNode]]]
 
 TS_PATH='/home/users/.local/share/dwalde/time-sheet.csv'
 
@@ -69,28 +74,61 @@ 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(1, len(outs)):
-        cat = outs[i]
-        print(f", ({outs[i]}: {entries[outs[i]][0][1]})", end="")
-    print("")
+    stack = [(entries['tree'], -1)]
+    while len(stack) > 0:
+        item, depth = stack.pop()
+        group_id = item[0]
+        children = item[1]
+        if depth >= 0:
+            print("\t"*depth, end='')
+            text = ""
+            if group_id in entries:
+                name = entries[group_id][0][1]
+                last = entries[group_id][-1]
+                if last[0] == 'in':
+                    text = f"\t punched in at {last[1]}"
+                print(group_id + ":\t" + name + " " + text)
+            else:
+                name = entries['groups'][group_id][0]
+                print(name)
+        for child in reversed(children):
+            stack.append((child, depth+1))
+
+
+def load_group_hierarchy(entries: TimeEntries):
+    groups = []
+    tree = ('', [])
+    id_to_node = {'' : tree}
+    entries['groups'] = {}
+    if '' in entries:
+        for entry in entries['']:
+            if len(entry) < 2:
+                continue
+            if entry[0] == 'group':
+                groups.append(entry)
+                entries['groups'][entry[1]] = entry[2:]
+        for cat in entries.keys():
+            if cat != '' and cat != 'groups':
+                groups.append([entries[cat][0][0]] + [cat] + entries[cat][0][1:])
+        last_process = 0
+        while len(groups) > 0 and last_process != len(groups):
+            skipped = []
+            for group in groups:
+                parent = ''
+                if len(group) > 3:
+                    parent = group[3]
+                if parent in id_to_node:
+                    id_to_node[parent][1].append((group[1], []))
+                    id_to_node[group[1]] = id_to_node[parent][1][-1]
+                else:
+                    skipped.append(group)
+            last_process = len(groups)
+            groups = skipped
+
+        for v in id_to_node.values():
+            v[1].sort()
+
+    entries['tree'] = tree
 
 
 def load_file():
@@ -105,6 +143,7 @@ def load_file():
                 if row[0] not in entries:
                     entries[row[0]] = []
                 entries[row[0]].append(row[1:])
+            load_group_hierarchy(entries)
     except FileNotFoundError:
         pass
     return entries
@@ -118,11 +157,13 @@ def save_file(entries: TimeEntries):
     with open(TS_PATH, 'w', encoding='utf-8') as file:
         writer = csv.writer(file)
         for category, items in entries.items():
+            if category == 'tree' or category == 'groups':
+                continue
             for item in items:
                 writer.writerow([category] + item)
 
 
-def new_category(entries: TimeEntries, category_id: str, category_name: str):
+def new_category(entries: TimeEntries, category_id: str, category_name: str, parent: Optional[str]):
     '''
     Create a new category with name and id/abbreviation.
     '''
@@ -130,7 +171,24 @@ def new_category(entries: TimeEntries, category_id: str, category_name: str):
         print(f'{category_id} already created: {entries[category_id][0]}')
         exit(2)
 
-    append_entry([category_id, 'category', category_name])
+    if parent is None:
+        parent = ''
+
+    append_entry([category_id, 'category', category_name, parent])
+
+
+def new_group(entries: TimeEntries, group_id: str,
+              group_name: str, parent: Optional[str]):
+    if 'groups' in entries:
+        for group in entries['groups']:
+            if group[1] == group_id:
+                print(f'{group_id} alread exists.')
+                exit(2)
+
+    if parent is None:
+        parent = ''
+
+    append_entry(['', 'group', group_id, group_name, parent])
 
 
 def punch(entries: TimeEntries, dir: str, category: str, args: List[str] = []):
@@ -173,6 +231,8 @@ def try_punch_out(entries: TimeEntries) -> bool:
     category = None
 
     for cat, items in entries.items():
+        if cat == '' or cat == 'groups' or cat == 'tree':
+            continue
         if items[-1][0] == 'in':
             if category is not None:
                 print(f'At least two categories punched in ({category}, {cat}), please specify.')
@@ -215,6 +275,8 @@ def query_data(entries: TimeEntries, args: List[str]):
 
     total_time = datetime.timedelta(seconds=0)
     for cat in categories:
+        if cat == '' or cat == 'groups' or cat == 'tree':
+            continue
         td = datetime.timedelta(seconds=0)
         punch_in = None
 
@@ -282,10 +344,22 @@ def main(args):
     entries = load_file()
 
     if args[1] == 'new':
-        if len(args) < 4:
-            print('Missing args for new category: <id> <name>')
-            exit(1)
-        new_category(entries, args[2], args[3])
+        if args[2] == 'group':
+            if len(args) < 5:
+                print('Missing args for new group: <id> <name> [<parent>]')
+                exit(1)
+            parent = None
+            if len(args) > 5:
+                parent = args[5]
+            new_group(entries, args[3], args[4], parent)
+        else:
+            if len(args) < 4:
+                print('Missing args for new category: <id> <name> [<parent>]')
+                exit(1)
+            parent = None
+            if len(args) > 4:
+                parent = args[4]
+            new_category(entries, args[2], args[3], parent)
 
     elif args[1] == 'out':
         if len(args) < 3: