Commit d115d38b authored by Bram Schoenmakers's avatar Bram Schoenmakers

Implement strict recurrence when completing a todo item.

Strict recurrence means that the actual due date of the todo item is
used, instead of using today's date.
parent bf81c6fe
......@@ -106,8 +106,8 @@ class DoCommandTest(CommandTest.CommandTest):
self.assertEquals(self.errors, "")
self.assertFalse(self.todolist.todo(2).is_completed())
def test_recurrence(self):
command = DoCommand.DoCommand(["4"], self.todolist, self.out, self.error)
def _recurrence_helper(self, p_flags):
command = DoCommand.DoCommand(p_flags, self.todolist, self.out, self.error)
self.assertFalse(self.todolist.todo(4).has_tag('due'))
......@@ -124,6 +124,15 @@ class DoCommandTest(CommandTest.CommandTest):
self.assertFalse(todo.is_completed())
self.assertTrue(todo.has_tag('due'))
def test_recurrence(self):
self._recurrence_helper(["4"])
def test_strict_recurrence1(self):
self._recurrence_helper(["-s", "4"])
def test_strict_recurrence2(self):
self._recurrence_helper(["--strict", "4"])
def test_invalid1(self):
command = DoCommand.DoCommand(["99"], self.todolist, self.out, self.error)
command.execute()
......
......@@ -18,7 +18,7 @@ from datetime import date, timedelta
import unittest
from Config import config
from Recurrence import advance_recurring_todo, NoRecurrenceException
from Recurrence import advance_recurring_todo, strict_advance_recurring_todo, NoRecurrenceException
import Todo
class RelativeDateTester(unittest.TestCase):
......@@ -55,13 +55,50 @@ class RelativeDateTester(unittest.TestCase):
self.assertEquals(new_todo.due_date(), new_due)
def test_noduedate(self):
def test_duedate4(self):
""" Where due date is in the past. """
past = date.today() - timedelta(8)
new_due = date.today() - timedelta(1)
self.todo.set_tag(config().tag_due(), past.isoformat())
new_todo = strict_advance_recurring_todo(self.todo)
self.assertEquals(new_todo.due_date(), new_due)
def test_duedate5(self):
""" Where due date is in the future. """
future = date.today() + timedelta(1)
new_due = date.today() + timedelta(8)
self.todo.set_tag(config().tag_due(), future.isoformat())
new_todo = strict_advance_recurring_todo(self.todo)
self.assertEquals(new_todo.due_date(), new_due)
def test_duedate6(self):
""" Where due date is today. """
today = date.today()
new_due = date.today() + timedelta(7)
self.todo.set_tag(config().tag_due(), today.isoformat())
new_todo = strict_advance_recurring_todo(self.todo)
self.assertEquals(new_todo.due_date(), new_due)
def test_noduedate1(self):
new_due = date.today() + timedelta(7)
new_todo = advance_recurring_todo(self.todo)
self.assertTrue(new_todo.has_tag(config().tag_due()))
self.assertEquals(new_todo.due_date(), new_due)
def test_noduedate2(self):
new_due = date.today() + timedelta(7)
new_todo = strict_advance_recurring_todo(self.todo)
self.assertTrue(new_todo.has_tag(config().tag_due()))
self.assertEquals(new_todo.due_date(), new_due)
def test_startdate(self):
""" Start date is before due date. """
self.todo.set_tag(config().tag_due(), date.today().isoformat())
......@@ -73,6 +110,18 @@ class RelativeDateTester(unittest.TestCase):
self.assertEquals(new_todo.start_date(), new_start)
def test_startdate(self):
""" Strict recurrence. Start date is before due date. """
due = date.today() - timedelta(1)
self.todo.set_tag(config().tag_due(), date.today().isoformat())
yesterday = due - timedelta(1)
self.todo.set_tag(config().tag_start(), yesterday.isoformat())
new_start = date.today() + timedelta(5)
new_todo = strict_advance_recurring_todo(self.todo)
self.assertEquals(new_todo.start_date(), new_start)
def test_startdate2(self):
""" Start date equals due date. """
self.todo.set_tag(config().tag_due(), date.today().isoformat())
......
......@@ -27,9 +27,23 @@ class DoCommand(DCommand):
p_prompt=lambda a: None):
super(DoCommand, self).__init__(p_args, p_todolist, p_out, p_err, p_prompt)
self.strict_recurrence = False
def get_flags(self):
""" Additional flags. """
return ("s", ["strict"])
def process_flag(self, p_opt, p_value):
if p_opt == "s" or p_opt == "--strict":
self.strict_recurrence = True
def _handle_recurrence(self):
if self.todo.has_tag('rec'):
new_todo = advance_recurring_todo(self.todo)
if self.strict_recurrence:
new_todo = strict_advance_recurring_todo(self.todo)
else:
new_todo = advance_recurring_todo(self.todo)
self.todolist.add_todo(new_todo)
self.out(pretty_print(new_todo, [self.todolist.pp_number()]))
......@@ -60,7 +74,7 @@ class DoCommand(DCommand):
self.todolist.set_todo_completed(p_todo)
def usage(self):
return """Synopsis: do [--force] <NUMBER>"""
return """Synopsis: do [--force] [--strict] <NUMBER>"""
def help(self):
return """Marks the todo with given number as complete.
......@@ -70,4 +84,10 @@ be marked as completed as well. When --force is given, no interaction is
required and the subitems are not marked completed.
In case the completed todo is recurring, a new todo will be added to the list,
while the given todo item is marked as complete."""
while the given todo item is marked as complete. The new date is calculated
based on the todo item's due date. If the due date is in the past, today's date
is used to calculate the new recurrence date. Using --strict prevents this,
then the actual due date of the todo item is used to calculate the new
recurrence date. Note that a future due date is always used as such to
calculate the new due date.
"""
......@@ -34,7 +34,7 @@ def _get_due_date(p_todo):
due = p_todo.due_date()
return due if (due and due >= date.today()) else date.today()
def advance_recurring_todo(p_todo):
def _advance_recurring_todo_helper(p_todo, p_offset):
"""
Given a Todo item, return a new instance of a Todo item with the dates
shifted according to the recurrence rule.
......@@ -48,10 +48,9 @@ def advance_recurring_todo(p_todo):
if not pattern:
raise NoRecurrenceException()
due = _get_due_date(todo)
length = todo.length()
new_due = relative_date_to_date(pattern, due)
new_due = relative_date_to_date(pattern, p_offset)
todo.set_tag(config().tag_due(), new_due.isoformat())
if todo.start_date():
......@@ -61,3 +60,19 @@ def advance_recurring_todo(p_todo):
todo.set_creation_date(date.today())
return todo
def advance_recurring_todo(p_todo):
return _advance_recurring_todo_helper(p_todo, _get_due_date(p_todo))
def strict_advance_recurring_todo(p_todo):
"""
Given a Todo item, return a new instance of a Todo item with the dates
shifted according to the recurrence rule.
Strict means that the real due date is taken as a offset, not today or a
future date to determine the offset.
When no recurrence tag is present, an exception is raised.
"""
offset = p_todo.due_date() or date.today()
return _advance_recurring_todo_helper(p_todo, offset)
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment