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.