[FIX] website_forum: post edition working again
[odoo/odoo.git] / addons / resource / tests / test_resource.py
1 # -*- coding: utf-8 -*-
2 ##############################################################################
3 #
4 #    OpenERP, Open Source Business Applications
5 #    Copyright (c) 2013-TODAY OpenERP S.A. <http://www.openerp.com>
6 #
7 #    This program is free software: you can redistribute it and/or modify
8 #    it under the terms of the GNU Affero General Public License as
9 #    published by the Free Software Foundation, either version 3 of the
10 #    License, or (at your option) any later version.
11 #
12 #    This program is distributed in the hope that it will be useful,
13 #    but WITHOUT ANY WARRANTY; without even the implied warranty of
14 #    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15 #    GNU Affero General Public License for more details.
16 #
17 #    You should have received a copy of the GNU Affero General Public License
18 #    along with this program.  If not, see <http://www.gnu.org/licenses/>.
19 #
20 ##############################################################################
21
22 from datetime import datetime, timedelta
23 from dateutil.relativedelta import relativedelta
24
25 from openerp.addons.resource.tests.common import TestResourceCommon
26
27
28 class TestResource(TestResourceCommon):
29
30     def test_00_intervals(self):
31         intervals = [
32             (
33                 datetime.strptime('2013-02-04 09:00:00', '%Y-%m-%d %H:%M:%S'),
34                 datetime.strptime('2013-02-04 11:00:00', '%Y-%m-%d %H:%M:%S')
35             ), (
36                 datetime.strptime('2013-02-04 08:00:00', '%Y-%m-%d %H:%M:%S'),
37                 datetime.strptime('2013-02-04 12:00:00', '%Y-%m-%d %H:%M:%S')
38             ), (
39                 datetime.strptime('2013-02-04 11:00:00', '%Y-%m-%d %H:%M:%S'),
40                 datetime.strptime('2013-02-04 14:00:00', '%Y-%m-%d %H:%M:%S')
41             ), (
42                 datetime.strptime('2013-02-04 17:00:00', '%Y-%m-%d %H:%M:%S'),
43                 datetime.strptime('2013-02-04 21:00:00', '%Y-%m-%d %H:%M:%S')
44             ), (
45                 datetime.strptime('2013-02-03 08:00:00', '%Y-%m-%d %H:%M:%S'),
46                 datetime.strptime('2013-02-03 10:00:00', '%Y-%m-%d %H:%M:%S')
47             ), (
48                 datetime.strptime('2013-02-04 18:00:00', '%Y-%m-%d %H:%M:%S'),
49                 datetime.strptime('2013-02-04 19:00:00', '%Y-%m-%d %H:%M:%S')
50             )
51         ]
52
53         # Test: interval cleaning
54         cleaned_intervals = self.resource_calendar.interval_clean(intervals)
55         self.assertEqual(len(cleaned_intervals), 3, 'resource_calendar: wrong interval cleaning')
56         # First interval: 03, unchanged
57         self.assertEqual(cleaned_intervals[0][0], datetime.strptime('2013-02-03 08:00:00', '%Y-%m-%d %H:%M:%S'), 'resource_calendar: wrong interval cleaning')
58         self.assertEqual(cleaned_intervals[0][1], datetime.strptime('2013-02-03 10:00:00', '%Y-%m-%d %H:%M:%S'), 'resource_calendar: wrong interval cleaning')
59         # Second intreval: 04, 08-14, combining 08-12 and 11-14, 09-11 being inside 08-12
60         self.assertEqual(cleaned_intervals[1][0], datetime.strptime('2013-02-04 08:00:00', '%Y-%m-%d %H:%M:%S'), 'resource_calendar: wrong interval cleaning')
61         self.assertEqual(cleaned_intervals[1][1], datetime.strptime('2013-02-04 14:00:00', '%Y-%m-%d %H:%M:%S'), 'resource_calendar: wrong interval cleaning')
62         # Third interval: 04, 17-21, 18-19 being inside 17-21
63         self.assertEqual(cleaned_intervals[2][0], datetime.strptime('2013-02-04 17:00:00', '%Y-%m-%d %H:%M:%S'), 'resource_calendar: wrong interval cleaning')
64         self.assertEqual(cleaned_intervals[2][1], datetime.strptime('2013-02-04 21:00:00', '%Y-%m-%d %H:%M:%S'), 'resource_calendar: wrong interval cleaning')
65
66         # Test: disjoint removal
67         working_interval = (datetime.strptime('2013-02-04 08:00:00', '%Y-%m-%d %H:%M:%S'), datetime.strptime('2013-02-04 18:00:00', '%Y-%m-%d %H:%M:%S'))
68         result = self.resource_calendar.interval_remove_leaves(working_interval, intervals)
69         self.assertEqual(len(result), 1, 'resource_calendar: wrong leave removal from interval')
70         # First interval: 04, 14-17
71         self.assertEqual(result[0][0], datetime.strptime('2013-02-04 14:00:00', '%Y-%m-%d %H:%M:%S'), 'resource_calendar: wrong leave removal from interval')
72         self.assertEqual(result[0][1], datetime.strptime('2013-02-04 17:00:00', '%Y-%m-%d %H:%M:%S'), 'resource_calendar: wrong leave removal from interval')
73
74         # Test: schedule hours on intervals
75         result = self.resource_calendar.interval_schedule_hours(cleaned_intervals, 5.5)
76         self.assertEqual(len(result), 2, 'resource_calendar: wrong hours scheduling in interval')
77         # First interval: 03, 8-10 untouches
78         self.assertEqual(result[0][0], datetime.strptime('2013-02-03 08:00:00', '%Y-%m-%d %H:%M:%S'), 'resource_calendar: wrong leave removal from interval')
79         self.assertEqual(result[0][1], datetime.strptime('2013-02-03 10:00:00', '%Y-%m-%d %H:%M:%S'), 'resource_calendar: wrong leave removal from interval')
80         # First interval: 04, 08-11:30
81         self.assertEqual(result[1][0], datetime.strptime('2013-02-04 08:00:00', '%Y-%m-%d %H:%M:%S'), 'resource_calendar: wrong leave removal from interval')
82         self.assertEqual(result[1][1], datetime.strptime('2013-02-04 11:30:00', '%Y-%m-%d %H:%M:%S'), 'resource_calendar: wrong leave removal from interval')
83
84         # Test: schedule hours on intervals, backwards
85         cleaned_intervals.reverse()
86         result = self.resource_calendar.interval_schedule_hours(cleaned_intervals, 5.5, remove_at_end=False)
87         self.assertEqual(len(result), 2, 'resource_calendar: wrong hours scheduling in interval')
88         # First interval: 03, 8-10 untouches
89         self.assertEqual(result[0][0], datetime.strptime('2013-02-04 17:00:00', '%Y-%m-%d %H:%M:%S'), 'resource_calendar: wrong leave removal from interval')
90         self.assertEqual(result[0][1], datetime.strptime('2013-02-04 21:00:00', '%Y-%m-%d %H:%M:%S'), 'resource_calendar: wrong leave removal from interval')
91         # First interval: 04, 08-11:30
92         self.assertEqual(result[1][0], datetime.strptime('2013-02-04 12:30:00', '%Y-%m-%d %H:%M:%S'), 'resource_calendar: wrong leave removal from interval')
93         self.assertEqual(result[1][1], datetime.strptime('2013-02-04 14:00:00', '%Y-%m-%d %H:%M:%S'), 'resource_calendar: wrong leave removal from interval')
94
95     def test_10_calendar_basics(self):
96         """ Testing basic method of resource.calendar """
97         cr, uid = self.cr, self.uid
98
99         # --------------------------------------------------
100         # Test1: get_next_day
101         # --------------------------------------------------
102
103         # Test: next day: next day after day1 is day4
104         date = self.resource_calendar.get_next_day(cr, uid, self.calendar_id, day_date=self.date1.date())
105         self.assertEqual(date, self.date2.date(), 'resource_calendar: wrong next day computing')
106
107         # Test: next day: next day after day4 is (day1+7)
108         date = self.resource_calendar.get_next_day(cr, uid, self.calendar_id, day_date=self.date2.date())
109         self.assertEqual(date, self.date1.date() + relativedelta(days=7), 'resource_calendar: wrong next day computing')
110
111         # Test: next day: next day after day4+1 is (day1+7)
112         date = self.resource_calendar.get_next_day(cr, uid, self.calendar_id, day_date=self.date2.date() + relativedelta(days=1))
113         self.assertEqual(date, self.date1.date() + relativedelta(days=7), 'resource_calendar: wrong next day computing')
114
115         # Test: next day: next day after day1-1 is day1
116         date = self.resource_calendar.get_next_day(cr, uid, self.calendar_id, day_date=self.date1.date() + relativedelta(days=-1))
117         self.assertEqual(date, self.date1.date(), 'resource_calendar: wrong next day computing')
118
119         # --------------------------------------------------
120         # Test2: get_previous_day
121         # --------------------------------------------------
122
123         # Test: previous day: previous day before day1 is (day4-7)
124         date = self.resource_calendar.get_previous_day(cr, uid, self.calendar_id, day_date=self.date1.date())
125         self.assertEqual(date, self.date2.date() + relativedelta(days=-7), 'resource_calendar: wrong previous day computing')
126
127         # Test: previous day: previous day before day4 is day1
128         date = self.resource_calendar.get_previous_day(cr, uid, self.calendar_id, day_date=self.date2.date())
129         self.assertEqual(date, self.date1.date(), 'resource_calendar: wrong previous day computing')
130
131         # Test: previous day: previous day before day4+1 is day4
132         date = self.resource_calendar.get_previous_day(cr, uid, self.calendar_id, day_date=self.date2.date() + relativedelta(days=1))
133         self.assertEqual(date, self.date2.date(), 'resource_calendar: wrong previous day computing')
134
135         # Test: previous day: previous day before day1-1 is (day4-7)
136         date = self.resource_calendar.get_previous_day(cr, uid, self.calendar_id, day_date=self.date1.date() + relativedelta(days=-1))
137         self.assertEqual(date, self.date2.date() + relativedelta(days=-7), 'resource_calendar: wrong previous day computing')
138
139         # --------------------------------------------------
140         # Test3: misc
141         # --------------------------------------------------
142
143         weekdays = self.resource_calendar.get_weekdays(cr, uid, self.calendar_id)
144         self.assertEqual(weekdays, [1, 4], 'resource_calendar: wrong weekdays computing')
145
146         attendances = self.resource_calendar.get_attendances_for_weekdays(cr, uid, self.calendar_id, [2, 3, 4, 5])
147         self.assertEqual(set([att.id for att in attendances]), set([self.att2_id, self.att3_id]),
148                          'resource_calendar: wrong attendances filtering by weekdays computing')
149
150     def test_20_calendar_working_intervals(self):
151         """ Testing working intervals computing method of resource.calendar """
152         cr, uid = self.cr, self.uid
153         _format = '%Y-%m-%d %H:%M:%S'
154
155         # Test: day0 without leaves: 1 interval
156         intervals = self.resource_calendar.get_working_intervals_of_day(cr, uid, self.calendar_id, start_dt=self.date1)
157         self.assertEqual(len(intervals), 1, 'resource_calendar: wrong working intervals')
158         self.assertEqual(intervals[0][0], datetime.strptime('2013-02-12 09:08:07', _format), 'resource_calendar: wrong working intervals')
159         self.assertEqual(intervals[0][1], datetime.strptime('2013-02-12 16:00:00', _format), 'resource_calendar: wrong working intervals')
160
161         # Test: day3 without leaves: 2 interval
162         intervals = self.resource_calendar.get_working_intervals_of_day(cr, uid, self.calendar_id, start_dt=self.date2)
163         self.assertEqual(len(intervals), 2, 'resource_calendar: wrong working intervals')
164         self.assertEqual(intervals[0][0], datetime.strptime('2013-02-15 10:11:12', _format), 'resource_calendar: wrong working intervals')
165         self.assertEqual(intervals[0][1], datetime.strptime('2013-02-15 13:00:00', _format), 'resource_calendar: wrong working intervals')
166         self.assertEqual(intervals[1][0], datetime.strptime('2013-02-15 16:00:00', _format), 'resource_calendar: wrong working intervals')
167         self.assertEqual(intervals[1][1], datetime.strptime('2013-02-15 23:00:00', _format), 'resource_calendar: wrong working intervals')
168
169         # Test: day0 with leaves outside range: 1 interval
170         intervals = self.resource_calendar.get_working_intervals_of_day(cr, uid, self.calendar_id, start_dt=self.date1.replace(hour=0), compute_leaves=True)
171         self.assertEqual(len(intervals), 1, 'resource_calendar: wrong working intervals')
172         self.assertEqual(intervals[0][0], datetime.strptime('2013-02-12 08:00:00', _format), 'resource_calendar: wrong working intervals')
173         self.assertEqual(intervals[0][1], datetime.strptime('2013-02-12 16:00:00', _format), 'resource_calendar: wrong working intervals')
174
175         # Test: day0 with leaves: 2 intervals because of leave between 9 ans 12, ending at 15:45:30
176         intervals = self.resource_calendar.get_working_intervals_of_day(cr, uid, self.calendar_id,
177                                                                         start_dt=self.date1.replace(hour=8) + relativedelta(days=7),
178                                                                         end_dt=self.date1.replace(hour=15, minute=45, second=30) + relativedelta(days=7),
179                                                                         compute_leaves=True)
180         self.assertEqual(len(intervals), 2, 'resource_calendar: wrong working intervals')
181         self.assertEqual(intervals[0][0], datetime.strptime('2013-02-19 08:08:07', _format), 'resource_calendar: wrong working intervals')
182         self.assertEqual(intervals[0][1], datetime.strptime('2013-02-19 09:00:00', _format), 'resource_calendar: wrong working intervals')
183         self.assertEqual(intervals[1][0], datetime.strptime('2013-02-19 12:00:00', _format), 'resource_calendar: wrong working intervals')
184         self.assertEqual(intervals[1][1], datetime.strptime('2013-02-19 15:45:30', _format), 'resource_calendar: wrong working intervals')
185
186     def test_30_calendar_working_days(self):
187         """ Testing calendar hours computation on a working day """
188         cr, uid = self.cr, self.uid
189         _format = '%Y-%m-%d %H:%M:%S'
190
191         # Test: day1, beginning at 10:30 -> work from 10:30 (arrival) until 16:00
192         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))
193         self.assertEqual(len(intervals), 1, 'resource_calendar: wrong working interval / day computing')
194         self.assertEqual(intervals[0][0], datetime.strptime('2013-02-12 10:30:00', _format), 'resource_calendar: wrong working interval / day computing')
195         self.assertEqual(intervals[0][1], datetime.strptime('2013-02-12 16:00:00', _format), 'resource_calendar: wrong working interval / day computing')
196         # Test: hour computation for same interval, should give 5.5
197         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))
198         self.assertEqual(wh, 5.5, 'resource_calendar: wrong working interval / day time computing')
199
200         # Test: day1+7 on leave, without leave computation
201         intervals = self.resource_calendar.get_working_intervals_of_day(
202             cr, uid, self.calendar_id,
203             start_dt=self.date1.replace(hour=7, minute=0, second=0) + relativedelta(days=7)
204         )
205         # Result: day1 (08->16)
206         self.assertEqual(len(intervals), 1, 'resource_calendar: wrong working interval/day computing')
207         self.assertEqual(intervals[0][0], datetime.strptime('2013-02-19 08:00:00', _format), 'resource_calendar: wrong working interval / day computing')
208         self.assertEqual(intervals[0][1], datetime.strptime('2013-02-19 16:00:00', _format), 'resource_calendar: wrong working interval / day computing')
209
210         # Test: day1+7 on leave, with generic leave computation
211         intervals = self.resource_calendar.get_working_intervals_of_day(
212             cr, uid, self.calendar_id,
213             start_dt=self.date1.replace(hour=7, minute=0, second=0) + relativedelta(days=7),
214             compute_leaves=True
215         )
216         # Result: day1 (08->09 + 12->16)
217         self.assertEqual(len(intervals), 2, 'resource_calendar: wrong working interval/day computing')
218         self.assertEqual(intervals[0][0], datetime.strptime('2013-02-19 08:00:00', _format), 'resource_calendar: wrong working interval / day computing')
219         self.assertEqual(intervals[0][1], datetime.strptime('2013-02-19 09:00:00', _format), 'resource_calendar: wrong working interval / day computing')
220         self.assertEqual(intervals[1][0], datetime.strptime('2013-02-19 12:00:00', _format), 'resource_calendar: wrong working interval / day computing')
221         self.assertEqual(intervals[1][1], datetime.strptime('2013-02-19 16:00:00', _format), 'resource_calendar: wrong working interval / day computing')
222
223         # Test: day1+14 on leave, with generic leave computation
224         intervals = self.resource_calendar.get_working_intervals_of_day(
225             cr, uid, self.calendar_id,
226             start_dt=self.date1.replace(hour=7, minute=0, second=0) + relativedelta(days=14),
227             compute_leaves=True
228         )
229         # Result: day1 (08->16)
230         self.assertEqual(len(intervals), 1, 'resource_calendar: wrong working interval/day computing')
231         self.assertEqual(intervals[0][0], datetime.strptime('2013-02-26 08:00:00', _format), 'resource_calendar: wrong working interval / day computing')
232         self.assertEqual(intervals[0][1], datetime.strptime('2013-02-26 16:00:00', _format), 'resource_calendar: wrong working interval / day computing')
233
234         # Test: day1+14 on leave, with resource leave computation
235         intervals = self.resource_calendar.get_working_intervals_of_day(
236             cr, uid, self.calendar_id,
237             start_dt=self.date1.replace(hour=7, minute=0, second=0) + relativedelta(days=14),
238             compute_leaves=True,
239             resource_id=self.resource1_id
240         )
241         # Result: nothing, because on leave
242         self.assertEqual(len(intervals), 0, 'resource_calendar: wrong working interval/day computing')
243
244     def test_40_calendar_hours_scheduling(self):
245         """ Testing calendar hours scheduling """
246         cr, uid = self.cr, self.uid
247         _format = '%Y-%m-%d %H:%M:%S'
248
249         # --------------------------------------------------
250         # Test0: schedule hours backwards (old interval_min_get)
251         #   Done without calendar
252         # --------------------------------------------------
253
254         # Done without calendar
255         # res = self.resource_calendar.interval_min_get(cr, uid, None, self.date1, 40, resource=False)
256         # res: (datetime.datetime(2013, 2, 7, 9, 8, 7), datetime.datetime(2013, 2, 12, 9, 8, 7))
257
258         # --------------------------------------------------
259         # Test1: schedule hours backwards (old interval_min_get)
260         # --------------------------------------------------
261
262         # res = self.resource_calendar.interval_min_get(cr, uid, self.calendar_id, self.date1, 40, resource=False)
263         #   (datetime.datetime(2013, 1, 29, 9, 0), datetime.datetime(2013, 1, 29, 16, 0))
264         #   (datetime.datetime(2013, 2, 1, 8, 0), datetime.datetime(2013, 2, 1, 13, 0))
265         #   (datetime.datetime(2013, 2, 1, 16, 0), datetime.datetime(2013, 2, 1, 23, 0))
266         #   (datetime.datetime(2013, 2, 5, 8, 0), datetime.datetime(2013, 2, 5, 16, 0))
267         #   (datetime.datetime(2013, 2, 8, 8, 0), datetime.datetime(2013, 2, 8, 13, 0))
268         #   (datetime.datetime(2013, 2, 8, 16, 0), datetime.datetime(2013, 2, 8, 23, 0))
269         #   (datetime.datetime(2013, 2, 12, 8, 0), datetime.datetime(2013, 2, 12, 9, 0))
270
271         res = self.resource_calendar.schedule_hours(cr, uid, self.calendar_id, -40, day_dt=self.date1.replace(minute=0, second=0))
272         # current day, limited at 09:00 because of day_dt specified -> 1 hour
273         self.assertEqual(res[-1][0], datetime.strptime('2013-02-12 08:00:00', _format), 'resource_calendar: wrong hours scheduling')
274         self.assertEqual(res[-1][1], datetime.strptime('2013-02-12 09:00:00', _format), 'resource_calendar: wrong hours scheduling')
275         # previous days: 5+7 hours / 8 hours / 5+7 hours -> 32 hours
276         self.assertEqual(res[-2][0], datetime.strptime('2013-02-08 16:00:00', _format), 'resource_calendar: wrong hours scheduling')
277         self.assertEqual(res[-2][1], datetime.strptime('2013-02-08 23:00:00', _format), 'resource_calendar: wrong hours scheduling')
278         self.assertEqual(res[-3][0], datetime.strptime('2013-02-08 08:00:00', _format), 'resource_calendar: wrong hours scheduling')
279         self.assertEqual(res[-3][1], datetime.strptime('2013-02-08 13:00:00', _format), 'resource_calendar: wrong hours scheduling')
280         self.assertEqual(res[-4][0], datetime.strptime('2013-02-05 08:00:00', _format), 'resource_calendar: wrong hours scheduling')
281         self.assertEqual(res[-4][1], datetime.strptime('2013-02-05 16:00:00', _format), 'resource_calendar: wrong hours scheduling')
282         self.assertEqual(res[-5][0], datetime.strptime('2013-02-01 16:00:00', _format), 'resource_calendar: wrong hours scheduling')
283         self.assertEqual(res[-5][1], datetime.strptime('2013-02-01 23:00:00', _format), 'resource_calendar: wrong hours scheduling')
284         self.assertEqual(res[-6][0], datetime.strptime('2013-02-01 08:00:00', _format), 'resource_calendar: wrong hours scheduling')
285         self.assertEqual(res[-6][1], datetime.strptime('2013-02-01 13:00:00', _format), 'resource_calendar: wrong hours scheduling')
286         # 7 hours remaining
287         self.assertEqual(res[-7][0], datetime.strptime('2013-01-29 09:00:00', _format), 'resource_calendar: wrong hours scheduling')
288         self.assertEqual(res[-7][1], datetime.strptime('2013-01-29 16:00:00', _format), 'resource_calendar: wrong hours scheduling')
289         # Compute scheduled hours
290         td = timedelta()
291         for item in res:
292             td += item[1] - item[0]
293         self.assertEqual(seconds(td) / 3600.0, 40.0, 'resource_calendar: wrong hours scheduling')
294
295         # --------------------------------------------------
296         # Test2: schedule hours forward (old interval_get)
297         # --------------------------------------------------
298
299         # res = self.resource_calendar.interval_get(cr, uid, self.calendar_id, self.date1, 40, resource=False, byday=True)
300         #   (datetime.datetime(2013, 2, 12, 9, 0), datetime.datetime(2013, 2, 12, 16, 0))
301         #   (datetime.datetime(2013, 2, 15, 8, 0), datetime.datetime(2013, 2, 15, 13, 0))
302         #   (datetime.datetime(2013, 2, 15, 16, 0), datetime.datetime(2013, 2, 15, 23, 0))
303         #   (datetime.datetime(2013, 2, 22, 8, 0), datetime.datetime(2013, 2, 22, 13, 0))
304         #   (datetime.datetime(2013, 2, 22, 16, 0), datetime.datetime(2013, 2, 22, 23, 0))
305         #   (datetime.datetime(2013, 2, 26, 8, 0), datetime.datetime(2013, 2, 26, 16, 0))
306         #   (datetime.datetime(2013, 3, 1, 8, 0), datetime.datetime(2013, 3, 1, 9, 0))
307
308         res = self.resource_calendar.schedule_hours(
309             cr, uid, self.calendar_id, 40,
310             day_dt=self.date1.replace(minute=0, second=0)
311         )
312         self.assertEqual(res[0][0], datetime.strptime('2013-02-12 09:00:00', _format), 'resource_calendar: wrong hours scheduling')
313         self.assertEqual(res[0][1], datetime.strptime('2013-02-12 16:00:00', _format), 'resource_calendar: wrong hours scheduling')
314         self.assertEqual(res[1][0], datetime.strptime('2013-02-15 08:00:00', _format), 'resource_calendar: wrong hours scheduling')
315         self.assertEqual(res[1][1], datetime.strptime('2013-02-15 13:00:00', _format), 'resource_calendar: wrong hours scheduling')
316         self.assertEqual(res[2][0], datetime.strptime('2013-02-15 16:00:00', _format), 'resource_calendar: wrong hours scheduling')
317         self.assertEqual(res[2][1], datetime.strptime('2013-02-15 23:00:00', _format), 'resource_calendar: wrong hours scheduling')
318         self.assertEqual(res[3][0], datetime.strptime('2013-02-19 08:00:00', _format), 'resource_calendar: wrong hours scheduling')
319         self.assertEqual(res[3][1], datetime.strptime('2013-02-19 16:00:00', _format), 'resource_calendar: wrong hours scheduling')
320         self.assertEqual(res[4][0], datetime.strptime('2013-02-22 08:00:00', _format), 'resource_calendar: wrong hours scheduling')
321         self.assertEqual(res[4][1], datetime.strptime('2013-02-22 13:00:00', _format), 'resource_calendar: wrong hours scheduling')
322         self.assertEqual(res[5][0], datetime.strptime('2013-02-22 16:00:00', _format), 'resource_calendar: wrong hours scheduling')
323         self.assertEqual(res[5][1], datetime.strptime('2013-02-22 23:00:00', _format), 'resource_calendar: wrong hours scheduling')
324         self.assertEqual(res[6][0], datetime.strptime('2013-02-26 08:00:00', _format), 'resource_calendar: wrong hours scheduling')
325         self.assertEqual(res[6][1], datetime.strptime('2013-02-26 09:00:00', _format), 'resource_calendar: wrong hours scheduling')
326         td = timedelta()
327         for item in res:
328             td += item[1] - item[0]
329         self.assertEqual(seconds(td) / 3600.0, 40.0, 'resource_calendar: wrong hours scheduling')
330
331         # res = self.resource_calendar.interval_get(cr, uid, self.calendar_id, self.date1, 40, resource=self.resource1_id, byday=True)
332         #   (datetime.datetime(2013, 2, 12, 9, 0), datetime.datetime(2013, 2, 12, 16, 0))
333         #   (datetime.datetime(2013, 2, 15, 8, 0), datetime.datetime(2013, 2, 15, 13, 0))
334         #   (datetime.datetime(2013, 2, 15, 16, 0), datetime.datetime(2013, 2, 15, 23, 0))
335         #   (datetime.datetime(2013, 3, 1, 8, 0), datetime.datetime(2013, 3, 1, 13, 0))
336         #   (datetime.datetime(2013, 3, 1, 16, 0), datetime.datetime(2013, 3, 1, 23, 0))
337         #   (datetime.datetime(2013, 3, 5, 8, 0), datetime.datetime(2013, 3, 5, 16, 0))
338         #   (datetime.datetime(2013, 3, 8, 8, 0), datetime.datetime(2013, 3, 8, 9, 0))
339
340         res = self.resource_calendar.schedule_hours(
341             cr, uid, self.calendar_id, 40,
342             day_dt=self.date1.replace(minute=0, second=0),
343             compute_leaves=True,
344             resource_id=self.resource1_id
345         )
346         self.assertEqual(res[0][0], datetime.strptime('2013-02-12 09:00:00', _format), 'resource_calendar: wrong hours scheduling')
347         self.assertEqual(res[0][1], datetime.strptime('2013-02-12 16:00:00', _format), 'resource_calendar: wrong hours scheduling')
348         self.assertEqual(res[1][0], datetime.strptime('2013-02-15 08:00:00', _format), 'resource_calendar: wrong hours scheduling')
349         self.assertEqual(res[1][1], datetime.strptime('2013-02-15 13:00:00', _format), 'resource_calendar: wrong hours scheduling')
350         self.assertEqual(res[2][0], datetime.strptime('2013-02-15 16:00:00', _format), 'resource_calendar: wrong hours scheduling')
351         self.assertEqual(res[2][1], datetime.strptime('2013-02-15 23:00:00', _format), 'resource_calendar: wrong hours scheduling')
352         self.assertEqual(res[3][0], datetime.strptime('2013-02-19 08:00:00', _format), 'resource_calendar: wrong hours scheduling')
353         self.assertEqual(res[3][1], datetime.strptime('2013-02-19 09:00:00', _format), 'resource_calendar: wrong hours scheduling')
354         self.assertEqual(res[4][0], datetime.strptime('2013-02-19 12:00:00', _format), 'resource_calendar: wrong hours scheduling')
355         self.assertEqual(res[4][1], datetime.strptime('2013-02-19 16:00:00', _format), 'resource_calendar: wrong hours scheduling')
356         self.assertEqual(res[5][0], datetime.strptime('2013-02-22 08:00:00', _format), 'resource_calendar: wrong hours scheduling')
357         self.assertEqual(res[5][1], datetime.strptime('2013-02-22 09:00:00', _format), 'resource_calendar: wrong hours scheduling')
358         self.assertEqual(res[6][0], datetime.strptime('2013-02-22 16:00:00', _format), 'resource_calendar: wrong hours scheduling')
359         self.assertEqual(res[6][1], datetime.strptime('2013-02-22 23:00:00', _format), 'resource_calendar: wrong hours scheduling')
360         self.assertEqual(res[7][0], datetime.strptime('2013-03-01 11:30:00', _format), 'resource_calendar: wrong hours scheduling')
361         self.assertEqual(res[7][1], datetime.strptime('2013-03-01 13:00:00', _format), 'resource_calendar: wrong hours scheduling')
362         self.assertEqual(res[8][0], datetime.strptime('2013-03-01 16:00:00', _format), 'resource_calendar: wrong hours scheduling')
363         self.assertEqual(res[8][1], datetime.strptime('2013-03-01 22:30:00', _format), 'resource_calendar: wrong hours scheduling')
364         td = timedelta()
365         for item in res:
366             td += item[1] - item[0]
367         self.assertEqual(seconds(td) / 3600.0, 40.0, 'resource_calendar: wrong hours scheduling')
368
369         # --------------------------------------------------
370         # Test3: working hours (old _interval_hours_get)
371         # --------------------------------------------------
372
373         # old API: resource without leaves
374         # res: 2 weeks -> 40 hours
375         res = self.resource_calendar._interval_hours_get(
376             cr, uid, self.calendar_id,
377             self.date1.replace(hour=6, minute=0),
378             self.date2.replace(hour=23, minute=0) + relativedelta(days=7),
379             resource_id=self.resource1_id, exclude_leaves=True)
380         self.assertEqual(res, 40.0, 'resource_calendar: wrong _interval_hours_get compatibility computation')
381
382         # new API: resource without leaves
383         # res: 2 weeks -> 40 hours
384         res = self.resource_calendar.get_working_hours(
385             cr, uid, self.calendar_id,
386             self.date1.replace(hour=6, minute=0),
387             self.date2.replace(hour=23, minute=0) + relativedelta(days=7),
388             compute_leaves=False, resource_id=self.resource1_id)
389         self.assertEqual(res, 40.0, 'resource_calendar: wrong get_working_hours computation')
390
391         # old API: resource and leaves
392         # res: 2 weeks -> 40 hours - (3+4) leave hours
393         res = self.resource_calendar._interval_hours_get(
394             cr, uid, self.calendar_id,
395             self.date1.replace(hour=6, minute=0),
396             self.date2.replace(hour=23, minute=0) + relativedelta(days=7),
397             resource_id=self.resource1_id, exclude_leaves=False)
398         self.assertEqual(res, 33.0, 'resource_calendar: wrong _interval_hours_get compatibility computation')
399
400         # new API: resource and leaves
401         # res: 2 weeks -> 40 hours - (3+4) leave hours
402         res = self.resource_calendar.get_working_hours(
403             cr, uid, self.calendar_id,
404             self.date1.replace(hour=6, minute=0),
405             self.date2.replace(hour=23, minute=0) + relativedelta(days=7),
406             compute_leaves=True, resource_id=self.resource1_id)
407         self.assertEqual(res, 33.0, 'resource_calendar: wrong get_working_hours computation')
408
409         # --------------------------------------------------
410         # Test4: misc
411         # --------------------------------------------------
412
413         # Test without calendar and default_interval
414         res = self.resource_calendar.get_working_hours(
415             cr, uid, None,
416             self.date1.replace(hour=6, minute=0),
417             self.date2.replace(hour=23, minute=0),
418             compute_leaves=True, resource_id=self.resource1_id,
419             default_interval=(8, 16))
420         self.assertEqual(res, 32.0, 'resource_calendar: wrong get_working_hours computation')
421
422     def test_50_calendar_schedule_days(self):
423         """ Testing calendar days scheduling """
424         cr, uid = self.cr, self.uid
425         _format = '%Y-%m-%d %H:%M:%S'
426
427         # --------------------------------------------------
428         # Test1: with calendar
429         # --------------------------------------------------
430
431         res = self.resource_calendar.schedule_days_get_date(cr, uid, self.calendar_id, 5, day_date=self.date1)
432         self.assertEqual(res.date(), datetime.strptime('2013-02-26 00:0:00', _format).date(), 'resource_calendar: wrong days scheduling')
433
434         res = self.resource_calendar.schedule_days_get_date(
435             cr, uid, self.calendar_id, 5, day_date=self.date1,
436             compute_leaves=True, resource_id=self.resource1_id)
437         self.assertEqual(res.date(), datetime.strptime('2013-03-01 00:0:00', _format).date(), 'resource_calendar: wrong days scheduling')
438
439         # --------------------------------------------------
440         # Test2: misc
441         # --------------------------------------------------
442
443         # Without calendar, should only count days -> 12 -> 16, 5 days with default intervals
444         res = self.resource_calendar.schedule_days_get_date(cr, uid, None, 5, day_date=self.date1, default_interval=(8, 16))
445         self.assertEqual(res, datetime.strptime('2013-02-16 16:00:00', _format), 'resource_calendar: wrong days scheduling')
446
447 def seconds(td):
448     assert isinstance(td, timedelta)
449
450     return (td.microseconds + (td.seconds + td.days * 24 * 3600) * 10**6) / 10.**6