From 7cf8b9f4ae3a0ed98ff33d22321e2271a561d612 Mon Sep 17 00:00:00 2001 From: luve-odoo Date: Mon, 25 Sep 2023 17:54:50 +0200 Subject: [PATCH] [FIX] project : traceback with multi-company MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit How to reproduce: - Link 2 distinct projects to at least 2 different companies - Modify and save any setting in project settings (this action should trigger the write function of the project) --> Traceback: expected singleton Why? - If projects associated with differing companies are updated collectively, the condition self.company_id.id anticipates a singular value, but it’s possible for there to be multiple. Solution: - When we want to write a company_id on some projects, take back the ones already with the right companyc(as we don't have to change their stage) and then write the first stage found on the other records ( by putting self.company_id.ids in order to avoid the singleton exception). taskid:3520107 closes odoo/odoo#136614 Signed-off-by: Xavier Bol (xbo) --- addons/project/models/project_project.py | 32 +++++++++++++------ .../tests/test_project_stage_multicompany.py | 10 +----- 2 files changed, 24 insertions(+), 18 deletions(-) diff --git a/addons/project/models/project_project.py b/addons/project/models/project_project.py index 5e4f1fab96f..ff3f2e46fd3 100644 --- a/addons/project/models/project_project.py +++ b/addons/project/models/project_project.py @@ -218,6 +218,16 @@ class Project(models.Model): if not self.alias_enabled: self.alias_name = False + @api.onchange('company_id') + def _onchange_company_id(self): + if (self.env.user.has_group('project.group_project_stages') and self.stage_id.company_id + and self.stage_id.company_id != self.company_id): + self.stage_id = self.env['project.project.stage'].search( + [('company_id', 'in', [self.company_id.id, False])], + order=f"sequence asc, {self.env['project.project.stage']._order}", + limit=1, + ).id + def _compute_alias_enabled(self): for project in self: project.alias_enabled = bool(project.alias_email) @@ -463,15 +473,19 @@ class Project(models.Model): def write(self, vals): # Here we modify the project's stage according to the selected company (selecting the first # stage in sequence that is linked to the company). - if self.env.user.has_group('project.group_project_stages') and\ - vals.get('company_id') not in (None, self.company_id.id) and\ - self.stage_id.company_id: - ProjectStage = self.env['project.project.stage'] - vals['stage_id'] = ProjectStage.search( - [('company_id', 'in', (vals['company_id'], False))], - order=f"company_id asc, {ProjectStage._order}", - limit=1, - ).id + company_id = vals.get('company_id') + if self.env.user.has_group('project.group_project_stages') and company_id: + projects_already_with_company = self.filtered(lambda p: p.company_id.id == company_id) + if projects_already_with_company: + projects_already_with_company.write({key: value for key, value in vals.items() if key != 'company_id'}) + self -= projects_already_with_company + if company_id not in (None, *self.company_id.ids) and self.stage_id.company_id: + ProjectStage = self.env['project.project.stage'] + vals["stage_id"] = ProjectStage.search( + [('company_id', 'in', (company_id, False))], + order=f"sequence asc, {ProjectStage._order}", + limit=1, + ).id # directly compute is_favorite to dodge allow write access right if 'is_favorite' in vals: diff --git a/addons/project/tests/test_project_stage_multicompany.py b/addons/project/tests/test_project_stage_multicompany.py index 22b2c0cb4ad..05b003875f5 100644 --- a/addons/project/tests/test_project_stage_multicompany.py +++ b/addons/project/tests/test_project_stage_multicompany.py @@ -76,12 +76,4 @@ class TestProjectStagesMulticompany(TestMultiCompanyProject): project.company_id = self.company_b.id # Check that project was moved to stage_company_b - self.assertEqual(self.project_company_a.stage_id, self.stage_company_b, "Project Company A should now be in Stage Company B") - - # Here we remove the company from the stage; then changing the project's company to company A should - # move it to the first stage in sequence that is linked to no company, and not in stage company A - self.stage_company_a.company_id = False - - project.company_id = self.company_a.id - - self.assertNotEqual(self.project_company_a.stage_id, self.stage_company_a, "Project Company A should not be in Stage Company A") + self.assertFalse(self.project_company_a.stage_id.company_id, "Project Company A should now be in a stage without company")