From 0f8fcb56dadd1bddf4030b62fb61458e31251e66 Mon Sep 17 00:00:00 2001 From: "Xavier Bol (xbo)" Date: Fri, 2 Jun 2023 14:48:29 +0000 Subject: [PATCH] [FIX] project: fix planned date removal of projects This commit's purpose is to allow the user to remove the planned date end, or the planned date start of a project from the list view, or the form view of the project. If the user removes either the planned date end, or the planned date start, both dates will be removed. If the user tries to add only a date end or a date start while keeping the other date empty on a project with no planned date, these changes will be discarded. The goal of this fix is for the projects to always have either both dates set, or both dates set to False. closes odoo/odoo#130651 X-original-commit: 250a0d233c8c2e074b967d59d53b1d4aac5feba2 Related: odoo/enterprise#45131 Signed-off-by: Xavier Bol (xbo) --- addons/project/models/project_project.py | 22 +++++ addons/project/tests/test_project_base.py | 98 +++++++++++++++++++ .../sale_timesheet/data/sale_service_demo.xml | 1 - 3 files changed, 120 insertions(+), 1 deletion(-) diff --git a/addons/project/models/project_project.py b/addons/project/models/project_project.py index 6a8ab98a1e8..e07d0aeb8ba 100644 --- a/addons/project/models/project_project.py +++ b/addons/project/models/project_project.py @@ -379,6 +379,13 @@ class Project(models.Model): else: project.access_instruction_message = '' + @api.onchange('date_start', 'date') + def _onchange_planned_date(self): + if not self.date and self.date_start: + self.date_start = False + elif not self.date_start and self.date: + self.date = False + @api.model def _map_tasks_default_valeus(self, task, project): """ get the default value for the copied task on project duplication """ @@ -466,6 +473,21 @@ class Project(models.Model): if vals.get('privacy_visibility'): self._change_privacy_visibility(vals['privacy_visibility']) + date_start = vals.get('date_start', True) + date_end = vals.get('date', True) + if not date_start or not date_end: + vals['date_start'] = False + vals['date'] = False + else: + no_current_date_begin = not all(project.date_start for project in self) + no_current_date_end = not all(project.date for project in self) + date_start_update = 'date_start' in vals + date_end_update = 'date' in vals + if (date_start_update and no_current_date_end and not date_end_update): + del vals['date_start'] + elif (date_end_update and no_current_date_begin and not date_start_update): + del vals['date'] + res = super(Project, self).write(vals) if vals else True if 'allow_task_dependencies' in vals and not vals.get('allow_task_dependencies'): diff --git a/addons/project/tests/test_project_base.py b/addons/project/tests/test_project_base.py index 731928bc4da..ec4d40e8701 100644 --- a/addons/project/tests/test_project_base.py +++ b/addons/project/tests/test_project_base.py @@ -2,6 +2,7 @@ from lxml import etree +from odoo import fields from odoo.osv import expression from odoo.tests import users from odoo.tests.common import TransactionCase @@ -248,3 +249,100 @@ class TestProjectBase(TestProjectCommon): self.project_pigs.rating_ids.invalidate_recordset() self.assertEqual(len(self.project_pigs.rating_ids), 1, "There should be 1 rating linked to the project") + + def test_planned_dates_consistency_for_project(self): + """ This test ensures that a project can not have date start set, + if its date end is False and that it can not have a date end + set if its date start is False . + """ + self.assertFalse(self.project_goats.date_start) + self.assertFalse(self.project_goats.date) + + self.project_goats.write({'date_start': '2021-09-27', 'date': '2021-09-28'}) + self.assertEqual(fields.Date.to_string(self.project_goats.date_start), '2021-09-27', "The start date should be set.") + self.assertEqual(fields.Date.to_string(self.project_goats.date), '2021-09-28', "The expiration date should be set.") + + self.project_goats.date_start = False + self.assertFalse(fields.Date.to_string(self.project_goats.date_start), "The start date should be unset.") + self.assertFalse(fields.Date.to_string(self.project_goats.date), "The expiration date should be unset as well.") + + self.project_goats.write({'date_start': '2021-09-27', 'date': '2021-09-28'}) + self.project_goats.date = False + self.assertFalse(fields.Date.to_string(self.project_goats.date), "The expiration date should be unset.") + self.assertFalse(fields.Date.to_string(self.project_goats.date_start), "The start date should be unset as well.") + + self.project_goats.write({'date_start': '2021-09-27'}) + self.assertFalse(fields.Date.to_string(self.project_goats.date_start), "The start date should be unset since expiration date if not set.") + self.assertFalse(fields.Date.to_string(self.project_goats.date), "The expiration date should stay be unset.") + + self.project_goats.write({'date': '2021-09-28'}) + self.assertFalse(fields.Date.to_string(self.project_goats.date), "The expiration date should be unset since the start date if not set.") + self.assertFalse(fields.Date.to_string(self.project_goats.date_start), "The start date should be unset.") + + self.project_pigs.write({'date_start': '2021-09-23', 'date': '2021-09-24'}) + + # Case 1: one project has date range set and the other one has no date range set. + projects = self.project_goats + self.project_pigs + projects.write({'date_start': '2021-09-27', 'date': '2021-09-28'}) + for p in projects: + self.assertEqual(fields.Date.to_string(p.date_start), '2021-09-27', f'The start date of {p.name} should be updated.') + self.assertEqual(fields.Date.to_string(p.date), '2021-09-28', f'The expiration date of {p.name} should be updated.') + self.project_goats.date_start = False + projects.write({'date_start': '2021-09-30'}) + self.assertFalse(fields.Date.to_string(self.project_goats.date_start), 'The start date should not be updated') + self.assertFalse(fields.Date.to_string(self.project_goats.date), 'The expiration date should not be updated') + self.assertEqual(fields.Date.to_string(self.project_pigs.date_start), '2021-09-27', 'The start date should not be updated.') + self.assertEqual(fields.Date.to_string(self.project_pigs.date), '2021-09-28', 'The expiration date should not be updated.') + projects.write({'date_start': False}) + for p in projects: + self.assertFalse(fields.Date.to_string(p.date_start), f'The start date of {p.name} should be set to False.') + self.assertFalse(fields.Date.to_string(p.date), f'The expiration date of {p.name} should be set to False.') + self.project_pigs.write({'date_start': '2021-09-27', 'date': '2021-09-28'}) + projects.write({'date': False}) + for p in projects: + self.assertFalse(fields.Date.to_string(p.date_start), f'The start date of {p.name} should be set to False.') + self.assertFalse(fields.Date.to_string(p.date), f'The expiration date of {p.name} should be set to False.') + + # Case 2: both projects have no date range set + projects.write({'date_start': '2021-09-27'}) + for p in projects: + self.assertFalse(fields.Date.to_string(p.date_start), f'The start date of {p.name} should not be updated.') + self.assertFalse(fields.Date.to_string(p.date), f'The expiration date of {p.name} should not be updated.') + projects.write({'date': '2021-09-28'}) + for p in projects: + self.assertFalse(fields.Date.to_string(p.date_start), f'The start date of {p.name} should not be updated.') + self.assertFalse(fields.Date.to_string(p.date), f'The expiration date of {p.name} should not be updated.') + + projects.write({'date_start': '2021-09-27', 'date': '2021-09-28'}) + for p in projects: + self.assertEqual(fields.Date.to_string(p.date_start), '2021-09-27', f'The start date of {p.name} should be updated.') + self.assertEqual(fields.Date.to_string(p.date), '2021-09-28', f'The expiration date of {p.name} should be updated.') + + # Case 3: both projects have a different date range set + self.project_pigs.write({'date_start': '2021-09-23', 'date': '2021-09-30'}) + projects.write({'date_start': '2021-09-22'}) + self.assertEqual(fields.Date.to_string(self.project_goats.date_start), '2021-09-22', 'The start date should be updated.') + self.assertEqual(fields.Date.to_string(self.project_goats.date), '2021-09-28', 'The expiration date should not be updated.') + self.assertEqual(fields.Date.to_string(self.project_pigs.date_start), '2021-09-22', 'The start date should be updated.') + self.assertEqual(fields.Date.to_string(self.project_pigs.date), '2021-09-30', 'The expiration date should not be updated.') + projects.write({'date': '2021-09-29'}) + self.assertEqual(fields.Date.to_string(self.project_goats.date_start), '2021-09-22', 'The start date should not be updated.') + self.assertEqual(fields.Date.to_string(self.project_goats.date), '2021-09-29', 'The expiration date should be updated.') + self.assertEqual(fields.Date.to_string(self.project_pigs.date_start), '2021-09-22', 'The start date should not be updated.') + self.assertEqual(fields.Date.to_string(self.project_pigs.date), '2021-09-29', 'The expiration date should be updated.') + projects.write({'date_start': False}) + for p in projects: + self.assertFalse(fields.Date.to_string(p.date_start), f'The start date of {p.name} should be set to False.') + self.assertFalse(fields.Date.to_string(p.date), f'The expiration date of {p.name} should be set to False.') + self.project_goats.write({'date_start': '2021-09-27', 'date': '2021-09-28'}) + self.project_pigs.write({'date_start': '2021-09-23', 'date': '2021-09-30'}) + projects.write({'date': False}) + for p in projects: + self.assertFalse(fields.Date.to_string(p.date_start), f'The start date of {p.name} should be set to False.') + self.assertFalse(fields.Date.to_string(p.date), f'The expiration date of {p.name} should be set to False.') + self.project_goats.write({'date_start': '2021-09-27', 'date': '2021-09-28'}) + self.project_pigs.write({'date_start': '2021-09-23', 'date': '2021-09-30'}) + projects.write({'date_start': '2021-09-25', 'date': '2021-09-26'}) + for p in projects: + self.assertEqual(fields.Date.to_string(p.date_start), '2021-09-25', f'The start date of {p.name} should be updated.') + self.assertEqual(fields.Date.to_string(p.date), '2021-09-26', f'The expiration date of {p.name} should be updated.') diff --git a/addons/sale_timesheet/data/sale_service_demo.xml b/addons/sale_timesheet/data/sale_service_demo.xml index 3955b79cc9f..d5a10e8df88 100644 --- a/addons/sale_timesheet/data/sale_service_demo.xml +++ b/addons/sale_timesheet/data/sale_service_demo.xml @@ -28,7 +28,6 @@ - After-Sales Services Services provided to customers who have purchased products.