def _get_car_atn(self, acquisition_date, car_value, fuel_type, co2): # Compute the correction coefficient from the age of the car now = Datetime.from_string(Datetime.now()) start = Datetime.from_string(acquisition_date) if start: number_of_month = (now.year - start.year) * 12.0 + now.month - start.month + int(bool(now.day - start.day + 1)) if number_of_month <= 12: age_coefficient = 1.00 elif number_of_month <= 24: age_coefficient = 0.94 elif number_of_month <= 36: age_coefficient = 0.88 elif number_of_month <= 48: age_coefficient = 0.82 elif number_of_month <= 60: age_coefficient = 0.76 else: age_coefficient = 0.70 car_value = car_value * age_coefficient # Compute atn value from corrected car_value magic_coeff = 6.0 / 7.0 # Don't ask me why if fuel_type == 'electric': atn = 0.0 else: if fuel_type in ['diesel', 'hybrid']: reference = 87.0 else: reference = 105.0 if co2 <= reference: atn = car_value * max(0.04, (0.055 - 0.001 * (reference - co2))) * magic_coeff else: atn = car_value * min(0.18, (0.055 + 0.001 * (co2 - reference))) * magic_coeff return max(1280, atn) / 12.0
def test_50_calendar_schedule_days(self): """ Testing calendar days scheduling """ # -------------------------------------------------- # Test1: with calendar # -------------------------------------------------- res = self.calendar.schedule_days_get_date(5, day_date=self.date1) self.assertEqual( res.date(), Datetime.from_string("2013-02-26 00:00:00").date(), "resource_calendar: wrong days scheduling" ) res = self.calendar.schedule_days_get_date(-2, day_date=self.date1) self.assertEqual( res.date(), Datetime.from_string("2013-02-08 00:00:00").date(), "resource_calendar: wrong days scheduling" ) res = self.calendar.schedule_days_get_date( 5, day_date=self.date1, compute_leaves=True, resource_id=self.resource1_id ) self.assertEqual( res.date(), Datetime.from_string("2013-03-01 00:00:00").date(), "resource_calendar: wrong days scheduling" ) # -------------------------------------------------- # Test2: misc # -------------------------------------------------- # Without calendar, should only count days -> 12 -> 16, 5 days with default intervals res = self.ResourceCalendar.with_context(self.context).schedule_days_get_date( 5, day_date=self.date1, default_interval=(8, 16) ) self.assertEqual(res, Datetime.from_string("2013-02-16 16:00:00"), "resource_calendar: wrong days scheduling")
def test_calendar_working_day_intervals_limited_attendances(self): """ Test attendances limited in time. """ attendance = self.env['resource.calendar.attendance'].search( [('name', '=', 'Att3')]) attendance.write({ 'date_from': self.date2 + relativedelta(days=7), 'date_to': False, }) intervals = self.calendar.get_working_intervals_of_day(start_dt=self.date2) self.assertEqual(intervals, [(Datetime.from_string('2013-02-15 10:11:12'), Datetime.from_string('2013-02-15 13:00:00'))]) attendance.write({ 'date_from': False, 'date_to': self.date2 - relativedelta(days=7), }) intervals = self.calendar.get_working_intervals_of_day(start_dt=self.date2) self.assertEqual(intervals, [(Datetime.from_string('2013-02-15 10:11:12'), Datetime.from_string('2013-02-15 13:00:00'))]) attendance.write({ 'date_from': self.date2 + relativedelta(days=7), 'date_to': self.date2 - relativedelta(days=7), }) intervals = self.calendar.get_working_intervals_of_day(start_dt=self.date2) self.assertEqual(intervals, [(Datetime.from_string('2013-02-15 10:11:12'), Datetime.from_string('2013-02-15 13:00:00'))]) attendance.write({ 'date_from': self.date2, 'date_to': self.date2, }) intervals = self.calendar.get_working_intervals_of_day(start_dt=self.date2) self.assertEqual(len(intervals), 2) self.assertEqual(intervals[0], (Datetime.from_string('2013-02-15 10:11:12'), Datetime.from_string('2013-02-15 13:00:00'))) self.assertEqual(intervals[1], (Datetime.from_string('2013-02-15 16:00:00'), Datetime.from_string('2013-02-15 23:00:00')))
def test_calendar_hours_scheduling_timezone(self): # user in timezone UTC-9 asks for work hours self.env.user.tz = 'US/Alaska' res = self.calendar.plan_hours( 42, to_naive_utc(Datetime.from_string('2013-02-12 09:25:00'), self.env.user)) self.assertEqual(res, to_naive_utc(Datetime.from_string('2013-02-26 11:25:00'), self.env.user))
def test_interval_schedule_hours(self): cleaned_intervals = self.env['resource.calendar'].interval_clean(self.intervals) result = self.env['resource.calendar'].interval_schedule_hours(cleaned_intervals, 5.5) self.assertEqual(len(result), 2) # First interval: 03, 8-10 untouched self.assertEqual(result[0], (Datetime.from_string('2013-02-03 08:00:00'), Datetime.from_string('2013-02-03 10:00:00'))) # First interval: 04, 08-11:30 self.assertEqual(result[1], (Datetime.from_string('2013-02-04 08:00:00'), Datetime.from_string('2013-02-04 11:30:00')))
def test_calendar_working_hours_default_calendar(self): # Test without calendar and default_interval res = self.env['resource.calendar'].with_context(tz='UTC').get_working_hours( Datetime.from_string('2013-02-12 06:00:00'), Datetime.from_string('2013-02-15 23:00:00'), compute_leaves=True, resource_id=self.resource1_id, default_interval=(8, 16)) self.assertEqual(res, 32.0)
def test_interval_schedule_hours_backwards(self): cleaned_intervals = self.env['resource.calendar']._interval_merge(self.intervals) result = self.env['resource.calendar']._interval_schedule_hours(cleaned_intervals, 5.5, backwards=True) self.assertEqual(len(result), 2) # First interval: 03, 8-10 untouched self.assertEqual(result[1][:2], (Datetime.from_string('2013-02-04 17:00:00'), Datetime.from_string('2013-02-04 21:00:00'))) # First interval: 04, 08-11:30 self.assertEqual(result[0][:2], (Datetime.from_string('2013-02-04 12:30:00'), Datetime.from_string('2013-02-04 14:00:00')))
def test_calendar_working_hours(self): # new API: resource without leaves # res: 2 weeks -> 40 hours res = self.calendar.get_work_hours_count( Datetime.from_string('2013-02-12 06:00:00'), Datetime.from_string('2013-02-22 23:00:00'), self.resource1_id, compute_leaves=False) self.assertEqual(res, 40.0)
def test_calendar_working_hours_leaves(self): # new API: resource and leaves # res: 2 weeks -> 40 hours - (3+4) leave hours res = self.calendar.get_work_hours_count( Datetime.from_string('2013-02-12 06:00:00'), Datetime.from_string('2013-02-22 23:00:00'), self.resource1_id, compute_leaves=True) self.assertEqual(res, 33.0)
def test_interval_schedule_hours_backwards(self): cleaned_intervals = self.env['resource.calendar'].interval_clean(self.intervals) cleaned_intervals.reverse() result = self.env['resource.calendar'].interval_schedule_hours(cleaned_intervals, 5.5, remove_at_end=False) self.assertEqual(len(result), 2) # First interval: 03, 8-10 untouched self.assertEqual(result[0], (Datetime.from_string('2013-02-04 17:00:00'), Datetime.from_string('2013-02-04 21:00:00'))) # First interval: 04, 08-11:30 self.assertEqual(result[1], (Datetime.from_string('2013-02-04 12:30:00'), Datetime.from_string('2013-02-04 14:00:00')))
def test_interval_merge(self): cleaned_intervals = self.env['resource.calendar']._interval_merge(self.intervals) self.assertEqual(len(cleaned_intervals), 3) # First interval: 03, unchanged self.assertEqual(cleaned_intervals[0][:2], (Datetime.from_string('2013-02-03 08:00:00'), Datetime.from_string('2013-02-03 10:00:00'))) # Second interval: 04, 08-14, combining 08-12 and 11-14, 09-11 being inside 08-12 self.assertEqual(cleaned_intervals[1][:2], (Datetime.from_string('2013-02-04 08:00:00'), Datetime.from_string('2013-02-04 14:00:00'))) # Third interval: 04, 17-21, 18-19 being inside 17-21 self.assertEqual(cleaned_intervals[2][:2], (Datetime.from_string('2013-02-04 17:00:00'), Datetime.from_string('2013-02-04 21:00:00')))
def test_30_calendar_working_days(self): """ Testing calendar hours computation on a working day """ # Test: day1, beginning at 10:30 -> work from 10:30 (arrival) until 16:00 intervals = self.calendar.get_working_intervals_of_day(start_dt=self.date1.replace(hour=10, minute=30, second=0)) self.assertEqual(len(intervals), 1, 'resource_calendar: wrong working interval / day computing') self.assertEqual(intervals[0][0], Datetime.from_string('2013-02-12 10:30:00'), 'resource_calendar: wrong working interval / day computing') self.assertEqual(intervals[0][1], Datetime.from_string('2013-02-12 16:00:00'), 'resource_calendar: wrong working interval / day computing') # Test: hour computation for same interval, should give 5.5 wh = self.calendar.get_working_hours_of_date(start_dt=self.date1.replace(hour=10, minute=30, second=0)) self.assertEqual(wh, 5.5, 'resource_calendar: wrong working interval / day time computing') # Test: day1+7 on leave, without leave computation intervals = self.calendar.get_working_intervals_of_day( start_dt=self.date1.replace(hour=7, minute=0, second=0) + relativedelta(days=7) ) # Result: day1 (08->16) self.assertEqual(len(intervals), 1, 'resource_calendar: wrong working interval/day computing') self.assertEqual(intervals[0][0], Datetime.from_string('2013-02-19 08:00:00'), 'resource_calendar: wrong working interval / day computing') self.assertEqual(intervals[0][1], Datetime.from_string('2013-02-19 16:00:00'), 'resource_calendar: wrong working interval / day computing') # Test: day1+7 on leave, with generic leave computation intervals = self.calendar.get_working_intervals_of_day( start_dt=self.date1.replace(hour=7, minute=0, second=0) + relativedelta(days=7), compute_leaves=True ) # Result: day1 (08->09 + 12->16) self.assertEqual(len(intervals), 2, 'resource_calendar: wrong working interval/day computing') self.assertEqual(intervals[0][0], Datetime.from_string('2013-02-19 08:00:00'), 'resource_calendar: wrong working interval / day computing') self.assertEqual(intervals[0][1], Datetime.from_string('2013-02-19 09:00:00'), 'resource_calendar: wrong working interval / day computing') self.assertEqual(intervals[1][0], Datetime.from_string('2013-02-19 12:00:00'), 'resource_calendar: wrong working interval / day computing') self.assertEqual(intervals[1][1], Datetime.from_string('2013-02-19 16:00:00'), 'resource_calendar: wrong working interval / day computing') # Test: day1+14 on leave, with generic leave computation intervals = self.calendar.get_working_intervals_of_day( start_dt=self.date1.replace(hour=7, minute=0, second=0) + relativedelta(days=14), compute_leaves=True ) # Result: day1 (08->16) self.assertEqual(len(intervals), 1, 'resource_calendar: wrong working interval/day computing') self.assertEqual(intervals[0][0], Datetime.from_string('2013-02-26 08:00:00'), 'resource_calendar: wrong working interval / day computing') self.assertEqual(intervals[0][1], Datetime.from_string('2013-02-26 16:00:00'), 'resource_calendar: wrong working interval / day computing') # Test: day1+14 on leave, with resource leave computation intervals = self.calendar.get_working_intervals_of_day( start_dt=self.date1.replace(hour=7, minute=0, second=0) + relativedelta(days=14), compute_leaves=True, resource_id=self.resource1_id ) # Result: nothing, because on leave self.assertEqual(len(intervals), 0, 'resource_calendar: wrong working interval/day computing')
def test_leave(self): def to_tuple(interval): return (interval.start_datetime, interval.end_datetime) # Here we test if the leaves are correctly computed in the case our user is in UTC # NB: Beware of winter/spring time work_no_tz = [to_tuple(x) for x in self.calendar._get_day_leave_intervals(Date.from_string('2018-12-25'), time(0), time(23, 59, 59), self.resource1_id)] self.assertEqual(work_no_tz[0], (Datetime.from_string('2018-12-25 08:00:00'), Datetime.from_string('2018-12-25 16:00:00'))) work_user_tz = [to_tuple(x) for x in self.calendar._get_day_leave_intervals(Date.from_string('2018-05-01'), time(0), time(23, 59, 59), self.resource1_id)] self.assertEqual(work_user_tz[0], (Datetime.from_string('2018-05-01 08:00:00'), Datetime.from_string('2018-05-01 16:00:00'))) work_spec = [to_tuple(x) for x in self.calendar._get_day_leave_intervals(Date.from_string('2018-04-06'), time(0), time(23, 59, 59), self.resource1_id)] self.assertEqual(work_spec[0], (Datetime.from_string('2018-04-06 08:00:00'), Datetime.from_string('2018-04-06 13:00:00')))
def test_work_days_count(self): # user in timezone UTC-9 asks for work hours self.env.user.tz = 'US/Alaska' res = self.test.get_work_days_count( to_naive_utc(Datetime.from_string('2013-02-12 06:00:00'), self.env.user), to_naive_utc(Datetime.from_string('2013-02-22 23:00:00'), self.env.user)) self.assertEqual(res, 3.75) # generic leaves, 3 hours res = self.test.get_work_days_count( to_naive_utc(Datetime.from_string('2013-02-12 06:00:00'), self.env.user), to_naive_utc(Datetime.from_string('2013-02-22 20:00:00'), self.env.user)) self.assertEqual(res, 3.5) # last day is truncated of 3 hours on 12) self.env['resource.calendar.leaves'].create({ 'name': 'Timezoned Leaves', 'calendar_id': self.test.resource_calendar_id.id, 'resource_id': self.test.resource_id.id, 'date_from': to_naive_utc(Datetime.from_string('2013-02-13 10:00:00'), self.env.user), 'date_to': to_naive_utc(Datetime.from_string('2013-02-17 12:00:00'), self.env.user) }) res = self.test.get_work_days_count( to_naive_utc(Datetime.from_string('2013-02-12 06:00:00'), self.env.user), to_naive_utc(Datetime.from_string('2013-02-22 20:00:00'), self.env.user)) self.assertEqual(res, 2.5) # one day is on leave and last day is truncated of 3 hours on 12)
def test_calendar_working_hours_leaves(self): # old API: resource and leaves # res: 2 weeks -> 40 hours - (3+4) leave hours res = self.calendar._interval_hours_get( Datetime.from_string('2013-02-12 06:00:00'), Datetime.from_string('2013-02-22 23:00:00'), resource_id=self.resource1_id, exclude_leaves=False) self.assertEqual(res, 33.0) # new API: resource and leaves # res: 2 weeks -> 40 hours - (3+4) leave hours res = self.calendar.get_working_hours( Datetime.from_string('2013-02-12 06:00:00'), Datetime.from_string('2013-02-22 23:00:00'), compute_leaves=True, resource_id=self.resource1_id) self.assertEqual(res, 33.0)
def test_calendar_hours_scheduling_timezone_2(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 self.env.user.tz = 'Australia/Sydney' self.env['resource.calendar.attendance'].create({ 'name': 'Day3 - 1', 'dayofweek': '3', 'hour_from': 8, 'hour_to': 12, 'calendar_id': self.calendar.id, }) self.env['resource.calendar.attendance'].create({ 'name': 'Day3 - 2', 'dayofweek': '3', 'hour_from': 13, 'hour_to': 17, 'calendar_id': self.calendar.id, }) hours = 1.0/60.0 for test_date in ['2013-02-15 08:00:00', '2013-02-15 11:00:00']: start_dt = Datetime.from_string(test_date) start_dt_utc = to_naive_utc(start_dt, self.env.user) res = self.calendar._schedule_hours(hours, start_dt_utc) self.assertEqual( [(start_dt_utc, start_dt_utc.replace(minute=1))], res, 'resource_calendar: wrong schedule_hours computation')
def _check_session_timing(self): self.ensure_one() date_today = datetime.utcnow() session_start = Datetime.from_string(self.start_at) if not date_today - timedelta(hours=24) <= session_start: raise UserError(_("This session has been opened another day. To comply with the French law, you should close sessions on a daily basis. Please close session %s and open a new one.") % self.name) return True
def _get_acquisition_date(self): self.ensure_one() return babel.dates.format_date( date=Datetime.from_string(self.acquisition_date), format='MMMM y', locale=self._context.get('lang') or 'en_US' )
def test_leaves_timezones(self): self.env.user.tz = 'US/Alaska' # UTC-9 def to_tuple(interval): return (interval.start_datetime, interval.end_datetime) # Here we test if the leaves are correctly computed in the case our user is in tz Alaska # NB: Beware of winter/spring time work_no_tz = [to_tuple(x) for x in self.calendar._get_day_leave_intervals(Date.from_string('2018-12-25'), time(0), time(23, 59, 59), self.resource1_id)] self.assertEqual(work_no_tz[0], (Datetime.from_string('2018-12-25 17:00:00'), Datetime.from_string('2018-12-26 01:00:00'))) work_user_tz = [to_tuple(x) for x in self.calendar._get_day_leave_intervals(Date.from_string('2018-05-01'), time(0), time(23, 59, 59), self.resource1_id)] self.assertEqual(work_user_tz[0], (Datetime.from_string('2018-05-01 16:00:00'), Datetime.from_string('2018-05-02 00:00:00'))) work_spec = [to_tuple(x) for x in self.calendar._get_day_leave_intervals(Date.from_string('2018-04-06'), time(0), time(23, 59, 59), self.resource1_id)] self.assertEqual(work_spec[0], (Datetime.from_string('2018-04-06 16:00:00'), Datetime.from_string('2018-04-06 21:00:00')))
def test_calendar_working_day_intervals_leaves_generic(self): # Test: day0 with leaves outside range: 1 interval intervals = self.calendar.get_working_intervals_of_day(start_dt=Datetime.from_string('2013-02-12 07:00:00'), compute_leaves=True) self.assertEqual(len(intervals), 1) self.assertEqual(intervals[0], (Datetime.from_string('2013-02-12 08:00:00'), Datetime.from_string('2013-02-12 16:00:00'))) # Test: day0 with leaves: 2 intervals because of leave between 9 ans 12, ending at 15:45:30 intervals = self.calendar.get_working_intervals_of_day(start_dt=Datetime.from_string('2013-02-19 08:15:00'), end_dt=Datetime.from_string('2013-02-19 15:45:30'), compute_leaves=True) self.assertEqual(len(intervals), 2) self.assertEqual(intervals[0], (Datetime.from_string('2013-02-19 08:15:00'), Datetime.from_string('2013-02-19 09:00:00'))) self.assertEqual(intervals[1], (Datetime.from_string('2013-02-19 12:00:00'), Datetime.from_string('2013-02-19 15:45:30')))
def test_calendar_working_day_intervals_leaves_generic(self): # Test: day0 with leaves outside range: 1 interval intervals = self.calendar._get_day_work_intervals(Date.from_string('2013-02-12'), start_time=time(7, 0, 0), compute_leaves=True) self.assertEqual(len(intervals), 1) self.assertEqual(intervals[0][:2], (Datetime.from_string('2013-02-12 08:00:00'), Datetime.from_string('2013-02-12 16:00:00'))) # Test: day0 with leaves: 2 intervals because of leave between 9 and 12, ending at 15:45:30 intervals = self.calendar._get_day_work_intervals(Date.from_string('2013-02-19'), start_time=time(8, 15, 0), end_time=time(15, 45, 30), compute_leaves=True) self.assertEqual(len(intervals), 2) self.assertEqual(intervals[0][:2], (Datetime.from_string('2013-02-19 08:15:00'), Datetime.from_string('2013-02-19 09:00:00'))) self.assertEqual(intervals[1][:2], (Datetime.from_string('2013-02-19 12:00:00'), Datetime.from_string('2013-02-19 15:45:30'))) self.assertEqual(intervals[0][2]['attendances'], self.att_1) self.assertEqual(intervals[0][2]['leaves'], self.leave1) self.assertEqual(intervals[1][2]['attendances'], self.att_1) self.assertEqual(intervals[0][2]['leaves'], self.leave1)
def test_calendar_working_day_intervals_leaves_resource(self): # Test: day1+14 on leave, with resource leave computation intervals = self.calendar.get_working_intervals_of_day( Datetime.from_string('2013-02-26 07:00:00'), compute_leaves=True, resource_id=self.resource1_id ) # Result: nothing, because on leave self.assertEqual(len(intervals), 0, 'resource_calendar: wrong working interval/day computing')
def setUp(self): super(TestTimeType, self).setUp() Leave = self.env['resource.calendar.leaves'] self.other1 = Leave.create({ 'name': 'Formation', 'calendar_id': self.calendar.id, 'resource_id': self.resource1_id, 'date_from': Datetime.from_string('2013-02-15 09:00:00'), 'date_to': Datetime.from_string('2013-02-15 19:00:00'), 'time_type': 'other', }) self.other2 = Leave.create({ 'name': 'Homeworking', 'calendar_id': self.calendar.id, 'resource_id': self.resource1_id, 'date_from': Datetime.from_string('2013-02-12 09:00:00'), 'date_to': Datetime.from_string('2013-02-12 15:00:00'), 'time_type': 'other', })
def test_calendar_working_day_intervals_no_leaves(self): # Test: day0 without leaves: 1 interval intervals = self.calendar._get_day_work_intervals(Date.from_string('2013-02-12'), start_time=time(9, 8, 7)) self.assertEqual(len(intervals), 1) self.assertEqual(intervals[0][:2], (Datetime.from_string('2013-02-12 09:08:07'), Datetime.from_string('2013-02-12 16:00:00'))) self.assertEqual(intervals[0][2]['attendances'], self.att_1) # Test: day1, beginning at 10:30 -> work from 10:30 (arrival) until 16:00 intervals = self.calendar._get_day_work_intervals(Date.from_string('2013-02-19'), start_time=time(10, 30, 0)) self.assertEqual(len(intervals), 1) self.assertEqual(intervals[0][:2], (Datetime.from_string('2013-02-19 10:30:00'), Datetime.from_string('2013-02-19 16:00:00'))) self.assertEqual(intervals[0][2]['attendances'], self.att_1) # Test: day3 without leaves: 2 interval intervals = self.calendar._get_day_work_intervals(Date.from_string('2013-02-15'), start_time=time(10, 11, 12)) self.assertEqual(len(intervals), 2) self.assertEqual(intervals[0][:2], (Datetime.from_string('2013-02-15 10:11:12'), Datetime.from_string('2013-02-15 13:00:00'))) self.assertEqual(intervals[1][:2], (Datetime.from_string('2013-02-15 16:00:00'), Datetime.from_string('2013-02-15 23:00:00'))) self.assertEqual(intervals[0][2]['attendances'], self.att_2) self.assertEqual(intervals[1][2]['attendances'], self.att_3)
def ctx_tz(record, field): res_lang = None ctx = record._context tz_name = pytz.timezone(ctx.get('tz') or record.env.user.tz) timestamp = Datetime.from_string(record[field]) if ctx.get('lang'): res_lang = record.env['res.lang'].search([('code', '=', ctx['lang'])], limit=1) if res_lang: timestamp = pytz.utc.localize(timestamp, is_dst=False) return datetime.strftime(timestamp.astimezone(tz_name), res_lang.date_format + ' ' + res_lang.time_format) return Datetime.context_timestamp(record, timestamp)
def test_days_count_with_domain(self): self.test.resource_id.write({ 'user_id': self.lost_user.id, }) self.env['resource.calendar.leaves'].sudo(self.lost_user).create({ 'name': 'first', 'calendar_id': self.test.resource_calendar_id.id, 'resource_id': self.test.resource_id.id, 'date_from': to_naive_utc(Datetime.from_string('2018-02-05 08:00:00'), self.lost_user), 'date_to': to_naive_utc(Datetime.from_string('2018-02-09 18:00:00'), self.lost_user) }) self.env['resource.calendar.leaves'].sudo(self.lost_user).create({ 'name': 'second', 'calendar_id': self.test.resource_calendar_id.id, 'resource_id': self.test.resource_id.id, 'date_from': to_naive_utc(Datetime.from_string('2018-01-12 08:00:00'), self.lost_user), 'date_to': to_naive_utc(Datetime.from_string('2018-01-13 18:00:00'), self.lost_user) }) res = self.test.get_work_days_count( to_naive_utc(Datetime.from_string('2018-02-04 06:00:00'), self.env.user), to_naive_utc(Datetime.from_string('2018-02-14 20:00:00'), self.env.user), domain=[('name', '=', '')] ) self.assertEqual(res, 3.0) res = self.test.get_work_days_count( to_naive_utc(Datetime.from_string('2018-02-04 06:00:00'), self.env.user), to_naive_utc(Datetime.from_string('2018-02-14 20:00:00'), self.env.user), domain=[('name', '=', 'first')] ) self.assertEqual(res, 1.0) res = self.test.get_leaves_day_count( to_naive_utc(Datetime.from_string('2018-02-04 06:00:00'), self.env.user), to_naive_utc(Datetime.from_string('2018-02-14 20:00:00'), self.env.user), domain=[('name', '=', 'first')] ) self.assertEqual(res, 2.0)
def test_calendar_timezone(self): # user in timezone UTC-9 asks for work hours # Limits: between 2013-02-19 10:00:00 and 2013-02-26 15:30:00 (User TZ) # between 2013-02-19 19:00:00 and 2013-02-27 00:30:00 (UTC) # Leaves: between 2013-02-21 10:00:00 and 2013-02-26 12:00:00 (User TZ) # res: 19/02 (10-16 (beginning)) + 22/02 (0 (leave)) + 26/02 (12-15.30 (leave+ending)) self.env.user.tz = 'US/Alaska' (self.leave1 | self.leave2 | self.leave3).unlink() leave = self.env['resource.calendar.leaves'].create({ 'name': 'Timezoned Leaves', 'calendar_id': self.calendar.id, 'resource_id': self.resource1_id, 'date_from': to_naive_utc(Datetime.from_string('2013-02-21 10:00:00'), self.env.user), 'date_to': to_naive_utc(Datetime.from_string('2013-02-26 12:00:00'), self.env.user) }) res = self.calendar.get_work_hours_count( to_naive_utc(Datetime.from_string('2013-02-19 10:00:00'), self.env.user), to_naive_utc(Datetime.from_string('2013-02-26 15:30:00'), self.env.user), self.resource1_id, compute_leaves=True) self.assertEqual(res, 9.5)
def _check_delay(self, action, record, record_dt): """ Override the check of delay to try to use a user-related calendar. If no calendar is found, fallback on the default behavior. """ if action.trg_date_calendar_id and action.trg_date_range_type == 'day' and action.trg_date_resource_field_id: user = record[action.trg_date_resource_field_id.name] if user.employee_ids and user.employee_ids[0].contract_id and user.employee_ids[0].contract_id.working_hours: calendar = user.employee_ids[0].contract_id.working_hours start_dt = Datetime.from_string(record_dt) resource_id = user.employee_ids[0].resource_id.id return calendar.schedule_days_get_date(action.trg_date_range, day_date=start_dt, compute_leaves=True, resource_id=resource_id) return super(BaseActionRule, self)._check_delay(action, record, record_dt)
def test_work_days_count_timezones_ultra(self): # user in timezone UTC+4 is attached to the resource and create leaves self.test.resource_id.write({ 'user_id': self.lost_user.id, }) reunion_leave = self.env['resource.calendar.leaves'].sudo(self.lost_user).create({ 'name': 'Timezoned Leaves', 'calendar_id': self.test.resource_calendar_id.id, 'resource_id': self.test.resource_id.id, 'date_from': to_naive_utc(Datetime.from_string('2013-02-12 10:00:00'), self.lost_user), 'date_to': to_naive_utc(Datetime.from_string('2013-02-12 12:00:00'), self.lost_user) }) self.assertEqual(reunion_leave.tz, 'Indian/Reunion') # user in timezone UTC-9 read and manipulate leaves self.env.user.tz = 'US/Alaska' res = self.test.get_work_days_data( to_naive_utc(Datetime.from_string('2013-02-12 06:00:00'), self.env.user), to_naive_utc(Datetime.from_string('2013-02-12 20:00:00'), self.env.user)) self.assertEqual(res['days'], 0.75) self.assertEqual(res['hours'], 6.0) # user in timezone UTC+4 read and manipulate leaves res = self.test.sudo(self.lost_user).get_work_days_data( to_naive_utc(Datetime.from_string('2013-02-12 06:00:00'), self.env.user), to_naive_utc(Datetime.from_string('2013-02-12 20:00:00'), self.env.user)) self.assertEqual(res['days'], 0.75) self.assertEqual(res['hours'], 6.0)
def setUp(self): super(TestGlobalLeaves, self).setUp() self.Leave = self.env['resource.calendar.leaves'] # This leave has a timezone of False : UTC should be used as default self.global_no_tz = self.Leave.create({ 'name': 'global no timezone', 'calendar_id': self.calendar.id, 'date_from': to_naive_utc(Datetime.from_string('2018-12-25 08:00:00'), self.env.user), 'date_to': to_naive_utc(Datetime.from_string('2018-12-25 23:00:00'), self.env.user), 'tz': False, }) # This leave has no timezone defined : should default to user timezone (here UTC) self.global_user_tz = self.Leave.create({ 'name': 'global user timezone', 'calendar_id': self.calendar.id, 'date_from': to_naive_utc(Datetime.from_string('2018-05-01 08:00:00'), self.env.user), 'date_to': to_naive_utc(Datetime.from_string('2018-05-01 23:00:00'), self.env.user), }) # This leave has been taken in Japan timezone # Leave from 8:00 to 13:00 but we have to adapt cause we define it in UTC self.global_spec_tz = self.Leave.create({ 'name': 'global specific timezone', 'calendar_id': self.calendar.id, 'date_from': Datetime.from_string('2018-04-05 23:00:00'), 'date_to': Datetime.from_string('2018-04-06 04:00:00'), 'tz' : 'Japan', # UTC+9 })
def test_calendar_days_scheduling(self): res = self.calendar.plan_days( 5, Datetime.from_string('2013-02-12 09:08:07')) self.assertEqual(res.date(), Datetime.from_string('2013-02-26 00:00:00').date(), 'resource_calendar: wrong days scheduling') res = self.calendar.plan_days( -2, Datetime.from_string('2013-02-12 09:08:07')) self.assertEqual(res.date(), Datetime.from_string('2013-02-08 00:00:00').date(), 'resource_calendar: wrong days scheduling') res = self.calendar.plan_days( 5, Datetime.from_string('2013-02-12 09:08:07'), compute_leaves=True, resource_id=self.resource1_id) self.assertEqual(res.date(), Datetime.from_string('2013-03-01 00:00:00').date(), 'resource_calendar: wrong days scheduling')
def test_work_days_count_timezones_ultra(self): # user in timezone UTC+4 is attached to the resource and create leaves self.test.resource_id.write({ 'user_id': self.lost_user.id, }) reunion_leave = self.env['resource.calendar.leaves'].sudo( self.lost_user).create({ 'name': 'Timezoned Leaves', 'calendar_id': self.test.resource_calendar_id.id, 'resource_id': self.test.resource_id.id, 'date_from': to_naive_utc(Datetime.from_string('2013-02-12 10:00:00'), self.lost_user), 'date_to': to_naive_utc(Datetime.from_string('2013-02-12 12:00:00'), self.lost_user) }) self.assertEqual(reunion_leave.tz, 'Indian/Reunion') # user in timezone UTC-9 read and manipulate leaves self.env.user.tz = 'US/Alaska' res = self.test.get_work_days_data( to_naive_utc(Datetime.from_string('2013-02-12 06:00:00'), self.env.user), to_naive_utc(Datetime.from_string('2013-02-12 20:00:00'), self.env.user)) self.assertEqual(res['days'], 0.75) self.assertEqual(res['hours'], 6.0) # user in timezone UTC+4 read and manipulate leaves res = self.test.sudo(self.lost_user).get_work_days_data( to_naive_utc(Datetime.from_string('2013-02-12 06:00:00'), self.env.user), to_naive_utc(Datetime.from_string('2013-02-12 20:00:00'), self.env.user)) self.assertEqual(res['days'], 0.75) self.assertEqual(res['hours'], 6.0)
def test_calendar_leave_days_intervals_timezone(self): # _get_day_leave_intervals converts from the timezone # of the user into UTC self.env.user.tz = 'US/Alaska' (self.leave1 | self.leave2 | self.leave3).unlink() leave = self.env['resource.calendar.leaves'].create({ 'name': 'Timezoned Leaves', 'calendar_id': self.calendar.id, 'resource_id': self.resource1_id, 'date_from': to_naive_utc(Datetime.from_string('2013-02-21 10:00:00'), self.env.user), 'date_to': to_naive_utc(Datetime.from_string('2013-02-26 12:00:00'), self.env.user) }) def to_tuple(interval): return (interval.start_datetime, interval.end_datetime) intervals = self.calendar._get_day_leave_intervals( Date.from_string('2013-02-26'), time(10), time(18), self.resource1_id) self.assertEqual(to_tuple(intervals[0]), (Datetime.from_string('2013-02-26 19:00:00'), Datetime.from_string('2013-02-26 21:00:00'))) self.env.user.tz = 'Japan' intervals = self.calendar._get_day_leave_intervals( Date.from_string('2013-02-26'), time(10), time(18), self.resource1_id) self.assertEqual(to_tuple(intervals[0]), (Datetime.from_string('2013-02-26 01:00:00'), Datetime.from_string('2013-02-26 03:00:00')))
def test_04(self): """After 48 hours""" date = Datetime.to_string(Datetime.from_string('2014-01-03 00:00:00')) self.mock_datetime.now.return_value = date self.assertAlmostEqual(self.line.theoretical_amount, -2)
def test_01(self): """Start""" date = Datetime.to_string(Datetime.from_string('2014-01-01 00:00:00')) self.mock_datetime.now.return_value = date self.assertAlmostEqual(self.line.theoretical_amount, 0)
def test_40_calendar_hours_scheduling(self): """ Testing calendar hours scheduling """ res = self.calendar.schedule_hours(-40, day_dt=self.date1.replace(minute=0, second=0)) # current day, limited at 09:00 because of day_dt specified -> 1 hour self.assertEqual(res[-1][0], Datetime.from_string('2013-02-12 08:00:00'), 'resource_calendar: wrong hours scheduling') self.assertEqual(res[-1][1], Datetime.from_string('2013-02-12 09:00:00'), 'resource_calendar: wrong hours scheduling') # previous days: 5+7 hours / 8 hours / 5+7 hours -> 32 hours self.assertEqual(res[-2][0], Datetime.from_string('2013-02-08 16:00:00'), 'resource_calendar: wrong hours scheduling') self.assertEqual(res[-2][1], Datetime.from_string('2013-02-08 23:00:00'), 'resource_calendar: wrong hours scheduling') self.assertEqual(res[-3][0], Datetime.from_string('2013-02-08 08:00:00'), 'resource_calendar: wrong hours scheduling') self.assertEqual(res[-3][1], Datetime.from_string('2013-02-08 13:00:00'), 'resource_calendar: wrong hours scheduling') self.assertEqual(res[-4][0], Datetime.from_string('2013-02-05 08:00:00'), 'resource_calendar: wrong hours scheduling') self.assertEqual(res[-4][1], Datetime.from_string('2013-02-05 16:00:00'), 'resource_calendar: wrong hours scheduling') self.assertEqual(res[-5][0], Datetime.from_string('2013-02-01 16:00:00'), 'resource_calendar: wrong hours scheduling') self.assertEqual(res[-5][1], Datetime.from_string('2013-02-01 23:00:00'), 'resource_calendar: wrong hours scheduling') self.assertEqual(res[-6][0], Datetime.from_string('2013-02-01 08:00:00'), 'resource_calendar: wrong hours scheduling') self.assertEqual(res[-6][1], Datetime.from_string('2013-02-01 13:00:00'), 'resource_calendar: wrong hours scheduling') # 7 hours remaining self.assertEqual(res[-7][0], Datetime.from_string('2013-01-29 09:00:00'), 'resource_calendar: wrong hours scheduling') self.assertEqual(res[-7][1], Datetime.from_string('2013-01-29 16:00:00'), 'resource_calendar: wrong hours scheduling') # Compute scheduled hours td = timedelta() for item in res: td += item[1] - item[0] self.assertEqual( seconds(td) / 3600.0, 40.0, 'resource_calendar: wrong hours scheduling') # -------------------------------------------------- # Test2: schedule hours forward # -------------------------------------------------- res = self.calendar.schedule_hours(40, day_dt=self.date1.replace(minute=0, second=0)) self.assertEqual(res[0][0], Datetime.from_string('2013-02-12 09:00:00'), 'resource_calendar: wrong hours scheduling') self.assertEqual(res[0][1], Datetime.from_string('2013-02-12 16:00:00'), 'resource_calendar: wrong hours scheduling') self.assertEqual(res[1][0], Datetime.from_string('2013-02-15 08:00:00'), 'resource_calendar: wrong hours scheduling') self.assertEqual(res[1][1], Datetime.from_string('2013-02-15 13:00:00'), 'resource_calendar: wrong hours scheduling') self.assertEqual(res[2][0], Datetime.from_string('2013-02-15 16:00:00'), 'resource_calendar: wrong hours scheduling') self.assertEqual(res[2][1], Datetime.from_string('2013-02-15 23:00:00'), 'resource_calendar: wrong hours scheduling') self.assertEqual(res[3][0], Datetime.from_string('2013-02-19 08:00:00'), 'resource_calendar: wrong hours scheduling') self.assertEqual(res[3][1], Datetime.from_string('2013-02-19 16:00:00'), 'resource_calendar: wrong hours scheduling') self.assertEqual(res[4][0], Datetime.from_string('2013-02-22 08:00:00'), 'resource_calendar: wrong hours scheduling') self.assertEqual(res[4][1], Datetime.from_string('2013-02-22 13:00:00'), 'resource_calendar: wrong hours scheduling') self.assertEqual(res[5][0], Datetime.from_string('2013-02-22 16:00:00'), 'resource_calendar: wrong hours scheduling') self.assertEqual(res[5][1], Datetime.from_string('2013-02-22 23:00:00'), 'resource_calendar: wrong hours scheduling') self.assertEqual(res[6][0], Datetime.from_string('2013-02-26 08:00:00'), 'resource_calendar: wrong hours scheduling') self.assertEqual(res[6][1], Datetime.from_string('2013-02-26 09:00:00'), 'resource_calendar: wrong hours scheduling') td = timedelta() for item in res: td += item[1] - item[0] self.assertEqual( seconds(td) / 3600.0, 40.0, 'resource_calendar: wrong hours scheduling') res = self.calendar.schedule_hours(40, day_dt=self.date1.replace(minute=0, second=0), compute_leaves=True, resource_id=self.resource1_id) self.assertEqual(res[0][0], Datetime.from_string('2013-02-12 09:00:00'), 'resource_calendar: wrong hours scheduling') self.assertEqual(res[0][1], Datetime.from_string('2013-02-12 16:00:00'), 'resource_calendar: wrong hours scheduling') self.assertEqual(res[1][0], Datetime.from_string('2013-02-15 08:00:00'), 'resource_calendar: wrong hours scheduling') self.assertEqual(res[1][1], Datetime.from_string('2013-02-15 13:00:00'), 'resource_calendar: wrong hours scheduling') self.assertEqual(res[2][0], Datetime.from_string('2013-02-15 16:00:00'), 'resource_calendar: wrong hours scheduling') self.assertEqual(res[2][1], Datetime.from_string('2013-02-15 23:00:00'), 'resource_calendar: wrong hours scheduling') self.assertEqual(res[3][0], Datetime.from_string('2013-02-19 08:00:00'), 'resource_calendar: wrong hours scheduling') self.assertEqual(res[3][1], Datetime.from_string('2013-02-19 09:00:00'), 'resource_calendar: wrong hours scheduling') self.assertEqual(res[4][0], Datetime.from_string('2013-02-19 12:00:00'), 'resource_calendar: wrong hours scheduling') self.assertEqual(res[4][1], Datetime.from_string('2013-02-19 16:00:00'), 'resource_calendar: wrong hours scheduling') self.assertEqual(res[5][0], Datetime.from_string('2013-02-22 08:00:00'), 'resource_calendar: wrong hours scheduling') self.assertEqual(res[5][1], Datetime.from_string('2013-02-22 09:00:00'), 'resource_calendar: wrong hours scheduling') self.assertEqual(res[6][0], Datetime.from_string('2013-02-22 16:00:00'), 'resource_calendar: wrong hours scheduling') self.assertEqual(res[6][1], Datetime.from_string('2013-02-22 23:00:00'), 'resource_calendar: wrong hours scheduling') self.assertEqual(res[7][0], Datetime.from_string('2013-03-01 11:30:00'), 'resource_calendar: wrong hours scheduling') self.assertEqual(res[7][1], Datetime.from_string('2013-03-01 13:00:00'), 'resource_calendar: wrong hours scheduling') self.assertEqual(res[8][0], Datetime.from_string('2013-03-01 16:00:00'), 'resource_calendar: wrong hours scheduling') self.assertEqual(res[8][1], Datetime.from_string('2013-03-01 22:30:00'), 'resource_calendar: wrong hours scheduling') td = timedelta() for item in res: td += item[1] - item[0] self.assertEqual( seconds(td) / 3600.0, 40.0, 'resource_calendar: wrong hours scheduling') # -------------------------------------------------- # Test3: working hours (old _interval_hours_get) # -------------------------------------------------- # old API: resource without leaves # res: 2 weeks -> 40 hours res = self.calendar._interval_hours_get( 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) self.assertEqual( res, 40.0, 'resource_calendar: wrong _interval_hours_get compatibility computation' ) # new API: resource without leaves # res: 2 weeks -> 40 hours res = self.calendar.get_working_hours( 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) self.assertEqual( res, 40.0, 'resource_calendar: wrong get_working_hours computation') # old API: resource and leaves # res: 2 weeks -> 40 hours - (3+4) leave hours res = self.calendar._interval_hours_get( 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) self.assertEqual( res, 33.0, 'resource_calendar: wrong _interval_hours_get compatibility computation' ) # new API: resource and leaves # res: 2 weeks -> 40 hours - (3+4) leave hours res = self.calendar.get_working_hours( 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) self.assertEqual( res, 33.0, 'resource_calendar: wrong get_working_hours computation') # -------------------------------------------------- # Test4: misc # -------------------------------------------------- # Test without calendar and default_interval res = self.ResourceCalendar.with_context( self.context).get_working_hours(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)) self.assertEqual( res, 32.0, 'resource_calendar: wrong get_working_hours computation') self.att0_0_id = self.ResourceAttendance.with_context( self.context).create({ 'name': 'Att0', 'dayofweek': '0', 'hour_from': 7.5, 'hour_to': 12.5, 'calendar_id': self.calendar.id, }) self.att0_1_id = self.ResourceAttendance.with_context( self.context).create({ 'name': 'Att0', 'dayofweek': '0', 'hour_from': 13, 'hour_to': 14, 'calendar_id': self.calendar.id, }) date1 = Datetime.from_string('2013-02-11 07:30:00') date2 = Datetime.from_string('2013-02-11 14:00:00') res = self.calendar.get_working_hours(date1, date2, compute_leaves=False, resource_id=self.resource1_id) # 7h30 -> 12h30 = 5 / 13h -> 14h = 1 / -> 6h self.assertEqual( res, 6, 'resource_calendar: wrong get_working_hours computation')
def test_06(self): """After 50 days""" date = Datetime.to_string(Datetime.from_string('2014-02-20 00:00:00')) self.mock_datetime.now.return_value = date self.assertAlmostEqual(self.line.theoretical_amount, -50)
def test_10(self): """At last""" date = Datetime.to_string(Datetime.from_string('2014-12-31 00:00:00')) self.mock_datetime.now.return_value = date self.assertAlmostEqual(self.line.theoretical_amount, -364)
def test_contract_on_another_company(self): """ Test that the work entry generation still work if the contract is not on the same company than the employee (Internal Use Case) So when generating the work entries in Belgium, there is an issue when accessing to the time off in Hong Kong. """ company = self.env['res.company'].create({'name': 'Another Company'}) employee = self.env['hr.employee'].create({ 'name': 'New Employee', 'company_id': company.id, }) self.env['hr.contract'].create({ 'name': 'Employee Contract', 'employee_id': employee.id, 'date_start': Date.from_string('2015-01-01'), 'state': 'open', 'company_id': self.env.ref('base.main_company').id, 'wage': 4000, }) leave_type = self.env['hr.leave.type'].create({ 'name': 'Sick', 'request_unit': 'hour', 'leave_validation_type': 'both', 'allocation_type': 'no', 'company_id': company.id, }) leave1 = self.env['hr.leave'].create({ 'name': 'Sick 1 week during christmas snif', 'employee_id': employee.id, 'holiday_status_id': leave_type.id, 'date_from': Datetime.from_string('2019-12-23 06:00:00'), 'date_to': Datetime.from_string('2019-12-27 20:00:00'), 'number_of_days': 5, }) leave1.action_approve() leave1.action_validate() # The work entries generation shouldn't raise an error user = self.env['res.users'].create({ 'name': 'Classic User', 'login': '******', 'company_id': self.env.ref('base.main_company').id, 'company_ids': self.env.ref('base.main_company').ids, 'groups_id': [(6, 0, [ self.env.ref('hr_contract.group_hr_contract_manager').id, self.env.ref('base.group_user').id ])], }) self.env['hr.employee'].with_user(user).generate_work_entries( '2019-12-01', '2019-12-31')
def test_calendar_hours_scheduling_forward(self): res = self.calendar._schedule_hours( 40, day_dt=Datetime.from_string('2013-02-12 09:00:00')) self.assertEqual(res[0][:2], (Datetime.from_string('2013-02-12 09:00:00'), Datetime.from_string('2013-02-12 16:00:00'))) self.assertEqual(res[1][:2], (Datetime.from_string('2013-02-15 08:00:00'), Datetime.from_string('2013-02-15 13:00:00'))) self.assertEqual(res[2][:2], (Datetime.from_string('2013-02-15 16:00:00'), Datetime.from_string('2013-02-15 23:00:00'))) self.assertEqual(res[3][:2], (Datetime.from_string('2013-02-19 08:00:00'), Datetime.from_string('2013-02-19 16:00:00'))) self.assertEqual(res[4][:2], (Datetime.from_string('2013-02-22 08:00:00'), Datetime.from_string('2013-02-22 13:00:00'))) self.assertEqual(res[5][:2], (Datetime.from_string('2013-02-22 16:00:00'), Datetime.from_string('2013-02-22 23:00:00'))) self.assertEqual(res[6][:2], (Datetime.from_string('2013-02-26 08:00:00'), Datetime.from_string('2013-02-26 09:00:00'))) td = timedelta() for item in res: td += item[1] - item[0] self.assertEqual(td.total_seconds() / 3600.0, 40.0) res = self.calendar.plan_hours( 40, day_dt=Datetime.from_string('2013-02-12 09:00:00')) self.assertEqual(res, Datetime.from_string('2013-02-26 09:00:00'))
def setUp(self): super(TestResourceCommon, self).setUp() self.context = context = dict(tz='UTC') self.env['res.users'].browse(self.env.uid).with_context(context).write( {'tz': 'UTC'}) # Usefull models self.Resource = self.env['resource.resource'] self.ResourceCalendar = self.env['resource.calendar'] self.ResourceAttendance = self.env['resource.calendar.attendance'] self.ResourceLeaves = self.env['resource.calendar.leaves'] # Some demo data self.date1 = Datetime.from_string( '2013-02-12 09:08:07' ) # weekday() returns 1, isoweekday() returns 2 self.date2 = Datetime.from_string( '2013-02-15 10:11:12' ) # weekday() returns 4, isoweekday() returns 5 # Leave1: 19/02/2013, from 9 to 12, is a day 1 self.leave1_start = Datetime.from_string('2013-02-19 09:00:00') self.leave1_end = Datetime.from_string('2013-02-19 12:00:00') # Leave2: 22/02/2013, from 9 to 15, is a day 4 self.leave2_start = Datetime.from_string('2013-02-22 09:00:00') self.leave2_end = Datetime.from_string('2013-02-22 15:00:00') # Leave3: 25/02/2013 (day0) -> 01/03/2013 (day4) self.leave3_start = Datetime.from_string('2013-02-25 13:00:00') self.leave3_end = Datetime.from_string('2013-03-01 11:30:00') # Resource data # Calendar working days: 1 (8-16 -> 8hours), 4 (8-13, 16-23 -> 12hours) self.calendar = self.ResourceCalendar.with_context(context).create({ 'name': 'TestCalendar', }) self.att1_id = self.ResourceAttendance.with_context(context).create({ 'name': 'Att1', 'dayofweek': '1', 'hour_from': 8, 'hour_to': 16, 'calendar_id': self.calendar.id, }).id self.att2_id = self.ResourceAttendance.with_context(context).create({ 'name': 'Att2', 'dayofweek': '4', 'hour_from': 8, 'hour_to': 13, 'calendar_id': self.calendar.id, }).id self.att3_id = self.ResourceAttendance.with_context(context).create({ 'name': 'Att3', 'dayofweek': '4', 'hour_from': 16, 'hour_to': 23, 'calendar_id': self.calendar.id, }).id self.resource1_id = self.Resource.with_context(context).create({ 'name': 'TestResource1', 'resource_type': 'user', 'time_efficiency': 150.0, 'calendar_id': self.calendar.id, }).id self.leave1_id = self.ResourceLeaves.with_context(context).create({ 'name': 'GenericLeave', 'calendar_id': self.calendar.id, 'date_from': self.leave1_start, 'date_to': self.leave1_end, }).id self.leave2_id = self.ResourceLeaves.with_context(context).create({ 'name': 'ResourceLeave', 'calendar_id': self.calendar.id, 'resource_id': self.resource1_id, 'date_from': self.leave2_start, 'date_to': self.leave2_end, }).id self.leave3_id = self.ResourceLeaves.with_context(context).create({ 'name': 'ResourceLeave2', 'calendar_id': self.calendar.id, 'resource_id': self.resource1_id, 'date_from': self.leave3_start, 'date_to': self.leave3_end, }).id
def setUp(self): super(TestIntervals, self).setUp() # Some data intervals # - first one is included in second one # - second one is extended by third one # - sixth one is included in fourth one # - fifth one is prior to other one # Once cleaned: 1 interval 03/02 8-10), 2 intervals 04/02 (8-14 + 17-21) self.intervals = [ self.calendar._interval_new( Datetime.from_string('2013-02-04 09:00:00'), Datetime.from_string('2013-02-04 11:00:00')), self.calendar._interval_new( Datetime.from_string('2013-02-04 08:00:00'), Datetime.from_string('2013-02-04 12:00:00')), self.calendar._interval_new( Datetime.from_string('2013-02-04 11:00:00'), Datetime.from_string('2013-02-04 14:00:00')), self.calendar._interval_new( Datetime.from_string('2013-02-04 17:00:00'), Datetime.from_string('2013-02-04 21:00:00')), self.calendar._interval_new( Datetime.from_string('2013-02-03 08:00:00'), Datetime.from_string('2013-02-03 10:00:00')), self.calendar._interval_new( Datetime.from_string('2013-02-04 18:00:00'), Datetime.from_string('2013-02-04 19:00:00')) ]
def test_calendar_hours_scheduling_backward(self): res = self.calendar._schedule_hours( -40, day_dt=Datetime.from_string('2013-02-12 09:00:00')) # current day, limited at 09:00 because of day_dt specified -> 1 hour self.assertEqual(res[-1][:2], (Datetime.from_string('2013-02-12 08:00:00'), Datetime.from_string('2013-02-12 09:00:00'))) # previous days: 5+7 hours / 8 hours / 5+7 hours -> 32 hours self.assertEqual(res[-2][:2], (Datetime.from_string('2013-02-08 16:00:00'), Datetime.from_string('2013-02-08 23:00:00'))) self.assertEqual(res[-3][:2], (Datetime.from_string('2013-02-08 08:00:00'), Datetime.from_string('2013-02-08 13:00:00'))) self.assertEqual(res[-4][:2], (Datetime.from_string('2013-02-05 08:00:00'), Datetime.from_string('2013-02-05 16:00:00'))) self.assertEqual(res[-5][:2], (Datetime.from_string('2013-02-01 16:00:00'), Datetime.from_string('2013-02-01 23:00:00'))) self.assertEqual(res[-6][:2], (Datetime.from_string('2013-02-01 08:00:00'), Datetime.from_string('2013-02-01 13:00:00'))) # 7 hours remaining self.assertEqual(res[-7][:2], (Datetime.from_string('2013-01-29 09:00:00'), Datetime.from_string('2013-01-29 16:00:00'))) # Compute scheduled hours td = timedelta() for item in res: td += item[1] - item[0] self.assertEqual(td.total_seconds() / 3600.0, 40.0) res = self.calendar.plan_hours( -40, day_dt=Datetime.from_string('2013-02-12 09:00:00')) self.assertEqual(res, Datetime.from_string('2013-01-29 09:00:00'))
def recompute_effective_numbers(self): for revision in self: start_date = revision.week_start_date end_date = revision.week_end_date # Holds created in the period demand_search = [ ('create_date', '>=', start_date), ('create_date', '<=', end_date), ] resupply_search = [ ('expiration_date', '>=', start_date), ('expiration_date', '<=', end_date), ] if revision.type == 'web': demand_search.append(('channel', '=', 'web')) resupply_search.append(('channel', '=', 'web')) elif revision.type == 'ambassador': demand_search.append(('channel', '=', 'ambassador')) resupply_search.append(('channel', '=', 'ambassador')) elif revision.type == 'events': demand_search.append(('channel', '=', 'event')) resupply_search.append(('channel', '=', 'event')) elif revision.type == 'sub': demand_search.append(('channel', '=', 'sub')) resupply_search.append(('channel', '=', 'sub')) elif revision.type == 'cancel': # This is a special case where we have no holds requested # and only resupply by sponsorships cancelled. cancellations = self.env['recurring.contract'].search([ ('type', 'like', 'S'), ('state', '=', 'terminated'), ('end_date', '>=', start_date), ('end_date', '<=', end_date), ('end_date', '!=', False), ('hold_expiration_date', '!=', False), ('end_reason', '!=', '1'), ]) # Cancellations for which we didn't keep the child on hold resupply = len(cancellations.filtered(lambda c: ( Datetime.from_string(c.hold_expiration_date) - Datetime.from_string(c.end_date)).total_seconds() < 60 )) # Sponsor Cancel Holds that were released resupply_search.extend([ ('channel', '=', 'sponsor_cancel'), ('type', '=', HoldType.SPONSOR_CANCEL_HOLD.value), ]) resupply += self.env['compassion.hold'].search_count( resupply_search) revision.effective_resupply = resupply continue hold_obj = self.env['compassion.hold'] nb_holds = hold_obj.search_count(demand_search) resupply = hold_obj.search_count(resupply_search) revision.write({ 'holds': nb_holds, 'effective_resupply': resupply, }) return True
def recompute_effective_numbers(self): depart = self.env.ref("sponsorship_compassion.end_reason_depart") for revision in self: start_date = revision.week_start_date end_date = revision.week_end_date # Holds created in the period demand_search = [ ("create_date", ">=", start_date), ("create_date", "<=", end_date), ] resupply_search = [ ("expiration_date", ">=", start_date), ("expiration_date", "<=", end_date), ] if revision.type == "web": demand_search.append(("channel", "=", "web")) resupply_search.append(("channel", "=", "web")) elif revision.type == "ambassador": demand_search.append(("channel", "=", "ambassador")) resupply_search.append(("channel", "=", "ambassador")) elif revision.type == "events": demand_search.append(("channel", "=", "event")) resupply_search.append(("channel", "=", "event")) elif revision.type == "sub": demand_search.append(("channel", "=", "sub")) resupply_search.append(("channel", "=", "sub")) elif revision.type == "cancel": # This is a special case where we have no holds requested # and only resupply by sponsorships cancelled. cancellations = self.env["recurring.contract"].search([ ("type", "like", "S"), ("state", "=", "terminated"), ("end_date", ">=", start_date), ("end_date", "<=", end_date), ("end_date", "!=", False), ("hold_expiration_date", "!=", False), ("end_reason_id", "!=", depart.id), ]) # Cancellations for which we didn't keep the child on hold resupply = len( cancellations.filtered(lambda c: (Datetime.from_string( c.hold_expiration_date) - Datetime.from_string( c.end_date)).total_seconds() < 60)) # Sponsor Cancel Holds that were released resupply_search.extend([ ("channel", "=", "sponsor_cancel"), ("type", "=", HoldType.SPONSOR_CANCEL_HOLD.value), ]) resupply += self.env["compassion.hold"].search_count( resupply_search) revision.effective_resupply = resupply continue hold_obj = self.env["compassion.hold"] nb_holds = hold_obj.search_count(demand_search) resupply = hold_obj.search_count(resupply_search) revision.write({ "holds": nb_holds, "effective_resupply": resupply, }) return True
def generate_xlsx_report(self, workbook, data, attendances): # Setup sheet and data report_name = "ATTENDANCE FROM " + str( data['form']['date_from']) + " TO " + data['form']['date_to'] all_employees = self.env['hr.employee'].search([]) # Parse date from and date to type date date_from = datetime.strptime(data['form']['date_from'], "%Y-%m-%d") date_to = datetime.strptime(data['form']['date_to'], "%Y-%m-%d") # Get all dates between the date from and date to dates dates = [] delta = date_to - date_from # as timedelta for i in range(delta.days + 1): day = date_from + timedelta(days=i) dates.append(day) employees = all_employees[:] employees = employees.sorted(lambda e: e.department_id.sequence if e.department_id else 1000) # Setup columns sheet = workbook.add_worksheet(report_name[:31]) titles = workbook.add_format({'align': 'center', 'bold': True}) center = workbook.add_format({'align': 'center'}) t_heading = workbook.add_format({ 'align': 'center', 'bold': True, 'bg_color': '#BD5B5B', 'border': 1, 'valign': 'vcenter' }) sheet.set_column('B:B', 10) sheet.set_column('C:C', 35) sheet.set_column('D:D', 30) sheet.set_column('E:E', 35) # Add company logo # logo = self.env.user.sudo().company_id.logo # imgdata = base64.b64decode(logo) # image = io.BytesIO(imgdata) # sheet.insert_image(0, 1, 'python.png', {'x_scale': 0.5, 'y_scale': 0.5, 'image_data': image}) # Print dates between date from and date to dates_column = 5 dates_format = workbook.add_format({'align': 'center'}) for a_date in dates: sheet.merge_range(6, dates_column, 6, dates_column + 1, a_date.strftime("%d-%b"), dates_format) sheet.set_column(dates_column + 2, dates_column + 2, 15) sheet.write_row(7, dates_column, ['Enter', 'Exit', 'Working Hours'], t_heading) dates_column += 3 # Headings and titles sheet.merge_range(0, 2, 0, dates_column, 'HR DEPARTMENT', titles) sheet.merge_range(1, 2, 1, dates_column, 'ATTENDANCE REPORT', titles) sheet.merge_range(3, 2, 3, dates_column, "AVERAGE WORKING HOURS", titles) sheet.merge_range( 5, 2, 5, dates_column, 'FROM : ' + date_from.strftime("%d-%b") + ' TO : ' + date_to.strftime("%d-%b"), center) sheet.write_row('B8', ['Employee \nID', 'Name', 'Job Title', 'Department'], t_heading) # Continue titles and company logo after days printed # sheet.insert_image(0, dates_column, 'python.png', {'x_scale': 0.5, 'y_scale': 0.5, 'image_data': image}) sheet.set_column(dates_column, dates_column, 11) sheet.write(7, dates_column, 'Average \nWorking \nHours', t_heading) sheet.set_row(7, 60) row = 1 for obj in employees: num_days = 0 total_hours = 0 if len(obj.machine_attendance_ids) > 0: rgb_color = obj.department_id.color if not rgb_color: rgb_color = "rgba(255,0,0,1)" color = '#FFFFFF' if len(rgb_color) > 1: color = rgb_to_hex( eval(rgb_color[rgb_color.index('('):rgb_color. rindex(',')] + ")")) color = color.upper() emp_id = workbook.add_format({ 'bg_color': '#F09481', 'align': 'center', 'border': 1 }) attendance = workbook.add_format({ 'bg_color': color, 'align': 'center', 'border': 1 }) time = workbook.add_format({ 'bg_color': 'silver', 'align': 'center', 'border': 1 }) sheet.write_row('B' + str(row + 8), [row], emp_id) sheet.write_row('C' + str(row + 8), [ obj.name, obj.job_id.name or '-', obj.department_id.name or '-' ], attendance) employee_attendance_ids = \ obj.machine_attendance_ids.filtered(lambda a: date_to >= ODT.from_string(ODT.context_timestamp(a, ODT.from_string( a.punching_time)). strftime("%Y-%m-%d")) >= date_from) day_column = 5 for a_date in dates: a_date_attendances = employee_attendance_ids.filtered( lambda attend: ODT.context_timestamp( attend, ODT.from_string(attend.punching_time) ).strftime('%Y-%m-%d') == a_date.strftime("%Y-%m-%d")) if a_date_attendances: first_check_in_rec = a_date_attendances.sorted( lambda a: a.punching_time)[0] last_check_out_rec = a_date_attendances.sorted( lambda a: a.punching_time)[-1] first_check_in = first_check_in_rec.punching_time last_check_out = last_check_out_rec.punching_time worked_hours = 0 if first_check_in == last_check_out: last_check_out = '-' else: delta = datetime.strptime(last_check_out, DEFAULT_SERVER_DATETIME_FORMAT) - \ datetime.strptime(first_check_in, DEFAULT_SERVER_DATETIME_FORMAT) worked_hours = delta.total_seconds() / 3600.0 last_check_out = ODT.context_timestamp( obj, ODT.from_string(last_check_out)).strftime( '%H:%M') num_days += 1 total_hours += worked_hours first_check_in = ODT.context_timestamp( obj, ODT.from_string(first_check_in)).strftime('%H:%M') sheet.write_row(row + 7, day_column, [ first_check_in, last_check_out, round(worked_hours, 2) ], time) else: sheet.write_row(row + 7, day_column, ['-', '-', '-'], time) day_column += 3 employee_avg = 0 if num_days == 0 or total_hours == 0 else total_hours / num_days employee_avg = round(employee_avg, 2) sheet.write( row + 7, dates_column, employee_avg, workbook.add_format({ 'align': 'center', 'border': 1 })) row += 1
def test_simple_flow(self): date = Datetime.from_string( '2014-08-01 15:02:32') # so long, little task self.mock_datetime.now.return_value = date self.mock_datetime2.now.return_value = date Campaign = self.env['marketing.campaign'].with_user(self.user_market) Activity = self.env['marketing.activity'].with_user(self.user_market) MassMail = self.env['mailing.mailing'].with_user(self.user_market) ServerAction = self.env['ir.actions.server'].with_user( self.user_market) # Create campaign campaign = Campaign.create({ 'name': 'My First Campaign', 'model_id': self.test_model.id, 'domain': '%s' % ([('name', '!=', 'Invalid')]), }) # Create first activity flow mass_mailing = MassMail.create({ 'name': 'Hello', 'subject': 'Hello', 'body_html': '<div>My Email Body</div>', 'mailing_model_id': self.test_model.id, 'use_in_marketing_automation': True, }) act_0 = Activity.create({ 'name': 'Enter the campaign', 'campaign_id': campaign.id, 'activity_type': 'email', 'mass_mailing_id': mass_mailing.id, 'trigger_type': 'begin', 'interval_number': '0', }) # NOTSURE: let us consider currently that a smart admin created the server action for the marketing user, is probably the case actually server_action = ServerAction.sudo().create({ 'name': 'Update name', 'state': 'code', 'model_id': self.test_model.id, 'code': ''' for record in records: record.write({'name': record.name + 'SA'})''' }) act_1 = Activity.create({ 'name': 'Update name', 'activity_domain': '%s' % ([('name', 'ilike', 'Test')]), 'campaign_id': campaign.id, 'parent_id': act_0.id, 'activity_type': 'action', 'server_action_id': server_action.id, 'trigger_type': 'act', 'interval_number': '1', 'interval_type': 'hours', }) # User starts and syncs its campaign campaign.action_start_campaign() self.assertEqual(campaign.state, 'running') campaign.sync_participants() # All records not containing Invalid should be added as participants self.assertEqual(campaign.running_participant_count, 4) self.assertEqual( set(campaign.participant_ids.mapped('res_id')), set((self.test_rec1 | self.test_rec2 | self.test_rec3 | self.test_rec4).ids)) self.assertEqual(set(campaign.participant_ids.mapped('state')), set(['running'])) # Begin activity should contain a trace for each participant self.assertEqual( act_0.trace_ids.mapped('participant_id'), campaign.participant_ids, ) self.assertEqual(set(act_0.trace_ids.mapped('state')), set(['scheduled'])) self.assertEqual(set(act_0.trace_ids.mapped('schedule_date')), set([date])) # No other trace should have been created as the first one are waiting to be processed self.assertEqual(act_1.trace_ids, self.env['marketing.trace']) # First traces are processed, emails are sent with patch.object(IrMailServer, 'connect'): campaign.execute_activities() self.assertEqual(set(act_0.trace_ids.mapped('state')), set(['processed'])) # Child traces should have been generated for all traces of parent activity as filter is taken into account at processing, not generation self.assertEqual( set(act_1.trace_ids.mapped('participant_id.res_id')), set((self.test_rec1 | self.test_rec2 | self.test_rec3 | self.test_rec4).ids)) self.assertEqual(set(act_1.trace_ids.mapped('state')), set(['scheduled'])) self.assertEqual(set(act_1.trace_ids.mapped('schedule_date')), set([date + relativedelta(hours=1)])) # Traces are processed, but this is not the time to execute child traces campaign.execute_activities() self.assertEqual(set(act_1.trace_ids.mapped('state')), set(['scheduled'])) # Time is coming, a bit like the winter date = Datetime.from_string( '2014-08-01 17:02:32' ) # wow, a two hour span ! so much incredible ! self.mock_datetime.now.return_value = date self.mock_datetime2.now.return_value = date campaign.execute_activities() # There should be one rejected activity not matching the filter self.assertEqual( set( act_1.trace_ids.filtered(lambda tr: tr.participant_id.res_id != self.test_rec4.id).mapped('state')), set(['processed'])) self.assertEqual( set( act_1.trace_ids.filtered(lambda tr: tr.participant_id.res_id == self.test_rec4.id).mapped('state')), set(['rejected'])) # Check server action was actually processed self.assertTrue([ 'SA' in record.name for record in self.test_rec1 | self.test_rec2 | self.test_rec3 ]) self.assertTrue(['SA' not in record.name for record in self.test_rec4])
def test_calendar_hours_scheduling_forward_leaves_resource(self): res = self.calendar._schedule_hours( 40, day_dt=Datetime.from_string('2013-02-12 09:00:00'), compute_leaves=True, resource_id=self.resource1_id) self.assertEqual(res[0][:2], (Datetime.from_string('2013-02-12 09:00:00'), Datetime.from_string('2013-02-12 16:00:00'))) self.assertEqual(res[1][:2], (Datetime.from_string('2013-02-15 08:00:00'), Datetime.from_string('2013-02-15 13:00:00'))) self.assertEqual(res[2][:2], (Datetime.from_string('2013-02-15 16:00:00'), Datetime.from_string('2013-02-15 23:00:00'))) self.assertEqual(res[3][:2], (Datetime.from_string('2013-02-19 08:00:00'), Datetime.from_string('2013-02-19 09:00:00'))) self.assertEqual(res[4][:2], (Datetime.from_string('2013-02-19 12:00:00'), Datetime.from_string('2013-02-19 16:00:00'))) self.assertEqual(res[5][:2], (Datetime.from_string('2013-02-22 08:00:00'), Datetime.from_string('2013-02-22 09:00:00'))) self.assertEqual(res[6][:2], (Datetime.from_string('2013-02-22 16:00:00'), Datetime.from_string('2013-02-22 23:00:00'))) self.assertEqual(res[7][:2], (Datetime.from_string('2013-03-01 11:30:00'), Datetime.from_string('2013-03-01 13:00:00'))) self.assertEqual(res[8][:2], (Datetime.from_string('2013-03-01 16:00:00'), Datetime.from_string('2013-03-01 22:30:00'))) td = timedelta() for item in res: td += item[1] - item[0] self.assertEqual(td.total_seconds() / 3600.0, 40.0)
def action_update_participants(self): """ Synchronizes all participants based campaign activities demanding synchronization It is done in 2 part: * update traces related to updated activities. This means basically recomputing the schedule date * creating new traces for activities recently added in the workflow : * 'begin' activities simple create new traces for all running participants; * other activities: create child for traces linked to the parent of the newly created activity * we consider scheduling to be done after parent processing, independently of other time considerations * for 'not' triggers take into account brother traces that could be already processed """ for campaign in self: # Action 1: On activity modification modified_activities = campaign.marketing_activity_ids.filtered( lambda activity: activity.require_sync) traces_to_reschedule = self.env['marketing.trace'].search([ ('state', '=', 'scheduled'), ('activity_id', 'in', modified_activities.ids) ]) for trace in traces_to_reschedule: trace_offset = relativedelta( **{ trace.activity_id.interval_type: trace.activity_id.interval_number }) trigger_type = trace.activity_id.trigger_type if trigger_type == 'begin': trace.schedule_date = Datetime.from_string( trace.participant_id.create_date) + trace_offset elif trigger_type in [ 'act', 'mail_not_open', 'mail_not_click', 'mail_not_reply' ] and trace.parent_id: trace.schedule_date = Datetime.from_string( trace.parent_id.schedule_date) + trace_offset elif trace.parent_id: process_dt = trace.parent_id.mailing_trace_ids.state_update trace.schedule_date = Datetime.from_string( process_dt) + trace_offset # Action 2: On activity creation created_activities = campaign.marketing_activity_ids.filtered( lambda a: a.create_date >= campaign.last_sync_date) for activity in created_activities: activity_offset = relativedelta( **{activity.interval_type: activity.interval_number}) # Case 1: Trigger = begin # Create new root traces for all running participants -> consider campaign begin date is now to avoid spamming participants if activity.trigger_type == 'begin': participants = self.env['marketing.participant'].search([ ('state', '=', 'running'), ('campaign_id', '=', campaign.id) ]) for participant in participants: schedule_date = Datetime.from_string( Datetime.now()) + activity_offset self.env['marketing.trace'].create({ 'activity_id': activity.id, 'participant_id': participant.id, 'schedule_date': schedule_date, }) else: valid_parent_traces = self.env['marketing.trace'].search([ ('state', '=', 'processed'), ('activity_id', '=', activity.parent_id.id) ]) # avoid creating new traces that would have processed brother traces already processed # example: do not create a mail_not_click trace if mail_click is already processed if activity.trigger_type in [ 'mail_not_open', 'mail_not_click', 'mail_not_reply' ]: opposite_trigger = activity.trigger_type.replace( '_not_', '_') brother_traces = self.env['marketing.trace'].search([ ('parent_id', 'in', valid_parent_traces.ids), ('trigger_type', '=', opposite_trigger), ('state', '=', 'processed'), ]) valid_parent_traces = valid_parent_traces - brother_traces.mapped( 'parent_id') valid_parent_traces.mapped('participant_id').filtered( lambda participant: participant.state == 'completed' ).action_set_running() for parent_trace in valid_parent_traces: self.env['marketing.trace'].create({ 'activity_id': activity.id, 'participant_id': parent_trace.participant_id.id, 'parent_id': parent_trace.id, 'schedule_date': Datetime.from_string(parent_trace.schedule_date) + activity_offset, }) self.action_set_synchronized()
def setUpClass(cls): super(TestLeadConvertCommon, cls).setUpClass() # Sales Team organization # Role: M (team member) R (team manager) # SALESMAN---------------sales_team_1-----sales_team_convert # admin------------------M----------------/ (sales_team_1_m2) # user_sales_manager-----R----------------R # user_sales_leads-------M----------------/ (sales_team_1_m1) # user_sales_salesman----/----------------M (sales_team_convert_m1) # Stages Team organization # Name-------------------ST-------------------Sequ # stage_team1_1----------sales_team_1---------1 # stage_team1_2----------sales_team_1---------5 # stage_team1_won--------sales_team_1---------70 # stage_gen_1------------/--------------------3 # stage_gen_won----------/--------------------30 # stage_team_convert_1---sales_team_convert---1 cls.sales_team_convert = cls.env['crm.team'].create({ 'name': 'Convert Sales Team', 'sequence': 10, 'alias_name': False, 'use_leads': True, 'use_opportunities': True, 'company_id': False, 'user_id': cls.user_sales_manager.id, 'assignment_domain': [('priority', 'in', ['1', '2', '3'])], }) cls.sales_team_convert_m1 = cls.env['crm.team.member'].create({ 'user_id': cls.user_sales_salesman.id, 'crm_team_id': cls.sales_team_convert.id, 'assignment_max': 30, 'assignment_domain': False, }) cls.stage_team_convert_1 = cls.env['crm.stage'].create({ 'name': 'New', 'sequence': 1, 'team_id': cls.sales_team_convert.id, }) cls.lead_1.write( {'date_open': Datetime.from_string('2020-01-15 11:30:00')}) cls.crm_lead_dt_patcher = patch( 'odoo.addons.crm.models.crm_lead.fields.Datetime', wraps=Datetime) cls.crm_lead_dt_mock = cls.crm_lead_dt_patcher.start()
def test_45_calendar_hours_scheduling_minutes(self): """ Testing minutes computation in calendar hours scheduling """ res = self.calendar.schedule_hours_get_date(-39, day_dt=self.date1.replace( minute=25, second=20)) self.assertEqual(res, Datetime.from_string('2013-01-29 10:25:20'))
def test_20_calendar_working_intervals(self): """ Testing working intervals computing method of resource.calendar """ # Test: day0 without leaves: 1 interval intervals = self.calendar.get_working_intervals_of_day( start_dt=self.date1) self.assertEqual(len(intervals), 1, 'resource_calendar: wrong working intervals') self.assertEqual(intervals[0][0], Datetime.from_string('2013-02-12 09:08:07'), 'resource_calendar: wrong working intervals') self.assertEqual(intervals[0][1], Datetime.from_string('2013-02-12 16:00:00'), 'resource_calendar: wrong working intervals') # Test: day3 without leaves: 2 interval intervals = self.calendar.get_working_intervals_of_day( start_dt=self.date2) self.assertEqual(len(intervals), 2, 'resource_calendar: wrong working intervals') self.assertEqual(intervals[0][0], Datetime.from_string('2013-02-15 10:11:12'), 'resource_calendar: wrong working intervals') self.assertEqual(intervals[0][1], Datetime.from_string('2013-02-15 13:00:00'), 'resource_calendar: wrong working intervals') self.assertEqual(intervals[1][0], Datetime.from_string('2013-02-15 16:00:00'), 'resource_calendar: wrong working intervals') self.assertEqual(intervals[1][1], Datetime.from_string('2013-02-15 23:00:00'), 'resource_calendar: wrong working intervals') # Test: day0 with leaves outside range: 1 interval intervals = self.calendar.get_working_intervals_of_day( start_dt=self.date1.replace(hour=0), compute_leaves=True) self.assertEqual(len(intervals), 1, 'resource_calendar: wrong working intervals') self.assertEqual(intervals[0][0], Datetime.from_string('2013-02-12 08:00:00'), 'resource_calendar: wrong working intervals') self.assertEqual(intervals[0][1], Datetime.from_string('2013-02-12 16:00:00'), 'resource_calendar: wrong working intervals') # Test: day0 with leaves: 2 intervals because of leave between 9 ans 12, ending at 15:45:30 intervals = self.calendar.get_working_intervals_of_day( 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) self.assertEqual(len(intervals), 2, 'resource_calendar: wrong working intervals') self.assertEqual(intervals[0][0], Datetime.from_string('2013-02-19 08:08:07'), 'resource_calendar: wrong working intervals') self.assertEqual(intervals[0][1], Datetime.from_string('2013-02-19 09:00:00'), 'resource_calendar: wrong working intervals') self.assertEqual(intervals[1][0], Datetime.from_string('2013-02-19 12:00:00'), 'resource_calendar: wrong working intervals') self.assertEqual(intervals[1][1], Datetime.from_string('2013-02-19 15:45:30'), 'resource_calendar: wrong working intervals')
def action_delayed_line(self): raise UserError( _('This line is scheduled for: %s. \n However it is now planned to ' 'arrive late.') % Dt.to_string( Dt.context_timestamp(self, Dt.from_string(self.date_planned))))
def test_lead_convert_batch_internals(self): """ Test internals of convert wizard, working in batch mode """ date = Datetime.from_string('2020-01-20 16:00:00') self.crm_lead_dt_mock.now.return_value = date lead_w_partner = self.lead_w_partner self.assertEqual(lead_w_partner.user_id, self.user_sales_manager) self.assertEqual(lead_w_partner.team_id, self.sales_team_1) self.assertEqual(lead_w_partner.stage_id, self.env['crm.stage']) lead_w_contact = self.lead_w_contact self.assertEqual(lead_w_contact.user_id, self.user_sales_salesman) self.assertEqual(lead_w_contact.team_id, self.sales_team_convert) self.assertEqual(lead_w_contact.stage_id, self.stage_gen_1) lead_w_email_lost = self.lead_w_email_lost self.assertEqual(lead_w_email_lost.user_id, self.user_sales_leads) self.assertEqual(lead_w_email_lost.team_id, self.sales_team_1) self.assertEqual(lead_w_email_lost.stage_id, self.stage_team1_2) lead_w_email_lost.action_set_lost() self.assertEqual(lead_w_email_lost.active, False) convert = self.env['crm.lead2opportunity.partner'].with_context({ 'active_model': 'crm.lead', 'active_id': self.lead_1.id, 'active_ids': (self.lead_1 | lead_w_partner | lead_w_contact | lead_w_email_lost).ids, }).create({}) # test internals of convert wizard # self.assertEqual(convert.lead_id, self.lead_1) self.assertEqual(convert.user_id, self.lead_1.user_id) self.assertEqual(convert.team_id, self.lead_1.team_id) self.assertFalse(convert.partner_id) self.assertEqual(convert.name, 'convert') self.assertEqual(convert.action, 'create') convert.action_apply() self.assertEqual(convert.user_id, self.user_sales_leads) self.assertEqual(convert.team_id, self.sales_team_1) # lost leads are not converted (see crm_lead.convert_opportunity()) self.assertFalse(lead_w_email_lost.active) self.assertFalse(lead_w_email_lost.date_conversion) self.assertEqual(lead_w_email_lost.partner_id, self.env['res.partner']) self.assertEqual(lead_w_email_lost.stage_id, self.stage_team1_2) # did not change # other leads are converted into opportunities for opp in (self.lead_1 | lead_w_partner | lead_w_contact): # team management update: opportunity linked to chosen wizard values self.assertEqual(opp.type, 'opportunity') self.assertTrue(opp.active) self.assertEqual(opp.user_id, convert.user_id) self.assertEqual(opp.team_id, convert.team_id) # dates update: convert set them to now self.assertEqual(opp.date_open, date) self.assertEqual(opp.date_conversion, date) # stage update (depends on previous value) if opp == self.lead_1: self.assertEqual(opp.stage_id, self.stage_team1_1) # did not change elif opp == lead_w_partner: self.assertEqual(opp.stage_id, self.stage_team1_1 ) # is set to default stage of sales_team_1 elif opp == lead_w_contact: self.assertEqual(opp.stage_id, self.stage_gen_1) # did not change else: self.assertFalse(True)
def test_00_intervals(self): intervals = [(Datetime.from_string('2013-02-04 09:00:00'), Datetime.from_string('2013-02-04 11:00:00')), (Datetime.from_string('2013-02-04 08:00:00'), Datetime.from_string('2013-02-04 12:00:00')), (Datetime.from_string('2013-02-04 11:00:00'), Datetime.from_string('2013-02-04 14:00:00')), (Datetime.from_string('2013-02-04 17:00:00'), Datetime.from_string('2013-02-04 21:00:00')), (Datetime.from_string('2013-02-03 08:00:00'), Datetime.from_string('2013-02-03 10:00:00')), (Datetime.from_string('2013-02-04 18:00:00'), Datetime.from_string('2013-02-04 19:00:00'))] # Test: interval cleaning cleaned_intervals = self.ResourceCalendar.interval_clean(intervals) self.assertEqual(len(cleaned_intervals), 3, 'resource_calendar: wrong interval cleaning') # First interval: 03, unchanged self.assertEqual(cleaned_intervals[0][0], Datetime.from_string('2013-02-03 08:00:00'), 'resource_calendar: wrong interval cleaning') self.assertEqual(cleaned_intervals[0][1], Datetime.from_string('2013-02-03 10:00:00'), 'resource_calendar: wrong interval cleaning') # Second intreval: 04, 08-14, combining 08-12 and 11-14, 09-11 being inside 08-12 self.assertEqual(cleaned_intervals[1][0], Datetime.from_string('2013-02-04 08:00:00'), 'resource_calendar: wrong interval cleaning') self.assertEqual(cleaned_intervals[1][1], Datetime.from_string('2013-02-04 14:00:00'), 'resource_calendar: wrong interval cleaning') # Third interval: 04, 17-21, 18-19 being inside 17-21 self.assertEqual(cleaned_intervals[2][0], Datetime.from_string('2013-02-04 17:00:00'), 'resource_calendar: wrong interval cleaning') self.assertEqual(cleaned_intervals[2][1], Datetime.from_string('2013-02-04 21:00:00'), 'resource_calendar: wrong interval cleaning') # Test: disjoint removal working_interval = (Datetime.from_string('2013-02-04 08:00:00'), Datetime.from_string('2013-02-04 18:00:00')) result = self.ResourceCalendar.interval_remove_leaves( working_interval, intervals) self.assertEqual( len(result), 1, 'resource_calendar: wrong leave removal from interval') # First interval: 04, 14-17 self.assertEqual( result[0][0], Datetime.from_string('2013-02-04 14:00:00'), 'resource_calendar: wrong leave removal from interval') self.assertEqual( result[0][1], Datetime.from_string('2013-02-04 17:00:00'), 'resource_calendar: wrong leave removal from interval') # Test: schedule hours on intervals result = self.ResourceCalendar.interval_schedule_hours( cleaned_intervals, 5.5) self.assertEqual( len(result), 2, 'resource_calendar: wrong hours scheduling in interval') # First interval: 03, 8-10 untouches self.assertEqual( result[0][0], Datetime.from_string('2013-02-03 08:00:00'), 'resource_calendar: wrong leave removal from interval') self.assertEqual( result[0][1], Datetime.from_string('2013-02-03 10:00:00'), 'resource_calendar: wrong leave removal from interval') # First interval: 04, 08-11:30 self.assertEqual( result[1][0], Datetime.from_string('2013-02-04 08:00:00'), 'resource_calendar: wrong leave removal from interval') self.assertEqual( result[1][1], Datetime.from_string('2013-02-04 11:30:00'), 'resource_calendar: wrong leave removal from interval') # Test: schedule hours on intervals, backwards cleaned_intervals.reverse() result = self.ResourceCalendar.interval_schedule_hours( cleaned_intervals, 5.5, remove_at_end=False) self.assertEqual( len(result), 2, 'resource_calendar: wrong hours scheduling in interval') # First interval: 03, 8-10 untouches self.assertEqual( result[0][0], Datetime.from_string('2013-02-04 17:00:00'), 'resource_calendar: wrong leave removal from interval') self.assertEqual( result[0][1], Datetime.from_string('2013-02-04 21:00:00'), 'resource_calendar: wrong leave removal from interval') # First interval: 04, 08-11:30 self.assertEqual( result[1][0], Datetime.from_string('2013-02-04 12:30:00'), 'resource_calendar: wrong leave removal from interval') self.assertEqual( result[1][1], Datetime.from_string('2013-02-04 14:00:00'), 'resource_calendar: wrong leave removal from interval')
def setUp(self): super(TestResourceCommon, self).setUp() self.env.user.tz = 'UTC' # Some demo data self.date1 = Datetime.from_string('2013-02-12 09:08:07') # weekday() returns 1, isoweekday() returns 2 self.date2 = Datetime.from_string('2013-02-15 10:11:12') # weekday() returns 4, isoweekday() returns 5 # Resource data # Calendar working days: 1 (8-16 -> 8hours), 4 (8-13, 16-23 -> 12hours) self.calendar = self.env['resource.calendar'].create({ 'name': 'TestCalendar', 'attendance_ids': [(5, 0, 0)] }) self.att_1 = self.env['resource.calendar.attendance'].create({ 'name': 'Att1', 'calendar_id': self.calendar.id, 'dayofweek': '1', 'hour_from': 8, 'hour_to': 16 }) self.att_2 = self.env['resource.calendar.attendance'].create({ 'name': 'Att2', 'calendar_id': self.calendar.id, 'dayofweek': '4', 'hour_from': 8, 'hour_to': 13 }) self.att_3 = self.env['resource.calendar.attendance'].create({ 'name': 'Att3', 'calendar_id': self.calendar.id, 'dayofweek': '4', 'hour_from': 16, 'hour_to': 23 }) self.resource1_id = self.env['resource.resource'].create( { 'name': 'TestResource1', 'resource_type': 'user', 'time_efficiency': 150.0, 'calendar_id': self.calendar.id, } ).id # Leave1: 19/02/2013, from 9 to 12, is a day 1 self.leave1 = self.env['resource.calendar.leaves'].create({ 'name': 'GenericLeave', 'calendar_id': self.calendar.id, 'date_from': Datetime.from_string('2013-02-19 09:00:00'), 'date_to': Datetime.from_string('2013-02-19 12:00:00')}) # Leave2: 22/02/2013, from 9 to 15, is a day 4 self.leave2 = self.env['resource.calendar.leaves'].create({ 'name': 'ResourceLeave', 'calendar_id': self.calendar.id, 'resource_id': self.resource1_id, 'date_from': Datetime.from_string('2013-02-22 09:00:00'), 'date_to': Datetime.from_string('2013-02-22 15:00:00')}) # Leave3: 25/02/2013 (day0) -> 01/03/2013 (day4) self.leave3 = self.env['resource.calendar.leaves'].create({ 'name': 'ResourceLeave2', 'calendar_id': self.calendar.id, 'resource_id': self.resource1_id, 'date_from': Datetime.from_string('2013-02-25 13:00:00'), 'date_to': Datetime.from_string('2013-03-01 11:30:00')})
def test_30_calendar_working_days(self): """ Testing calendar hours computation on a working day """ # Test: day1, beginning at 10:30 -> work from 10:30 (arrival) until 16:00 intervals = self.calendar.get_working_intervals_of_day( start_dt=self.date1.replace(hour=10, minute=30, second=0)) self.assertEqual( len(intervals), 1, 'resource_calendar: wrong working interval / day computing') self.assertEqual( intervals[0][0], Datetime.from_string('2013-02-12 10:30:00'), 'resource_calendar: wrong working interval / day computing') self.assertEqual( intervals[0][1], Datetime.from_string('2013-02-12 16:00:00'), 'resource_calendar: wrong working interval / day computing') # Test: hour computation for same interval, should give 5.5 wh = self.calendar.get_working_hours_of_date( start_dt=self.date1.replace(hour=10, minute=30, second=0)) self.assertEqual( wh, 5.5, 'resource_calendar: wrong working interval / day time computing') # Test: day1+7 on leave, without leave computation intervals = self.calendar.get_working_intervals_of_day( start_dt=self.date1.replace(hour=7, minute=0, second=0) + relativedelta(days=7)) # Result: day1 (08->16) self.assertEqual( len(intervals), 1, 'resource_calendar: wrong working interval/day computing') self.assertEqual( intervals[0][0], Datetime.from_string('2013-02-19 08:00:00'), 'resource_calendar: wrong working interval / day computing') self.assertEqual( intervals[0][1], Datetime.from_string('2013-02-19 16:00:00'), 'resource_calendar: wrong working interval / day computing') # Test: day1+7 on leave, with generic leave computation intervals = self.calendar.get_working_intervals_of_day( start_dt=self.date1.replace(hour=7, minute=0, second=0) + relativedelta(days=7), compute_leaves=True) # Result: day1 (08->09 + 12->16) self.assertEqual( len(intervals), 2, 'resource_calendar: wrong working interval/day computing') self.assertEqual( intervals[0][0], Datetime.from_string('2013-02-19 08:00:00'), 'resource_calendar: wrong working interval / day computing') self.assertEqual( intervals[0][1], Datetime.from_string('2013-02-19 09:00:00'), 'resource_calendar: wrong working interval / day computing') self.assertEqual( intervals[1][0], Datetime.from_string('2013-02-19 12:00:00'), 'resource_calendar: wrong working interval / day computing') self.assertEqual( intervals[1][1], Datetime.from_string('2013-02-19 16:00:00'), 'resource_calendar: wrong working interval / day computing') # Test: day1+14 on leave, with generic leave computation intervals = self.calendar.get_working_intervals_of_day( start_dt=self.date1.replace(hour=7, minute=0, second=0) + relativedelta(days=14), compute_leaves=True) # Result: day1 (08->16) self.assertEqual( len(intervals), 1, 'resource_calendar: wrong working interval/day computing') self.assertEqual( intervals[0][0], Datetime.from_string('2013-02-26 08:00:00'), 'resource_calendar: wrong working interval / day computing') self.assertEqual( intervals[0][1], Datetime.from_string('2013-02-26 16:00:00'), 'resource_calendar: wrong working interval / day computing') # Test: day1+14 on leave, with resource leave computation intervals = self.calendar.get_working_intervals_of_day( start_dt=self.date1.replace(hour=7, minute=0, second=0) + relativedelta(days=14), compute_leaves=True, resource_id=self.resource1_id) # Result: nothing, because on leave self.assertEqual( len(intervals), 0, 'resource_calendar: wrong working interval/day computing')
def _get_acquisition_date(self): self.ensure_one() return babel.dates.format_date( date=Datetime.from_string(self.acquisition_date), format='MMMM y', locale=self._context.get('lang') or 'en_US')
def setUpClass(cls): super(TestLeadConvert, cls).setUpClass() date = Datetime.from_string('2020-01-20 16:00:00') cls.crm_lead_dt_mock.now.return_value = date
def test_07(self): """After 182 days, exactly half of the budget line""" date = Datetime.to_string(Datetime.from_string('2014-07-02 00:00:00')) self.mock_datetime.now.return_value = date self.assertAlmostEqual(self.line.theoretical_amount, -182)