From 024177ebc4eace19e2ebab25dc8c4887079ebf75 Mon Sep 17 00:00:00 2001 From: Christophe Simonis Date: Fri, 11 Sep 2015 18:07:49 +0200 Subject: [PATCH 1/5] [FIX] resource: get_working_intervals_of_day Use patch from 8.0 (64e1c28e358ec06a7683249fd7fae1ba631c1933) instead of the one from 7.0 (bbd15cdca6e3bf6c92d3e230a2b7697c801a2cfb). --- addons/resource/resource.py | 15 +++++----- addons/resource/tests/common.py | 23 +++++++-------- addons/resource/tests/test_resource.py | 39 ++++++++++++++------------ 3 files changed, 40 insertions(+), 37 deletions(-) diff --git a/addons/resource/resource.py b/addons/resource/resource.py index af077e4f617..06af0b99ecf 100644 --- a/addons/resource/resource.py +++ b/addons/resource/resource.py @@ -333,15 +333,14 @@ class resource_calendar(osv.osv): intervals.append((start_dt.replace(hour=default_interval[0]), start_dt.replace(hour=default_interval[1]))) return intervals - tzinfo = fields.datetime.context_timestamp(cr, uid, work_dt, context={}).tzinfo working_intervals = [] + tz_info = fields.datetime.context_timestamp(cr, uid, work_dt, context=context).tzinfo for calendar_working_day in self.get_attendances_for_weekdays(cr, uid, id, [start_dt.weekday()], context): - hour_from = work_dt.replace(hour=int(calendar_working_day.hour_from)).replace(tzinfo=tzinfo).astimezone(pytz.UTC).hour - hour_to = work_dt.replace(hour=int(calendar_working_day.hour_to)).replace(tzinfo=tzinfo).astimezone(pytz.UTC).hour - working_interval = ( - work_dt.replace(hour=int(hour_from)), - work_dt.replace(hour=int(hour_to)) - ) + x = work_dt.replace(hour=int(calendar_working_day.hour_from)) + y = work_dt.replace(hour=int(calendar_working_day.hour_to)) + x = x.replace(tzinfo=tz_info).astimezone(pytz.UTC).replace(tzinfo=None) + y = y.replace(tzinfo=tz_info).astimezone(pytz.UTC).replace(tzinfo=None) + working_interval = (x, y) working_intervals += self.interval_remove_leaves(working_interval, work_limits) # find leave intervals @@ -597,7 +596,7 @@ class resource_calendar(osv.osv): for dt_str, hours, calendar_id in date_and_hours_by_cal: result = self.schedule_hours( cr, uid, calendar_id, hours, - day_dt=datetime.datetime.strptime(dt_str, '%Y-%m-%d %H:%M:%S').replace(minute=0, second=0), + day_dt=datetime.datetime.strptime(dt_str, '%Y-%m-%d %H:%M:%S').replace(second=0), compute_leaves=True, resource_id=resource, default_interval=(8, 16) ) diff --git a/addons/resource/tests/common.py b/addons/resource/tests/common.py index 74b91abde2e..a82bf70b708 100644 --- a/addons/resource/tests/common.py +++ b/addons/resource/tests/common.py @@ -29,8 +29,9 @@ class TestResourceCommon(common.TransactionCase): def setUp(self): super(TestResourceCommon, self).setUp() cr, uid = self.cr, self.uid - if not hasattr(self, 'context'): - self.context = {} + self.context = context = dict(tz='UTC') + + self.registry('res.users').write(cr, uid, uid, {'tz': 'UTC'}, context=context) # Usefull models self.resource_resource = self.registry('resource.resource') @@ -56,7 +57,7 @@ class TestResourceCommon(common.TransactionCase): self.calendar_id = self.resource_calendar.create( cr, uid, { 'name': 'TestCalendar', - } + }, context=context ) self.att1_id = self.resource_attendance.create( cr, uid, { @@ -65,7 +66,7 @@ class TestResourceCommon(common.TransactionCase): 'hour_from': 8, 'hour_to': 16, 'calendar_id': self.calendar_id, - } + }, context=context ) self.att2_id = self.resource_attendance.create( cr, uid, { @@ -74,7 +75,7 @@ class TestResourceCommon(common.TransactionCase): 'hour_from': 8, 'hour_to': 13, 'calendar_id': self.calendar_id, - } + }, context=context ) self.att3_id = self.resource_attendance.create( cr, uid, { @@ -83,7 +84,7 @@ class TestResourceCommon(common.TransactionCase): 'hour_from': 16, 'hour_to': 23, 'calendar_id': self.calendar_id, - } + }, context=context ) self.resource1_id = self.resource_resource.create( cr, uid, { @@ -91,7 +92,7 @@ class TestResourceCommon(common.TransactionCase): 'resource_type': 'user', 'time_efficiency': 150.0, 'calendar_id': self.calendar_id, - } + }, context=context ) self.leave1_id = self.resource_leaves.create( cr, uid, { @@ -99,7 +100,7 @@ class TestResourceCommon(common.TransactionCase): 'calendar_id': self.calendar_id, 'date_from': self.leave1_start, 'date_to': self.leave1_end, - } + }, context=context ) self.leave2_id = self.resource_leaves.create( cr, uid, { @@ -108,7 +109,7 @@ class TestResourceCommon(common.TransactionCase): 'resource_id': self.resource1_id, 'date_from': self.leave2_start, 'date_to': self.leave2_end, - } + }, context=context ) self.leave3_id = self.resource_leaves.create( cr, uid, { @@ -117,7 +118,7 @@ class TestResourceCommon(common.TransactionCase): 'resource_id': self.resource1_id, 'date_from': self.leave3_start, 'date_to': self.leave3_end, - } + }, context=context ) # Some browse data - self.calendar = self.resource_calendar.browse(cr, uid, self.calendar_id) + self.calendar = self.resource_calendar.browse(cr, uid, self.calendar_id, context=context) diff --git a/addons/resource/tests/test_resource.py b/addons/resource/tests/test_resource.py index 0cecb9853e5..0c209825cd7 100644 --- a/addons/resource/tests/test_resource.py +++ b/addons/resource/tests/test_resource.py @@ -150,16 +150,17 @@ class TestResource(TestResourceCommon): def test_20_calendar_working_intervals(self): """ Testing working intervals computing method of resource.calendar """ cr, uid = self.cr, self.uid + context = self.context _format = '%Y-%m-%d %H:%M:%S' # Test: day0 without leaves: 1 interval - intervals = self.resource_calendar.get_working_intervals_of_day(cr, uid, self.calendar_id, start_dt=self.date1) + intervals = self.resource_calendar.get_working_intervals_of_day(cr, uid, self.calendar_id, start_dt=self.date1, context=context) self.assertEqual(len(intervals), 1, 'resource_calendar: wrong working intervals') self.assertEqual(intervals[0][0], datetime.strptime('2013-02-12 09:08:07', _format), 'resource_calendar: wrong working intervals') self.assertEqual(intervals[0][1], datetime.strptime('2013-02-12 16:00:00', _format), 'resource_calendar: wrong working intervals') # Test: day3 without leaves: 2 interval - intervals = self.resource_calendar.get_working_intervals_of_day(cr, uid, self.calendar_id, start_dt=self.date2) + intervals = self.resource_calendar.get_working_intervals_of_day(cr, uid, self.calendar_id, start_dt=self.date2, context=context) self.assertEqual(len(intervals), 2, 'resource_calendar: wrong working intervals') self.assertEqual(intervals[0][0], datetime.strptime('2013-02-15 10:11:12', _format), 'resource_calendar: wrong working intervals') self.assertEqual(intervals[0][1], datetime.strptime('2013-02-15 13:00:00', _format), 'resource_calendar: wrong working intervals') @@ -167,7 +168,7 @@ class TestResource(TestResourceCommon): self.assertEqual(intervals[1][1], datetime.strptime('2013-02-15 23:00:00', _format), 'resource_calendar: wrong working intervals') # Test: day0 with leaves outside range: 1 interval - intervals = self.resource_calendar.get_working_intervals_of_day(cr, uid, self.calendar_id, start_dt=self.date1.replace(hour=0), compute_leaves=True) + intervals = self.resource_calendar.get_working_intervals_of_day(cr, uid, self.calendar_id, start_dt=self.date1.replace(hour=0), compute_leaves=True, context=context) self.assertEqual(len(intervals), 1, 'resource_calendar: wrong working intervals') self.assertEqual(intervals[0][0], datetime.strptime('2013-02-12 08:00:00', _format), 'resource_calendar: wrong working intervals') self.assertEqual(intervals[0][1], datetime.strptime('2013-02-12 16:00:00', _format), 'resource_calendar: wrong working intervals') @@ -176,7 +177,7 @@ class TestResource(TestResourceCommon): intervals = self.resource_calendar.get_working_intervals_of_day(cr, uid, self.calendar_id, start_dt=self.date1.replace(hour=8) + relativedelta(days=7), end_dt=self.date1.replace(hour=15, minute=45, second=30) + relativedelta(days=7), - compute_leaves=True) + compute_leaves=True, context=context) self.assertEqual(len(intervals), 2, 'resource_calendar: wrong working intervals') self.assertEqual(intervals[0][0], datetime.strptime('2013-02-19 08:08:07', _format), 'resource_calendar: wrong working intervals') self.assertEqual(intervals[0][1], datetime.strptime('2013-02-19 09:00:00', _format), 'resource_calendar: wrong working intervals') @@ -186,21 +187,22 @@ class TestResource(TestResourceCommon): def test_30_calendar_working_days(self): """ Testing calendar hours computation on a working day """ cr, uid = self.cr, self.uid + context = self.context _format = '%Y-%m-%d %H:%M:%S' # Test: day1, beginning at 10:30 -> work from 10:30 (arrival) until 16:00 - intervals = self.resource_calendar.get_working_intervals_of_day(cr, uid, self.calendar_id, start_dt=self.date1.replace(hour=10, minute=30, second=0)) + intervals = self.resource_calendar.get_working_intervals_of_day(cr, uid, self.calendar_id, start_dt=self.date1.replace(hour=10, minute=30, second=0), context=context) self.assertEqual(len(intervals), 1, 'resource_calendar: wrong working interval / day computing') self.assertEqual(intervals[0][0], datetime.strptime('2013-02-12 10:30:00', _format), 'resource_calendar: wrong working interval / day computing') self.assertEqual(intervals[0][1], datetime.strptime('2013-02-12 16:00:00', _format), 'resource_calendar: wrong working interval / day computing') # Test: hour computation for same interval, should give 5.5 - wh = self.resource_calendar.get_working_hours_of_date(cr, uid, self.calendar_id, start_dt=self.date1.replace(hour=10, minute=30, second=0)) + wh = self.resource_calendar.get_working_hours_of_date(cr, uid, self.calendar_id, start_dt=self.date1.replace(hour=10, minute=30, second=0), context=context) self.assertEqual(wh, 5.5, 'resource_calendar: wrong working interval / day time computing') # Test: day1+7 on leave, without leave computation intervals = self.resource_calendar.get_working_intervals_of_day( cr, uid, self.calendar_id, - start_dt=self.date1.replace(hour=7, minute=0, second=0) + relativedelta(days=7) + start_dt=self.date1.replace(hour=7, minute=0, second=0) + relativedelta(days=7), context=context ) # Result: day1 (08->16) self.assertEqual(len(intervals), 1, 'resource_calendar: wrong working interval/day computing') @@ -211,7 +213,7 @@ class TestResource(TestResourceCommon): intervals = self.resource_calendar.get_working_intervals_of_day( cr, uid, self.calendar_id, start_dt=self.date1.replace(hour=7, minute=0, second=0) + relativedelta(days=7), - compute_leaves=True + compute_leaves=True, context=context ) # Result: day1 (08->09 + 12->16) self.assertEqual(len(intervals), 2, 'resource_calendar: wrong working interval/day computing') @@ -224,7 +226,7 @@ class TestResource(TestResourceCommon): intervals = self.resource_calendar.get_working_intervals_of_day( cr, uid, self.calendar_id, start_dt=self.date1.replace(hour=7, minute=0, second=0) + relativedelta(days=14), - compute_leaves=True + compute_leaves=True, context=context ) # Result: day1 (08->16) self.assertEqual(len(intervals), 1, 'resource_calendar: wrong working interval/day computing') @@ -236,7 +238,7 @@ class TestResource(TestResourceCommon): cr, uid, self.calendar_id, start_dt=self.date1.replace(hour=7, minute=0, second=0) + relativedelta(days=14), compute_leaves=True, - resource_id=self.resource1_id + resource_id=self.resource1_id, context=context ) # Result: nothing, because on leave self.assertEqual(len(intervals), 0, 'resource_calendar: wrong working interval/day computing') @@ -244,6 +246,7 @@ class TestResource(TestResourceCommon): def test_40_calendar_hours_scheduling(self): """ Testing calendar hours scheduling """ cr, uid = self.cr, self.uid + context = self.context _format = '%Y-%m-%d %H:%M:%S' # -------------------------------------------------- @@ -268,7 +271,7 @@ class TestResource(TestResourceCommon): # (datetime.datetime(2013, 2, 8, 16, 0), datetime.datetime(2013, 2, 8, 23, 0)) # (datetime.datetime(2013, 2, 12, 8, 0), datetime.datetime(2013, 2, 12, 9, 0)) - res = self.resource_calendar.schedule_hours(cr, uid, self.calendar_id, -40, day_dt=self.date1.replace(minute=0, second=0)) + res = self.resource_calendar.schedule_hours(cr, uid, self.calendar_id, -40, day_dt=self.date1.replace(minute=0, second=0), context=context) # current day, limited at 09:00 because of day_dt specified -> 1 hour self.assertEqual(res[-1][0], datetime.strptime('2013-02-12 08:00:00', _format), 'resource_calendar: wrong hours scheduling') self.assertEqual(res[-1][1], datetime.strptime('2013-02-12 09:00:00', _format), 'resource_calendar: wrong hours scheduling') @@ -307,7 +310,7 @@ class TestResource(TestResourceCommon): res = self.resource_calendar.schedule_hours( cr, uid, self.calendar_id, 40, - day_dt=self.date1.replace(minute=0, second=0) + day_dt=self.date1.replace(minute=0, second=0), context=context ) self.assertEqual(res[0][0], datetime.strptime('2013-02-12 09:00:00', _format), 'resource_calendar: wrong hours scheduling') self.assertEqual(res[0][1], datetime.strptime('2013-02-12 16:00:00', _format), 'resource_calendar: wrong hours scheduling') @@ -341,7 +344,7 @@ class TestResource(TestResourceCommon): cr, uid, self.calendar_id, 40, day_dt=self.date1.replace(minute=0, second=0), compute_leaves=True, - resource_id=self.resource1_id + resource_id=self.resource1_id, context=context ) self.assertEqual(res[0][0], datetime.strptime('2013-02-12 09:00:00', _format), 'resource_calendar: wrong hours scheduling') self.assertEqual(res[0][1], datetime.strptime('2013-02-12 16:00:00', _format), 'resource_calendar: wrong hours scheduling') @@ -376,7 +379,7 @@ class TestResource(TestResourceCommon): cr, uid, self.calendar_id, self.date1.replace(hour=6, minute=0), self.date2.replace(hour=23, minute=0) + relativedelta(days=7), - resource_id=self.resource1_id, exclude_leaves=True) + resource_id=self.resource1_id, exclude_leaves=True, context=context) self.assertEqual(res, 40.0, 'resource_calendar: wrong _interval_hours_get compatibility computation') # new API: resource without leaves @@ -385,7 +388,7 @@ class TestResource(TestResourceCommon): cr, uid, self.calendar_id, self.date1.replace(hour=6, minute=0), self.date2.replace(hour=23, minute=0) + relativedelta(days=7), - compute_leaves=False, resource_id=self.resource1_id) + compute_leaves=False, resource_id=self.resource1_id, context=context) self.assertEqual(res, 40.0, 'resource_calendar: wrong get_working_hours computation') # old API: resource and leaves @@ -394,7 +397,7 @@ class TestResource(TestResourceCommon): cr, uid, self.calendar_id, self.date1.replace(hour=6, minute=0), self.date2.replace(hour=23, minute=0) + relativedelta(days=7), - resource_id=self.resource1_id, exclude_leaves=False) + resource_id=self.resource1_id, exclude_leaves=False, context=context) self.assertEqual(res, 33.0, 'resource_calendar: wrong _interval_hours_get compatibility computation') # new API: resource and leaves @@ -403,7 +406,7 @@ class TestResource(TestResourceCommon): cr, uid, self.calendar_id, self.date1.replace(hour=6, minute=0), self.date2.replace(hour=23, minute=0) + relativedelta(days=7), - compute_leaves=True, resource_id=self.resource1_id) + compute_leaves=True, resource_id=self.resource1_id, context=context) self.assertEqual(res, 33.0, 'resource_calendar: wrong get_working_hours computation') # -------------------------------------------------- @@ -416,7 +419,7 @@ class TestResource(TestResourceCommon): self.date1.replace(hour=6, minute=0), self.date2.replace(hour=23, minute=0), compute_leaves=True, resource_id=self.resource1_id, - default_interval=(8, 16)) + default_interval=(8, 16), context=context) self.assertEqual(res, 32.0, 'resource_calendar: wrong get_working_hours computation') def test_50_calendar_schedule_days(self): From 2442fe2e4b9b44b984d0552e16be2d1e19ca7d29 Mon Sep 17 00:00:00 2001 From: Goffin Simon Date: Mon, 14 Sep 2015 10:24:48 +0200 Subject: [PATCH 2/5] [FIX] resource: hour_to and hour_from in interval_get_multi The function interval_get_multi must take into account the minutes in hour_from and hour_to. hour_to and hour_from are float fields in the model "resource.calendar.attendance" and the decimal part of these two fields is for the minutes. opw:648349 --- addons/resource/resource.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/addons/resource/resource.py b/addons/resource/resource.py index 155d6ab4c68..ec414f2f38a 100644 --- a/addons/resource/resource.py +++ b/addons/resource/resource.py @@ -165,8 +165,10 @@ class resource_calendar(osv.osv): current_hour = dt_from.hour while float_compare(todo, 0, 4) and maxrecur: for (hour_from,hour_to) in [(item['hour_from'], item['hour_to']) for item in hours_by_cal[id] if item['dayofweek'] == str(dt_from.weekday())]: - hour_from = dt_from.replace(hour=int(hour_from)).replace(tzinfo=tzinfo).astimezone(pytz.UTC).hour - hour_to = dt_from.replace(hour=int(hour_to)).replace(tzinfo=tzinfo).astimezone(pytz.UTC).hour + h_from = dt_from.replace(hour=int(hour_from), minute=int((hour_from % 1)*60)).replace(tzinfo=tzinfo).astimezone(pytz.UTC) + hour_from = h_from.hour + f_round(float(h_from.minute)/60, 2) + h_to = dt_from.replace(hour=int(hour_to), minute=int((hour_to % 1)*60)).replace(tzinfo=tzinfo).astimezone(pytz.UTC) + hour_to = h_to.hour + f_round(float(h_to.minute)/60, 2) leave_flag = False if (hour_to>current_hour) and float_compare(todo, 0, 4): m = max(hour_from, current_hour) From acf22b7bc84164df99046120287ad1f7f5d01783 Mon Sep 17 00:00:00 2001 From: Goffin Simon Date: Mon, 14 Sep 2015 15:12:40 +0200 Subject: [PATCH 3/5] [FIX] resource: current_hour in interval_get_multi The minutes of dt_from(start date) must be taken into account by current_hour and not by todo (hours). --- addons/resource/resource.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/addons/resource/resource.py b/addons/resource/resource.py index ec414f2f38a..0ff1fd71468 100644 --- a/addons/resource/resource.py +++ b/addons/resource/resource.py @@ -159,10 +159,10 @@ class resource_calendar(osv.osv): continue dt_leave = self._get_leaves(cr, uid, id, resource) - todo = hours + f_round(float(dt_from.minute)/60, 2) + todo = hours result = [] maxrecur = 100 - current_hour = dt_from.hour + current_hour = dt_from.hour + f_round(float(dt_from.minute)/60, 2) while float_compare(todo, 0, 4) and maxrecur: for (hour_from,hour_to) in [(item['hour_from'], item['hour_to']) for item in hours_by_cal[id] if item['dayofweek'] == str(dt_from.weekday())]: h_from = dt_from.replace(hour=int(hour_from), minute=int((hour_from % 1)*60)).replace(tzinfo=tzinfo).astimezone(pytz.UTC) From cc9113f818ad62c4bfc5ede90a1b055c8bb9414e Mon Sep 17 00:00:00 2001 From: dufresnedavid Date: Tue, 1 Sep 2015 17:10:33 -0400 Subject: [PATCH 4/5] [IMP] Prevent unclosed cursor during tests If an error happens in an overload of setUp, the already-open cursor is likely not to get properly released before the next test, deadlocking the db, because tearDown only runs if setUp has succesfully completed. Cleanups were added specifically to run every time, after tearDown has (potentially) been executed. closes #8327 Note: cleanups run in LIFO order (as they should). --- openerp/tests/common.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/openerp/tests/common.py b/openerp/tests/common.py index 3f0143ef9df..4e72b6c5fd6 100644 --- a/openerp/tests/common.py +++ b/openerp/tests/common.py @@ -94,9 +94,10 @@ class TransactionCase(BaseCase): TransactionCase.cr = self.cursor() TransactionCase.uid = openerp.SUPERUSER_ID - def tearDown(self): - self.cr.rollback() - self.cr.close() + @self.addCleanup + def close_cursor(): + self.cr.rollback() + self.cr.close() class SingleTransactionCase(BaseCase): From c2aff4772e549ab8ee643b7cb0f019114d638b75 Mon Sep 17 00:00:00 2001 From: Valencia Rodrigues Sah Date: Thu, 17 Sep 2015 15:35:21 +0530 Subject: [PATCH 5/5] [FIX] product: default value on required field The qty fields has become computed in 6.1, and the value set by the user is on min_qty. Set default value as it is required. Closes #8561 --- addons/product/product.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/addons/product/product.py b/addons/product/product.py index 98a33a98f8a..5222ebc3d81 100644 --- a/addons/product/product.py +++ b/addons/product/product.py @@ -901,7 +901,7 @@ class product_supplierinfo(osv.osv): 'company_id':fields.many2one('res.company','Company',select=1), } _defaults = { - 'qty': lambda *a: 0.0, + 'min_qty': lambda *a: 0.0, 'sequence': lambda *a: 1, 'delay': lambda *a: 1, 'company_id': lambda self,cr,uid,c: self.pool.get('res.company')._company_default_get(cr, uid, 'product.supplierinfo', context=c),