diff --git a/addons/project/models/project_task_recurrence.py b/addons/project/models/project_task_recurrence.py index ce8c553c40f..7d23669ad64 100644 --- a/addons/project/models/project_task_recurrence.py +++ b/addons/project/models/project_task_recurrence.py @@ -226,10 +226,19 @@ class ProjectTaskRecurrence(models.Model): def _set_next_recurrence_date(self): today = fields.Date.today() tomorrow = today + relativedelta(days=1) - for recurrence in self.filtered(lambda r: r.repeat_type == 'after' and r.recurrence_left > 0 or r.repeat_type == 'until' and r.repeat_until >= today or r.repeat_type == 'forever'): - next_date = self._get_next_recurring_dates(tomorrow, recurrence.repeat_interval, recurrence.repeat_unit, recurrence.repeat_type, recurrence.repeat_until, recurrence.repeat_on_month, recurrence.repeat_on_year, recurrence._get_weekdays(), recurrence.repeat_day, recurrence.repeat_week, recurrence.repeat_month, count=1) - recurrence.next_recurrence_date = next_date[0] if next_date else False + for recurrence in self.filtered( + lambda r: + r.repeat_type == 'after' and r.recurrence_left >= 0 + or r.repeat_type == 'until' and r.repeat_until >= today + or r.repeat_type == 'forever' + ): + if recurrence.repeat_type == 'after' and recurrence.recurrence_left == 0: + recurrence.next_recurrence_date = False + else: + next_date = self._get_next_recurring_dates(tomorrow, recurrence.repeat_interval, recurrence.repeat_unit, recurrence.repeat_type, recurrence.repeat_until, recurrence.repeat_on_month, recurrence.repeat_on_year, recurrence._get_weekdays(), recurrence.repeat_day, recurrence.repeat_week, recurrence.repeat_month, count=1) + recurrence.next_recurrence_date = next_date[0] if next_date else False + @api.model def _cron_create_recurring_tasks(self): if not self.env.user.has_group('project.group_project_recurring_tasks'): return diff --git a/addons/project/tests/test_project_recurrence.py b/addons/project/tests/test_project_recurrence.py index 92c9355b0a7..1ba1d961f0d 100644 --- a/addons/project/tests/test_project_recurrence.py +++ b/addons/project/tests/test_project_recurrence.py @@ -7,8 +7,8 @@ from odoo import fields from datetime import date, datetime from dateutil.rrule import MO, TU, WE, TH, FR, SA, SU +from freezegun import freeze_time -from unittest.mock import patch class TestProjectrecurrence(TransactionCase): @classmethod @@ -32,7 +32,7 @@ class TestProjectrecurrence(TransactionCase): self.env.cr.execute("UPDATE project_task SET create_date=%s WHERE id=%s", (create_date, task_id)) def test_recurrence_simple(self): - with patch.object(fields.Date, 'today', lambda: datetime(2020, 2, 1)): + with freeze_time("2020-02-01"): with Form(self.env['project.task']) as form: form.name = 'test recurring task' form.project_id = self.project_recurring @@ -57,7 +57,8 @@ class TestProjectrecurrence(TransactionCase): self.assertFalse(bool(task.recurrence_id), 'the recurrence should be deleted') def test_recurrence_cron(self): - with patch.object(fields.Date, 'today', lambda: datetime(2020, 1, 1)): + domain = [('project_id', '=', self.project_recurring.id)] + with freeze_time("2020-01-01"): form = Form(self.env['project.task']) form.name = 'test recurring task' form.description = 'my super recurring task bla bla bla' @@ -75,22 +76,27 @@ class TestProjectrecurrence(TransactionCase): task.planned_hours = 2 self.assertEqual(task.recurrence_id.next_recurrence_date, date(2020, 1, 15)) - self.assertEqual(self.env['project.task'].search_count([('project_id', '=', self.project_recurring.id)]), 1) + self.assertEqual(self.env['project.task'].search_count(domain), 1) self.env['project.task.recurrence']._cron_create_recurring_tasks() - self.assertEqual(self.env['project.task'].search_count([('project_id', '=', self.project_recurring.id)]), 1, 'no extra task should be created') + self.assertEqual(self.env['project.task'].search_count(domain), 1, 'no extra task should be created') self.assertEqual(task.recurrence_id.recurrence_left, 2) - with patch.object(fields.Date, 'today', lambda: datetime(2020, 1, 15)): - self.assertEqual(self.env['project.task'].search_count([('project_id', '=', self.project_recurring.id)]), 1) + with freeze_time("2020-01-15"): + self.assertEqual(self.env['project.task'].search_count(domain), 1) self.env['project.task.recurrence']._cron_create_recurring_tasks() - self.assertEqual(self.env['project.task'].search_count([('project_id', '=', self.project_recurring.id)]), 2) + self.assertEqual(self.env['project.task'].search_count(domain), 2) self.assertEqual(task.recurrence_id.recurrence_left, 1) - with patch.object(fields.Date, 'today', lambda: datetime(2020, 2, 15)): + with freeze_time("2020-02-15"): self.env['project.task.recurrence']._cron_create_recurring_tasks() + self.assertEqual(self.env['project.task'].search_count(domain), 3) + self.assertEqual(task.recurrence_id.recurrence_left, 0) + self.env['project.task.recurrence']._cron_create_recurring_tasks() + self.assertEqual(self.env['project.task'].search_count(domain), 3) self.assertEqual(task.recurrence_id.recurrence_left, 0) - tasks = self.env['project.task'].search([('project_id', '=', self.project_recurring.id)]) + + tasks = self.env['project.task'].search(domain) self.assertEqual(len(tasks), 3) self.assertTrue(bool(tasks[2].date_deadline)) @@ -100,7 +106,7 @@ class TestProjectrecurrence(TransactionCase): self.assertTrue(tasks[0][f] == tasks[1][f] == tasks[2][f], "Field %s should have been copied" % f) def test_recurrence_update_task(self): - with patch.object(fields.Date, 'today', lambda: datetime(2020, 1, 1)): + with freeze_time("2020-01-01"): task = self.env['project.task'].create({ 'name': 'test recurring task', 'project_id': self.project_recurring.id, @@ -112,10 +118,10 @@ class TestProjectrecurrence(TransactionCase): 'mon': True, }) - with patch.object(fields.Date, 'today', lambda: datetime(2020, 1, 6)): + with freeze_time("2020-01-06"): self.env['project.task.recurrence']._cron_create_recurring_tasks() - with patch.object(fields.Date, 'today', lambda: datetime(2020, 1, 13)): + with freeze_time("2020-01-13"): self.env['project.task.recurrence']._cron_create_recurring_tasks() task_c, task_b, task_a = self.env['project.task'].search([('project_id', '=', self.project_recurring.id)])