home · contact · privacy
Slightly improve and re-organize Condition tests.
[plomtask] / plomtask / todos.py
index 008f7a275ab42aa9bbbcfed1933c81f491854211..f5388b58f25ec1237b65b751c8fd5fa352160ddf 100644 (file)
@@ -1,7 +1,6 @@
 """Actionables."""
 from __future__ import annotations
 """Actionables."""
 from __future__ import annotations
-from dataclasses import dataclass
-from typing import Any
+from typing import Any, Set
 from sqlite3 import Row
 from plomtask.db import DatabaseConnection, BaseModel
 from plomtask.processes import Process, ProcessStepsNode
 from sqlite3 import Row
 from plomtask.db import DatabaseConnection, BaseModel
 from plomtask.processes import Process, ProcessStepsNode
@@ -12,13 +11,28 @@ from plomtask.exceptions import (NotFoundException, BadFormatException,
 from plomtask.dating import valid_date
 
 
 from plomtask.dating import valid_date
 
 
-@dataclass
 class TodoNode:
     """Collects what's useful to know for Todo/Condition tree display."""
 class TodoNode:
     """Collects what's useful to know for Todo/Condition tree display."""
+    # pylint: disable=too-few-public-methods
     todo: Todo
     seen: bool
     children: list[TodoNode]
 
     todo: Todo
     seen: bool
     children: list[TodoNode]
 
+    def __init__(self,
+                 todo: Todo,
+                 seen: bool,
+                 children: list[TodoNode]) -> None:
+        self.todo = todo
+        self.seen = seen
+        self.children = children
+
+    @property
+    def as_dict(self) -> dict[str, object]:
+        """Return self as (json.dumps-coompatible) dict."""
+        return {'todo': self.todo.id_,
+                'seen': self.seen,
+                'children': [c.as_dict for c in self.children]}
+
 
 class Todo(BaseModel[int], ConditionsRelations):
     """Individual actionable."""
 
 class Todo(BaseModel[int], ConditionsRelations):
     """Individual actionable."""
@@ -34,6 +48,13 @@ class Todo(BaseModel[int], ConditionsRelations):
                          ('todo_children', 'parent', 'children', 0),
                          ('todo_children', 'child', 'parents', 1)]
     to_search = ['comment']
                          ('todo_children', 'parent', 'children', 0),
                          ('todo_children', 'child', 'parents', 1)]
     to_search = ['comment']
+    days_to_update: Set[str] = set()
+    children: list[Todo]
+    parents: list[Todo]
+    sorters = {'doneness': lambda t: t.is_done,
+               'title': lambda t: t.title_then,
+               'comment': lambda t: t.comment,
+               'date': lambda t: t.date}
 
     # pylint: disable=too-many-arguments
     def __init__(self, id_: int | None,
 
     # pylint: disable=too-many-arguments
     def __init__(self, id_: int | None,
@@ -51,8 +72,8 @@ class Todo(BaseModel[int], ConditionsRelations):
         self.date = valid_date(date)
         self.comment = comment
         self.effort = effort
         self.date = valid_date(date)
         self.comment = comment
         self.effort = effort
-        self.children: list[Todo] = []
-        self.parents: list[Todo] = []
+        self.children = []
+        self.parents = []
         self.calendarize = calendarize
         if not self.id_:
             self.calendarize = self.process.calendarize
         self.calendarize = calendarize
         if not self.id_:
             self.calendarize = self.process.calendarize
@@ -129,11 +150,9 @@ class Todo(BaseModel[int], ConditionsRelations):
         assert isinstance(todo.id_, int)
         for t_id in db_conn.column_where('todo_children', 'child',
                                          'parent', todo.id_):
         assert isinstance(todo.id_, int)
         for t_id in db_conn.column_where('todo_children', 'child',
                                          'parent', todo.id_):
-            # pylint: disable=no-member
             todo.children += [cls.by_id(db_conn, t_id)]
         for t_id in db_conn.column_where('todo_children', 'parent',
                                          'child', todo.id_):
             todo.children += [cls.by_id(db_conn, t_id)]
         for t_id in db_conn.column_where('todo_children', 'parent',
                                          'child', todo.id_):
-            # pylint: disable=no-member
             todo.parents += [cls.by_id(db_conn, t_id)]
         for name in ('conditions', 'blockers', 'enables', 'disables'):
             table = f'todo_{name}'
             todo.parents += [cls.by_id(db_conn, t_id)]
         for name in ('conditions', 'blockers', 'enables', 'disables'):
             table = f'todo_{name}'
@@ -155,16 +174,6 @@ class Todo(BaseModel[int], ConditionsRelations):
         """Collect all Todos for Day of date."""
         return cls.by_date_range(db_conn, (date, date))
 
         """Collect all Todos for Day of date."""
         return cls.by_date_range(db_conn, (date, date))
 
-    @classmethod
-    def total_effort_at_date(cls, db_conn: DatabaseConnection, date: str
-                             ) -> float:
-        """Sum all .performed_effort of Todos at Day of date."""
-        total_effort = 0.0
-        days_todos = cls.by_date(db_conn, date)
-        for todo in days_todos:
-            total_effort += todo.performed_effort
-        return total_effort
-
     @property
     def is_doable(self) -> bool:
         """Decide whether .is_done settable based on children, Conditions."""
     @property
     def is_doable(self) -> bool:
         """Decide whether .is_done settable based on children, Conditions."""
@@ -307,12 +316,17 @@ class Todo(BaseModel[int], ConditionsRelations):
         if self.effort and self.effort < 0 and self.is_deletable:
             self.remove(db_conn)
             return
         if self.effort and self.effort < 0 and self.is_deletable:
             self.remove(db_conn)
             return
+        if self.id_ is None:
+            self.__class__.days_to_update.add(self.date)
         super().save(db_conn)
         super().save(db_conn)
+        for condition in self.enables + self.disables + self.conditions:
+            condition.save(db_conn)
 
     def remove(self, db_conn: DatabaseConnection) -> None:
         """Remove from DB, including relations."""
         if not self.is_deletable:
             raise HandledException('Cannot remove non-deletable Todo.')
 
     def remove(self, db_conn: DatabaseConnection) -> None:
         """Remove from DB, including relations."""
         if not self.is_deletable:
             raise HandledException('Cannot remove non-deletable Todo.')
+        self.__class__.days_to_update.add(self.date)
         children_to_remove = self.children[:]
         parents_to_remove = self.parents[:]
         for child in children_to_remove:
         children_to_remove = self.children[:]
         parents_to_remove = self.parents[:]
         for child in children_to_remove: