From e94a1dd2f95e9d7b77920e3b4cf898bfd63b99be Mon Sep 17 00:00:00 2001 From: "Abdelouahab (abla)" Date: Thu, 22 Feb 2024 16:27:47 +0000 Subject: [PATCH] [FIX] project: fix closing recurring task to reproduce: ============= - make a task recureent - change its state to a closing one -> Validation Error Problem: ======== - when creating the next occurence, we insert the followers of the original task in the new one, but it happens that we create a `mail_followers` twice which violates an SQL constraint of `mail_followers`. https://github.com/odoo/odoo/blob/ea170be9089ee6c784664475ac4ec1218d23dccd/addons/mail/models/mail_thread.py#L253-L262 the create method will create `mail_followers` for the task and as the condition that follows is truthy in this use-case `_insert_followers` will be called and create `mail_followers` again. - In previous versions we didn't face this issue because the creation of occurences was done by a cron, so the condition was never truthy thanks to `and self.env.user.active`. Solution: ========= to make sure the conditon stays falsy, we set `mail_create_nosubscribe` in context to `True` when creating the next occurence. opw-3742737 closes odoo/odoo#156945 X-original-commit: 64ca453bc36740ce4afcd46c1afbbb31abffdf7c Signed-off-by: Xavier Bol (xbo) Signed-off-by: Abdelouahab Laaroussi (abla) --- .../project/models/project_task_recurrence.py | 2 ++ .../project/tests/test_project_recurrence.py | 33 ++++++++++++++++++- 2 files changed, 34 insertions(+), 1 deletion(-) diff --git a/addons/project/models/project_task_recurrence.py b/addons/project/models/project_task_recurrence.py index 307101250a1..f47a0569e56 100644 --- a/addons/project/models/project_task_recurrence.py +++ b/addons/project/models/project_task_recurrence.py @@ -81,6 +81,8 @@ class ProjectTaskRecurrence(models.Model): def _create_next_occurrence(self, occurrence_from): self.ensure_one() + # Prevent double mail_followers creation + self = self.with_context(mail_create_nosubscribe=True) self.env['project.task'].sudo().create( self._create_next_occurrence_values(occurrence_from) ) diff --git a/addons/project/tests/test_project_recurrence.py b/addons/project/tests/test_project_recurrence.py index 2d3417110ce..383f6807e09 100644 --- a/addons/project/tests/test_project_recurrence.py +++ b/addons/project/tests/test_project_recurrence.py @@ -1,6 +1,7 @@ # -*- coding: utf-8 -*- from odoo import fields +from odoo.tests import users from odoo.tests.common import Form, TransactionCase from datetime import datetime, time @@ -13,7 +14,19 @@ class TestProjectRecurrence(TransactionCase): def setUpClass(cls): super(TestProjectRecurrence, cls).setUpClass() - cls.env.user.groups_id += cls.env.ref('project.group_project_recurring_tasks') + user_group_employee = cls.env.ref('base.group_user') + user_group_project_user = cls.env.ref('project.group_project_user') + user_group_project_recurring_task = cls.env.ref('project.group_project_recurring_tasks') + Users = cls.env['res.users'].with_context({'no_reset_password': True}) + + cls.env.user.groups_id += user_group_project_recurring_task + cls.user_projectuser = Users.create({ + 'name': 'Armande ProjectUser', + 'login': 'armandel', + 'password': 'armandel', + 'email': 'armande.projectuser@example.com', + 'groups_id': [(6, 0, [user_group_employee.id, user_group_project_user.id, user_group_project_recurring_task.id])] + }) cls.stage_a = cls.env['project.task.type'].create({'name': 'a'}) cls.stage_b = cls.env['project.task.type'].create({'name': 'b'}) @@ -146,3 +159,21 @@ class TestProjectRecurrence(TransactionCase): self.assertFalse(any((task_a + task_b + task_c).mapped('recurring_task')), "All tasks in the recurrence should have their recurrence disabled") + + @users('armandel') + def test_closed_recurring_task(self): + """ + When an active user closes a recurring task, the next occurrence should be created + """ + form = Form(self.env['project.task']) + form.name = 'test recurring task' + form.project_id = self.project_recurring + form.recurring_task = True + form.repeat_interval = 1 + form.repeat_unit = 'day' + form.repeat_type = 'forever' + task = form.save() + + self.assertEqual(len(task.recurrence_id.task_ids), 1, "recurrence should have a single task") + task.state = '1_done' + self.assertEqual(len(task.recurrence_id.task_ids), 2, "a new occurrence should have been created")