summaryrefslogtreecommitdiff
path: root/addons/project/tests/test_project_recurrence.py
diff options
context:
space:
mode:
Diffstat (limited to 'addons/project/tests/test_project_recurrence.py')
-rw-r--r--addons/project/tests/test_project_recurrence.py460
1 files changed, 460 insertions, 0 deletions
diff --git a/addons/project/tests/test_project_recurrence.py b/addons/project/tests/test_project_recurrence.py
new file mode 100644
index 00000000..63090189
--- /dev/null
+++ b/addons/project/tests/test_project_recurrence.py
@@ -0,0 +1,460 @@
+# -*- coding: utf-8 -*-
+
+
+from odoo.tests.common import SavepointCase, Form
+from odoo.exceptions import ValidationError
+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
+
+
+class TestProjectrecurrence(SavepointCase):
+ @classmethod
+ def setUpClass(cls):
+ super(TestProjectrecurrence, cls).setUpClass()
+
+ cls.env.user.groups_id += cls.env.ref('project.group_project_recurring_tasks')
+
+ cls.stage_a = cls.env['project.task.type'].create({'name': 'a'})
+ cls.stage_b = cls.env['project.task.type'].create({'name': 'b'})
+ cls.project_recurring = cls.env['project.project'].with_context({'mail_create_nolog': True}).create({
+ 'name': 'Recurring',
+ 'allow_recurring_tasks': True,
+ 'type_ids': [
+ (4, cls.stage_a.id),
+ (4, cls.stage_b.id),
+ ]
+ })
+
+ def set_task_create_date(self, task_id, create_date):
+ self.env.cr.execute("UPDATE project_task SET create_date=%s WHERE id=%s", (create_date, task_id))
+
+ def test_recurrence_simple(self):
+ 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
+
+ form.recurring_task = True
+ form.repeat_interval = 5
+ form.repeat_unit = 'month'
+ form.repeat_type = 'after'
+ form.repeat_number = 10
+ form.repeat_on_month = 'date'
+ form.repeat_day = '31'
+ task = form.save()
+ self.assertTrue(bool(task.recurrence_id), 'should create a recurrence')
+
+ task.write(dict(repeat_interval=2, repeat_number=11))
+ self.assertEqual(task.recurrence_id.repeat_interval, 2, 'recurrence should be updated')
+ self.assertEqual(task.recurrence_id.repeat_number, 11, 'recurrence should be updated')
+ self.assertEqual(task.recurrence_id.recurrence_left, 11)
+ self.assertEqual(task.recurrence_id.next_recurrence_date, date(2020, 2, 29))
+
+ task.recurring_task = False
+ self.assertFalse(bool(task.recurrence_id), 'the recurrence should be deleted')
+
+ def test_recurrence_cron_repeat_after(self):
+ 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'
+ form.project_id = self.project_recurring
+ form.date_deadline = datetime(2020, 2, 1)
+
+ form.recurring_task = True
+ form.repeat_interval = 1
+ form.repeat_unit = 'month'
+ form.repeat_type = 'after'
+ form.repeat_number = 2
+ form.repeat_on_month = 'date'
+ form.repeat_day = '15'
+ task = form.save()
+ task.planned_hours = 2
+
+ self.assertEqual(task.recurrence_id.next_recurrence_date, date(2020, 1, 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(domain), 1, 'no extra task should be created')
+ self.assertEqual(task.recurrence_id.recurrence_left, 2)
+
+ 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(domain), 2)
+ self.assertEqual(task.recurrence_id.recurrence_left, 1)
+
+ 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(domain)
+ self.assertEqual(len(tasks), 3)
+
+ self.assertTrue(bool(tasks[2].date_deadline))
+ self.assertFalse(tasks[1].date_deadline, "Deadline should not be copied")
+
+ for f in self.env['project.task.recurrence']._get_recurring_fields():
+ self.assertTrue(tasks[0][f] == tasks[1][f] == tasks[2][f], "Field %s should have been copied" % f)
+
+ def test_recurrence_cron_repeat_until(self):
+ 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'
+ form.project_id = self.project_recurring
+ form.date_deadline = datetime(2020, 2, 1)
+
+ form.recurring_task = True
+ form.repeat_interval = 1
+ form.repeat_unit = 'month'
+ form.repeat_type = 'until'
+ form.repeat_until = date(2020, 2, 20)
+ form.repeat_on_month = 'date'
+ form.repeat_day = '15'
+ task = form.save()
+ task.planned_hours = 2
+
+ self.assertEqual(task.recurrence_id.next_recurrence_date, date(2020, 1, 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(domain), 1, 'no extra task should be created')
+
+ 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(domain), 2)
+
+ 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.env['project.task.recurrence']._cron_create_recurring_tasks()
+ self.assertEqual(self.env['project.task'].search_count(domain), 3)
+
+ tasks = self.env['project.task'].search(domain)
+ self.assertEqual(len(tasks), 3)
+
+ self.assertTrue(bool(tasks[2].date_deadline))
+ self.assertFalse(tasks[1].date_deadline, "Deadline should not be copied")
+
+ for f in self.env['project.task.recurrence']._get_recurring_fields():
+ self.assertTrue(tasks[0][f] == tasks[1][f] == tasks[2][f], "Field %s should have been copied" % f)
+
+ def test_recurrence_cron_repeat_forever(self):
+ 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'
+ form.project_id = self.project_recurring
+ form.date_deadline = datetime(2020, 2, 1)
+
+ form.recurring_task = True
+ form.repeat_interval = 1
+ form.repeat_unit = 'month'
+ form.repeat_type = 'forever'
+ form.repeat_on_month = 'date'
+ form.repeat_day = '15'
+ task = form.save()
+ task.planned_hours = 2
+
+ self.assertEqual(task.recurrence_id.next_recurrence_date, date(2020, 1, 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(domain), 1, 'no extra task should be created')
+
+ 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(domain), 2)
+
+ 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)
+
+ with freeze_time("2020-02-16"):
+ self.env['project.task.recurrence']._cron_create_recurring_tasks()
+ self.assertEqual(self.env['project.task'].search_count(domain), 3)
+
+ with freeze_time("2020-02-17"):
+ self.env['project.task.recurrence']._cron_create_recurring_tasks()
+ self.assertEqual(self.env['project.task'].search_count(domain), 3)
+
+ with freeze_time("2020-02-17"):
+ self.env['project.task.recurrence']._cron_create_recurring_tasks()
+ self.assertEqual(self.env['project.task'].search_count(domain), 3)
+
+ with freeze_time("2020-03-15"):
+ self.env['project.task.recurrence']._cron_create_recurring_tasks()
+ self.assertEqual(self.env['project.task'].search_count(domain), 4)
+
+ tasks = self.env['project.task'].search(domain)
+ self.assertEqual(len(tasks), 4)
+
+ self.assertTrue(bool(tasks[3].date_deadline))
+ self.assertFalse(tasks[1].date_deadline, "Deadline should not be copied")
+
+ for f in self.env['project.task.recurrence']._get_recurring_fields():
+ self.assertTrue(
+ tasks[0][f] == tasks[1][f] == tasks[2][f] == tasks[3][f],
+ "Field %s should have been copied" % f)
+
+ def test_recurrence_update_task(self):
+ with freeze_time("2020-01-01"):
+ task = self.env['project.task'].create({
+ 'name': 'test recurring task',
+ 'project_id': self.project_recurring.id,
+ 'recurring_task': True,
+ 'repeat_interval': 1,
+ 'repeat_unit': 'week',
+ 'repeat_type': 'after',
+ 'repeat_number': 2,
+ 'mon': True,
+ })
+
+ with freeze_time("2020-01-06"):
+ self.env['project.task.recurrence']._cron_create_recurring_tasks()
+
+ 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)])
+
+ self.set_task_create_date(task_a.id, datetime(2020, 1, 1))
+ self.set_task_create_date(task_b.id, datetime(2020, 1, 6))
+ self.set_task_create_date(task_c.id, datetime(2020, 1, 13))
+ (task_a+task_b+task_c).invalidate_cache()
+
+ task_c.write({
+ 'name': 'my super updated task',
+ 'recurrence_update': 'all',
+ })
+
+ self.assertEqual(task_a.name, 'my super updated task')
+ self.assertEqual(task_b.name, 'my super updated task')
+ self.assertEqual(task_c.name, 'my super updated task')
+
+ task_a.write({
+ 'name': 'don\'t you dare change my title',
+ 'recurrence_update': 'this',
+ })
+
+ self.assertEqual(task_a.name, 'don\'t you dare change my title')
+ self.assertEqual(task_b.name, 'my super updated task')
+ self.assertEqual(task_c.name, 'my super updated task')
+
+ task_b.write({
+ 'description': 'hello!',
+ 'recurrence_update': 'subsequent',
+ })
+
+ self.assertEqual(task_a.description, False)
+ self.assertEqual(task_b.description, '<p>hello!</p>')
+ self.assertEqual(task_c.description, '<p>hello!</p>')
+
+ def test_recurrence_fields_visibility(self):
+ form = Form(self.env['project.task'])
+
+ form.name = 'test recurring task'
+ form.project_id = self.project_recurring
+ form.recurring_task = True
+
+ form.repeat_unit = 'week'
+ self.assertTrue(form.repeat_show_dow)
+ self.assertFalse(form.repeat_show_day)
+ self.assertFalse(form.repeat_show_week)
+ self.assertFalse(form.repeat_show_month)
+
+ form.repeat_unit = 'month'
+ form.repeat_on_month = 'date'
+ self.assertFalse(form.repeat_show_dow)
+ self.assertTrue(form.repeat_show_day)
+ self.assertFalse(form.repeat_show_week)
+ self.assertFalse(form.repeat_show_month)
+
+ form.repeat_unit = 'month'
+ form.repeat_on_month = 'day'
+ self.assertFalse(form.repeat_show_dow)
+ self.assertFalse(form.repeat_show_day)
+ self.assertTrue(form.repeat_show_week)
+ self.assertFalse(form.repeat_show_month)
+
+ form.repeat_unit = 'year'
+ form.repeat_on_year = 'date'
+ self.assertFalse(form.repeat_show_dow)
+ self.assertTrue(form.repeat_show_day)
+ self.assertFalse(form.repeat_show_week)
+ self.assertTrue(form.repeat_show_month)
+
+ form.repeat_unit = 'year'
+ form.repeat_on_year = 'day'
+ self.assertFalse(form.repeat_show_dow)
+ self.assertFalse(form.repeat_show_day)
+ self.assertTrue(form.repeat_show_week)
+ self.assertTrue(form.repeat_show_month)
+
+ form.recurring_task = False
+ self.assertFalse(form.repeat_show_dow)
+ self.assertFalse(form.repeat_show_day)
+ self.assertFalse(form.repeat_show_week)
+ self.assertFalse(form.repeat_show_month)
+
+ def test_recurrence_week_day(self):
+ form = Form(self.env['project.task'])
+
+ form.name = 'test recurring task'
+ form.project_id = self.project_recurring
+ form.recurring_task = True
+ form.repeat_unit = 'week'
+
+ form.mon = False
+ form.tue = False
+ form.wed = False
+ form.thu = False
+ form.fri = False
+ form.sat = False
+ form.sun = False
+
+ with self.assertRaises(ValidationError), self.cr.savepoint():
+ form.save()
+
+ def test_recurrence_next_dates_week(self):
+ dates = self.env['project.task.recurrence']._get_next_recurring_dates(
+ date_start=date(2020, 1, 1),
+ repeat_interval=1,
+ repeat_unit='week',
+ repeat_type=False,
+ repeat_until=False,
+ repeat_on_month=False,
+ repeat_on_year=False,
+ weekdays=False,
+ repeat_day=False,
+ repeat_week=False,
+ repeat_month=False,
+ count=5)
+
+ self.assertEqual(dates[0], datetime(2020, 1, 6, 0, 0))
+ self.assertEqual(dates[1], datetime(2020, 1, 13, 0, 0))
+ self.assertEqual(dates[2], datetime(2020, 1, 20, 0, 0))
+ self.assertEqual(dates[3], datetime(2020, 1, 27, 0, 0))
+ self.assertEqual(dates[4], datetime(2020, 2, 3, 0, 0))
+
+ dates = self.env['project.task.recurrence']._get_next_recurring_dates(
+ date_start=date(2020, 1, 1),
+ repeat_interval=3,
+ repeat_unit='week',
+ repeat_type='until',
+ repeat_until=date(2020, 2, 1),
+ repeat_on_month=False,
+ repeat_on_year=False,
+ weekdays=[MO, FR],
+ repeat_day=False,
+ repeat_week=False,
+ repeat_month=False,
+ count=100)
+
+ self.assertEqual(len(dates), 3)
+ self.assertEqual(dates[0], datetime(2020, 1, 3, 0, 0))
+ self.assertEqual(dates[1], datetime(2020, 1, 20, 0, 0))
+ self.assertEqual(dates[2], datetime(2020, 1, 24, 0, 0))
+
+ def test_recurrence_next_dates_month(self):
+ dates = self.env['project.task.recurrence']._get_next_recurring_dates(
+ date_start=date(2020, 1, 15),
+ repeat_interval=1,
+ repeat_unit='month',
+ repeat_type=False, # Forever
+ repeat_until=False,
+ repeat_on_month='date',
+ repeat_on_year=False,
+ weekdays=False,
+ repeat_day=31,
+ repeat_week=False,
+ repeat_month=False,
+ count=12)
+
+ # should take the last day of each month
+ self.assertEqual(dates[0], date(2020, 1, 31))
+ self.assertEqual(dates[1], date(2020, 2, 29))
+ self.assertEqual(dates[2], date(2020, 3, 31))
+ self.assertEqual(dates[3], date(2020, 4, 30))
+ self.assertEqual(dates[4], date(2020, 5, 31))
+ self.assertEqual(dates[5], date(2020, 6, 30))
+ self.assertEqual(dates[6], date(2020, 7, 31))
+ self.assertEqual(dates[7], date(2020, 8, 31))
+ self.assertEqual(dates[8], date(2020, 9, 30))
+ self.assertEqual(dates[9], date(2020, 10, 31))
+ self.assertEqual(dates[10], date(2020, 11, 30))
+ self.assertEqual(dates[11], date(2020, 12, 31))
+
+ dates = self.env['project.task.recurrence']._get_next_recurring_dates(
+ date_start=date(2020, 2, 20),
+ repeat_interval=3,
+ repeat_unit='month',
+ repeat_type=False, # Forever
+ repeat_until=False,
+ repeat_on_month='date',
+ repeat_on_year=False,
+ weekdays=False,
+ repeat_day=29,
+ repeat_week=False,
+ repeat_month=False,
+ count=5)
+
+ self.assertEqual(dates[0], date(2020, 2, 29))
+ self.assertEqual(dates[1], date(2020, 5, 29))
+ self.assertEqual(dates[2], date(2020, 8, 29))
+ self.assertEqual(dates[3], date(2020, 11, 29))
+ self.assertEqual(dates[4], date(2021, 2, 28))
+
+ dates = self.env['project.task.recurrence']._get_next_recurring_dates(
+ date_start=date(2020, 1, 10),
+ repeat_interval=1,
+ repeat_unit='month',
+ repeat_type='until',
+ repeat_until=datetime(2020, 5, 31),
+ repeat_on_month='day',
+ repeat_on_year=False,
+ weekdays=[SA(4), ], # 4th Saturday
+ repeat_day=29,
+ repeat_week=False,
+ repeat_month=False,
+ count=6)
+
+ self.assertEqual(len(dates), 5)
+ self.assertEqual(dates[0], datetime(2020, 1, 25))
+ self.assertEqual(dates[1], datetime(2020, 2, 22))
+ self.assertEqual(dates[2], datetime(2020, 3, 28))
+ self.assertEqual(dates[3], datetime(2020, 4, 25))
+ self.assertEqual(dates[4], datetime(2020, 5, 23))
+
+ def test_recurrence_next_dates_year(self):
+ dates = self.env['project.task.recurrence']._get_next_recurring_dates(
+ date_start=date(2020, 12, 1),
+ repeat_interval=1,
+ repeat_unit='year',
+ repeat_type='until',
+ repeat_until=datetime(2026, 1, 1),
+ repeat_on_month=False,
+ repeat_on_year='date',
+ weekdays=False,
+ repeat_day=31,
+ repeat_week=False,
+ repeat_month='november',
+ count=10)
+
+ self.assertEqual(len(dates), 5)
+ self.assertEqual(dates[0], datetime(2021, 11, 30))
+ self.assertEqual(dates[1], datetime(2022, 11, 30))
+ self.assertEqual(dates[2], datetime(2023, 11, 30))
+ self.assertEqual(dates[3], datetime(2024, 11, 30))
+ self.assertEqual(dates[4], datetime(2025, 11, 30))