From 34736b0a6c1f89f20f00b49c5a24083554a1bbfd Mon Sep 17 00:00:00 2001 From: Nicolas Martinelli Date: Wed, 7 Jun 2017 16:39:42 +1000 Subject: [PATCH] [FIX] resource: force start_dt Set up: - Use the usual working schedule from 8:00 to 12:00 and 13:00 to 17:00. - Set the OS and user TZ to Australia/Sidney TZ (restart your browser) - Create a BOM with 3 work orders, taking 1, 2 and 3 minutes (you can use the 'Assemble Furniture' routing) - Create a MO using the previously created BOM, e.g. for '[FURN001] Computer Desk' Case 1: Plan to start the next day at 08:00, e.g. 2017-06-08 The result is amazing. The system probably hit a flaw in the space-time continuum, which can only be explained with M-theory: - WO1 is planned from 2017-06-08 08:00:00 to 2017-06-07 08:01:00 - WO2 is planned from 2017-06-07 08:01:00 to 2017-06-06 08:02:00 - WO3 is planned from 2017-06-06 08:02:00 to 2017-06-05 08:03:00 Case 2: Plan to start the next day at 11:00, e.g. 2017-06-08 Once again, the result is literally a piece of art: - WO1 is planned from 2017-06-08 11:00:00 to 2017-06-08 08:01:00 - WO2 is planned from 2017-06-08 08:01:00 to 2017-06-07 08:02:00 - WO3 is planned from 2017-06-07 08:02:00 to 2017-06-06 08:03:00 To solve the problem, a first commit is made in MRP to force the end date to be larger than the start date. That hides the issue, but it doesn't solve it. To prevent the system to hit the 88 mph and go back in time, we force a 'hard limit' to prevent any selection of intervals starting before the requested start time. opw-745905 --- addons/resource/models/resource.py | 21 +++++++++++++++- addons/resource/tests/test_resource.py | 34 ++++++++++++++++++++++++++ 2 files changed, 54 insertions(+), 1 deletion(-) diff --git a/addons/resource/models/resource.py b/addons/resource/models/resource.py index a29c8bdd2a5..36f22ea1ffa 100644 --- a/addons/resource/models/resource.py +++ b/addons/resource/models/resource.py @@ -304,6 +304,11 @@ class ResourceCalendar(models.Model): elif start_dt is None: start_dt = datetime.datetime.now().replace(hour=0, minute=0, second=0, microsecond=0) else: + # FORWARD-PORT UP TO SAAS-14 + # Add a strict limit when searching for intervals + force_start_dt = self.env.context.get('force_start_dt') + if force_start_dt and force_start_dt < start_dt: + work_limits.append((force_start_dt.replace(hour=0, minute=0, second=0, microsecond=0), force_start_dt)) work_limits.append((start_dt.replace(hour=0, minute=0, second=0, microsecond=0), start_dt)) if end_dt is None: end_dt = start_dt.replace(hour=23, minute=59, second=59, microsecond=999999) @@ -335,7 +340,15 @@ class ResourceCalendar(models.Model): dt_t.replace(tzinfo=tz_info).astimezone(pytz.UTC).replace(tzinfo=None), calendar_working_day.id ) - working_intervals += self.interval_remove_leaves(working_interval, work_limits) + + # FORWARD-PORT UP TO SAAS-14 + # Add a strict limit when searching for intervals (yeah, once again!) + if self.env.context.get('force_start_dt'): + for wi in self.interval_remove_leaves(working_interval, work_limits): + if wi[0] >= self.env.context['force_start_dt']: + working_intervals += [wi] + else: + working_intervals += self.interval_remove_leaves(working_interval, work_limits) # find leave intervals if leaves is None and compute_leaves: @@ -423,6 +436,12 @@ class ResourceCalendar(models.Model): """ if day_dt is None: day_dt = datetime.datetime.now() + elif day_dt is not None and hours > 0: + # FORWARD-PORT UP TO SAAS-14 + # FIXME: think about a better fix... However, solved from saas-15 thanks to refactoring + # Make sure the to keep the original start date when searching for intervals, since a + # difference in day may occur depending on the TZ. + self = self.with_context(force_start_dt=day_dt) backwards = (hours < 0) hours = abs(hours) intervals = [] diff --git a/addons/resource/tests/test_resource.py b/addons/resource/tests/test_resource.py index 9fd6dddf8a8..971b9d3b575 100644 --- a/addons/resource/tests/test_resource.py +++ b/addons/resource/tests/test_resource.py @@ -477,6 +477,40 @@ class TestResource(TestResourceCommon): resource_id = self.env.ref('resource.resource_analyst').copy() self.assertTrue(resource_id, 'Unable to Duplicate Resource') + # FORWARD-PORT UP TO SAAS-14 + # Test already in Saas-15 + def test_80_resource_schedule_tz(self): + # Call schedule_hours for a user in Autralia, Sydney (GMT+10) + # Two cases: + # - start at 2013-02-15 08:00:00 => 2013-02-14 21:00:00 in UTC + # - start at 2013-02-15 11:00:00 => 2013-02-15 00:00:00 in UTC + + tz_context = dict(tz='Australia/Sydney') + self.env.user.with_context(tz_context).write({'tz': 'Australia/Sydney'}) + calendar = self.calendar.with_context(tz_context) + + self.env['resource.calendar.attendance'].create({ + 'name': 'Day3 - 1', + 'dayofweek': '3', + 'hour_from': 8, + 'hour_to': 12, + 'calendar_id': calendar.id, + }) + self.env['resource.calendar.attendance'].create({ + 'name': 'Day3 - 2', + 'dayofweek': '3', + 'hour_from': 13, + 'hour_to': 17, + 'calendar_id': calendar.id, + }) + + hours = 1.0/60.0 + start_dt = Datetime.from_string('2013-02-14 21:00:00') + res = calendar.schedule_hours(hours, start_dt) + self.assertEqual([(start_dt, start_dt.replace(minute=1))], res, 'resource_calendar: wrong schedule_hours computation') + start_dt = Datetime.from_string('2013-02-15 00:00:00') + res = calendar.schedule_hours(hours, start_dt) + self.assertEqual([(start_dt, start_dt.replace(minute=1))], res, 'resource_calendar: wrong schedule_hours computation') WAR_START = date(1932, 11, 2) WAR_END = date(1932, 12, 10)