[FIX] project : traceback with multi-company

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) <xbo@odoo.com>
This commit is contained in:
luve-odoo
2023-10-13 15:54:25 +00:00
parent 85b5ddfc0d
commit 7cf8b9f4ae
2 changed files with 24 additions and 18 deletions
+23 -9
View File
@@ -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:
@@ -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")