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 _interval_dates(self, frequency, company): """ Method used to compute the theoretical date from which account move lines should be fetched @param {string} frequency: a valid value of the selection field on the object (daily, monthly, annually) frequencies are literal (daily means 24 hours and so on) @param {recordset} company: the company for which the closing is done @return {dict} the theoretical date from which account move lines are fetched. date_stop date to which the move lines are fetched, always now() the dates are in their Odoo Database string representation """ date_stop = datetime.utcnow() interval_from = None name_interval = '' if frequency == 'daily': interval_from = date_stop - timedelta(days=1) name_interval = _('Daily Closing') elif frequency == 'monthly': month_target = date_stop.month > 1 and date_stop.month - 1 or 12 year_target = month_target < 12 and date_stop.year or date_stop.year - 1 interval_from = date_stop.replace(year=year_target, month=month_target) name_interval = _('Monthly Closing') elif frequency == 'annually': year_target = date_stop.year - 1 interval_from = date_stop.replace(year=year_target) name_interval = _('Annual Closing') return {'interval_from': FieldDateTime.to_string(interval_from), 'date_stop': FieldDateTime.to_string(date_stop), 'name_interval': name_interval}
def _send_sms_notification(self, params, send_mode='direct'): uuid = 'uid-1232389' params.update({ 'instance': 'test', 'sender': '+41414104141', 'operator': 'orange', 'command': 'FORWARD', 'date': Datetime.now(), 'uuid': uuid, }) if send_mode != 'direct': params.update({ 'receptionDate': Datetime.now(), 'requestUid': uuid, }) url_params = urllib.urlencode(params) response = self.url_open('/sms/mnc/?' + url_params) response_str = response.read() return response_str notification = self.env['sms.notification'].create(params) self.assertEqual(notification.state, 'new') response = notification.run_service() response_str = response.data self.assertEqual(notification.answer, response_str) return notification
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_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_in_date_5(self): """ Receive the same lot at different times, once they're in the same location, the quants are merged and only the earliest incoming date is kept. """ lot1 = self.env['stock.production.lot'].create({ 'name': 'lot1', 'product_id': self.product_lot.id, }) from odoo.fields import Datetime in_date1 = Datetime.now() self.env['stock.quant']._update_available_quantity(self.product_lot, self.stock_location, 1.0, lot_id=lot1, in_date=in_date1) quant = self.env['stock.quant'].search([ ('product_id', '=', self.product_lot.id), ('location_id', '=', self.stock_location.id), ]) self.assertEqual(len(quant), 1) self.assertEqual(quant.quantity, 1) self.assertEqual(quant.lot_id.id, lot1.id) self.assertEqual(quant.in_date, in_date1) in_date2 = Datetime.now() - timedelta(days=5) self.env['stock.quant']._update_available_quantity(self.product_lot, self.stock_location, 1.0, lot_id=lot1, in_date=in_date2) quant = self.env['stock.quant'].search([ ('product_id', '=', self.product_lot.id), ('location_id', '=', self.stock_location.id), ]) self.assertEqual(len(quant), 1) self.assertEqual(quant.quantity, 2) self.assertEqual(quant.lot_id.id, lot1.id) self.assertEqual(quant.in_date, in_date2)
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_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_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_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_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_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 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 poll(self, channels, last, options=None): if request.env.user.has_group('base.group_user'): ip_address = request.httprequest.remote_addr users_log = request.env['res.users.log'].search_count([ ('create_uid', '=', request.env.user.id), ('ip', '=', ip_address), ('create_date', '>=', Datetime.to_string(Datetime.now().replace(hour=0, minute=0, second=0, microsecond=0)))]) if not users_log: with registry(request.env.cr.dbname).cursor() as cr: env = Environment(cr, request.env.user.id, {}) env['res.users.log'].create({'ip': ip_address}) return super(BusController, self).poll(channels, last, options=options)
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 _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 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 _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 read_group(self, domain, fields, groupby, offset=0, limit=None, orderby=False, lazy=True): res = super(StockHistory, self).read_group(domain, fields, groupby, offset=offset, limit=limit, orderby=orderby, lazy=lazy) if 'inventory_value' in fields: date = self._context.get('history_date', fieldsDatetime.now()) stock_history = self.env['stock.history'] group_lines = {} for line in res: domain = line.get('__domain', domain) group_lines.setdefault(str(domain), self.search(domain)) stock_history |= group_lines[str(domain)] histories_dict = {} not_real_cost_method_products = stock_history.mapped('product_id').filtered(lambda product: product.cost_method != 'real') if not_real_cost_method_products: self._cr.execute("""SELECT DISTINCT ON (product_id, company_id) product_id, company_id, cost FROM product_price_history WHERE product_id in %s AND datetime <= %s ORDER BY product_id, company_id, datetime DESC, id DESC""", (tuple(not_real_cost_method_products.ids), date)) for history in self._cr.dictfetchall(): histories_dict[(history['product_id'], history['company_id'])] = history['cost'] for line in res: inv_value = 0.0 for stock_history in group_lines.get(str(line.get('__domain', domain))): product = stock_history.product_id if product.cost_method == 'real': price = stock_history.price_unit_on_quant else: price = histories_dict.get((product.id, stock_history.company_id.id), 0.0) inv_value += price * stock_history.quantity line['inventory_value'] = inv_value return res
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_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 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 test_event_date_range(self): self.patcher = patch('odoo.addons.event.models.event.fields.Datetime', wraps=Datetime) self.mock_datetime = self.patcher.start() self.mock_datetime.now.return_value = Datetime.to_string(datetime.datetime(2015, 12, 31, 12, 0)) self.event_0.registration_ids.event_begin_date = datetime.datetime(2015, 12, 31, 18, 0) self.assertEqual(self.event_0.registration_ids.get_date_range_str(), u'today') self.event_0.registration_ids.event_begin_date = datetime.datetime(2016, 1, 1, 6, 0) self.assertEqual(self.event_0.registration_ids.get_date_range_str(), u'tomorrow') self.event_0.registration_ids.event_begin_date = datetime.datetime(2016, 1, 2, 6, 0) self.assertEqual(self.event_0.registration_ids.get_date_range_str(), u'in 2 days') self.mock_datetime.now.return_value = Datetime.to_string(datetime.datetime(2015, 12, 10, 12, 0)) self.event_0.registration_ids.event_begin_date = datetime.datetime(2016, 1, 25, 6, 0) self.assertEqual(self.event_0.registration_ids.get_date_range_str(), u'next month') self.patcher.stop()
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 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_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 test_basic(self): """ Basic order test: no routing (thus no workorders), no lot """ self.product_1.type = 'product' self.product_2.type = 'product' inventory = self.env['stock.inventory'].create({ 'name': 'Initial inventory', 'filter': 'partial', 'line_ids': [(0, 0, { 'product_id': self.product_1.id, 'product_uom_id': self.product_1.uom_id.id, 'product_qty': 500, 'location_id': self.warehouse_1.lot_stock_id.id }), (0, 0, { 'product_id': self.product_2.id, 'product_uom_id': self.product_2.uom_id.id, 'product_qty': 500, 'location_id': self.warehouse_1.lot_stock_id.id })] }) inventory.action_validate() test_date_planned = Dt.now() - timedelta(days=1) test_quantity = 2.0 self.bom_1.routing_id = False man_order = self.env['mrp.production'].sudo(self.user_mrp_user).create( { 'name': 'Stick-0', 'product_id': self.product_4.id, 'product_uom_id': self.product_4.uom_id.id, 'product_qty': test_quantity, 'bom_id': self.bom_1.id, 'date_planned_start': test_date_planned, 'location_src_id': self.location_1.id, 'location_dest_id': self.warehouse_1.wh_output_stock_loc_id.id, }) self.assertEqual(man_order.state, 'confirmed', "Production order should be in confirmed state.") # check production move production_move = man_order.move_finished_ids self.assertEqual(production_move.date, test_date_planned) self.assertEqual(production_move.product_id, self.product_4) self.assertEqual(production_move.product_uom, man_order.product_uom_id) self.assertEqual(production_move.product_qty, man_order.product_qty) self.assertEqual(production_move.location_id, self.product_4.property_stock_production) self.assertEqual(production_move.location_dest_id, man_order.location_dest_id) # check consumption moves for move in man_order.move_raw_ids: self.assertEqual(move.date, test_date_planned) first_move = man_order.move_raw_ids.filtered( lambda move: move.product_id == self.product_2) self.assertEqual( first_move.product_qty, test_quantity / self.bom_1.product_qty * self.product_4.uom_id.factor_inv * 2) first_move = man_order.move_raw_ids.filtered( lambda move: move.product_id == self.product_1) self.assertEqual( first_move.product_qty, test_quantity / self.bom_1.product_qty * self.product_4.uom_id.factor_inv * 4) # waste some material, create a scrap # scrap = self.env['stock.scrap'].with_context( # active_model='mrp.production', active_id=man_order.id # ).create({}) # scrap = self.env['stock.scrap'].create({ # 'production_id': man_order.id, # 'product_id': first_move.product_id.id, # 'product_uom_id': first_move.product_uom.id, # 'scrap_qty': 5.0, # }) # check created scrap # procurements = self.env['procurement.order'].search([('move_dest_id', 'in', man_order.move_raw_ids.ids)]) # print procurements # procurements = self.env['procurement.order'].search([('production_id', '=', man_order.id)]) # print procurements # for proc in self.env['procurement.order'].browse(procurements): # date_planned = self.mrp_production_test1.date_planned # if proc.product_id.type not in ('product', 'consu'): # continue # if proc.product_id.id == order_line.product_id.id: # self.assertEqual(proc.date_planned, date_planned, "Planned date does not correspond") # # procurement state should be `confirmed` at this stage, except if procurement_jit is installed, in which # # case it could already be in `running` or `exception` state (not enough stock) # expected_states = ('confirmed', 'running', 'exception') # self.assertEqual(proc.state in expected_states, 'Procurement state is `%s` for %s, expected one of %s' % (proc.state, proc.product_id.name, expected_states)) # Change production quantity qty_wizard = self.env['change.production.qty'].create({ 'mo_id': man_order.id, 'product_qty': 3.0, }) # qty_wizard.change_prod_qty() # # I check qty after changed in production order. # #self.assertEqual(self.mrp_production_test1.product_qty, 3, "Qty is not changed in order.") # move = self.mrp_production_test1.move_finished_ids[0] # self.assertEqual(move.product_qty, self.mrp_production_test1.product_qty, "Qty is not changed in move line.") # # I run scheduler. # self.env['procurement.order'].run_scheduler() # # The production order is Waiting Goods, will force production which should set consume lines as available # self.mrp_production_test1.button_plan() # # I check that production order in ready state after forcing production. # #self.assertEqual(self.mrp_production_test1.availability, 'assigned', 'Production order availability should be set as available') # produce product produce_form = Form(self.env['mrp.product.produce'].with_context({ 'active_id': man_order.id, 'active_ids': [man_order.id], })) produce_form.product_qty = 1.0 produce_wizard = produce_form.save() produce_wizard.do_produce() # man_order.button_mark_done() man_order.button_mark_done() self.assertEqual(man_order.state, 'done', "Production order should be in done state.")
def test_event_configuration_from_type(self): """ Test data computation of event coming from its event.type template. Some one2many notably are duplicated from type configuration and some advanced testing is required, notably mail schedulers. """ self.assertEqual(self.env.user.tz, 'Europe/Brussels') event_type = self.event_type_complex.with_user(self.env.user) event_type.write({ 'use_mail_schedule': False, }) # Event type does not use mail schedule but data is kept for compatibility and avoid recreating them self.assertEqual(len(event_type.event_type_mail_ids), 2) event = self.env['event.event'].create({ 'name': 'Event Update Type', 'date_begin': FieldsDatetime.to_string(datetime.today() + timedelta(days=1)), 'date_end': FieldsDatetime.to_string(datetime.today() + timedelta(days=15)), 'auto_confirm': False, 'is_online': True, }) self.assertEqual(event.date_tz, self.env.user.tz) self.assertEqual(event.seats_availability, 'unlimited') self.assertFalse(event.auto_confirm) self.assertTrue(event.is_online) self.assertEqual(event.event_mail_ids, self.env['event.mail']) event.update({'event_type_id': event_type.id}) event._onchange_type() self.assertEqual(event.date_tz, 'Europe/Paris') self.assertEqual(event.seats_availability, 'limited') self.assertEqual(event.seats_max, event_type.default_registration_max) self.assertTrue(event.auto_confirm) self.assertFalse(event.is_online) self.assertEqual(event.event_mail_ids, self.env['event.mail']) event_type.write({ 'use_mail_schedule': True, 'event_type_mail_ids': [(5, 0), (0, 0, { 'interval_nbr': 1, 'interval_unit': 'days', 'interval_type': 'before_event', 'template_id': self.env['ir.model.data'].xmlid_to_res_id( 'event.event_reminder') })] }) event._onchange_type() self.assertEqual(event.event_mail_ids.interval_nbr, 1) self.assertEqual(event.event_mail_ids.interval_unit, 'days') self.assertEqual(event.event_mail_ids.interval_type, 'before_event') self.assertEqual(event.event_mail_ids.template_id, self.env.ref('event.event_reminder'))
def _get_report_data(self, data): year = data['year'] employees = self.env['hr.employee'].browse(data['employee_ids']) payslips = self.env['hr.payslip'].search([ ('employee_id', 'in', employees.ids), ('state', '=', 'done'), ('date_from', '>=', Datetime.now().replace(month=1, day=1, year=year)), ('date_from', '<=', Datetime.now().replace(month=12, day=31, year=year)), '|', ('struct_id.country_id', '=', False), ('struct_id.country_id', '=', self.env.ref('base.be').id), ]) lines = payslips.mapped('line_ids') payslip_rules = [(rule.code, rule.sequence) for rule in lines.mapped('salary_rule_id')] payslip_rules = sorted(payslip_rules, key=lambda x: x[1]) worked_days = payslips.mapped('worked_days_line_ids') result = { employee: { 'rules': OrderedDict((rule[0], { 'year': { 'name': False, 'total': 0 }, 'month': {m: { 'name': False, 'total': 0 } for m in range(12)}, 'quarter': {q: { 'name': False, 'total': 0 } for q in range(4)} }) for rule in payslip_rules), 'worked_days': { code: { 'year': { 'name': False, 'number_of_days': 0, 'number_of_hours': 0 }, 'month': { m: { 'name': False, 'number_of_days': 0, 'number_of_hours': 0 } for m in range(12) }, 'quarter': { q: { 'name': False, 'number_of_days': 0, 'number_of_hours': 0 } for q in range(4) } } for code in worked_days.mapped('code') } } for employee in employees } for line in lines: rule = result[line.employee_id]['rules'][line.salary_rule_id.code] month = line.slip_id.date_from.month - 1 rule['month'][month]['name'] = line.name rule['month'][month]['total'] += line.total rule['quarter'][(month) // 3]['name'] = line.name rule['quarter'][(month) // 3]['total'] += line.total rule['year']['name'] = line.name rule['year']['total'] += line.total rule['month'][month]['total'] = round( rule['month'][month]['total'], 2) rule['quarter'][(month) // 3]['total'] = round( rule['quarter'][(month) // 3]['total'], 2) rule['year']['total'] = round(rule['year']['total'], 2) for worked_day in worked_days: work = result[worked_day.payslip_id.employee_id]['worked_days'][ worked_day.code] month = worked_day.payslip_id.date_from.month - 1 work['month'][month]['name'] = worked_day.name work['month'][month]['number_of_days'] += worked_day.number_of_days work['month'][month][ 'number_of_hours'] += worked_day.number_of_hours work['quarter'][(month) // 3]['name'] = worked_day.name work['quarter'][(month) // 3]['number_of_days'] += worked_day.number_of_days work['quarter'][(month) // 3]['number_of_hours'] += worked_day.number_of_hours work['year']['name'] = worked_day.name work['year']['number_of_days'] += worked_day.number_of_days work['year']['number_of_hours'] += worked_day.number_of_hours return {'year': year, 'employee_data': result}
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_merge_method_followers(self): """ Test that the followers of the leads are added in the destination lead. They should be added if: - The related partner was active on the lead (posted a message in the last 30 days) - The related partner is not already following the destination lead Leads Followers Info --------------------------------------------------------------------------------- lead_w_contact contact_1 OK (destination lead) lead_w_email contact_1 KO (already following the destination lead) contact_2 OK (active on lead_w_email) contact_company KO (most recent message on lead_w_email is 35 days ago, message on lead_w_partner is not counted as he doesn't follow it) lead_w_partner contact_2 KO (already added with lead_w_email) lead_w_partner_company """ self.leads.message_follower_ids.unlink() self.leads.message_ids.unlink() self.lead_w_contact.message_subscribe([self.contact_1.id]) self.lead_w_email.message_subscribe( [self.contact_1.id, self.contact_2.id, self.contact_company.id]) self.lead_w_partner.message_subscribe([self.contact_2.id]) self.env['mail.message'].create([{ 'author_id': self.contact_1.id, 'model': 'crm.lead', 'res_id': self.lead_w_contact.id, 'date': Datetime.now() - timedelta(days=1), 'subtype_id': self.ref('mail.mt_comment'), 'reply_to': False, 'body': 'Test follower', }, { 'author_id': self.contact_1.id, 'model': 'crm.lead', 'res_id': self.lead_w_email.id, 'date': Datetime.now() - timedelta(days=20), 'subtype_id': self.ref('mail.mt_comment'), 'reply_to': False, 'body': 'Test follower', }, { 'author_id': self.contact_2.id, 'model': 'crm.lead', 'res_id': self.lead_w_email.id, 'date': Datetime.now() - timedelta(days=15), 'subtype_id': self.ref('mail.mt_comment'), 'reply_to': False, 'body': 'Test follower', }, { 'author_id': self.contact_2.id, 'model': 'crm.lead', 'res_id': self.lead_w_partner.id, 'date': Datetime.now() - timedelta(days=29), 'subtype_id': self.ref('mail.mt_comment'), 'reply_to': False, 'body': 'Test follower', }, { 'author_id': self.contact_company.id, 'model': 'crm.lead', 'res_id': self.lead_w_email.id, 'date': Datetime.now() - timedelta(days=35), 'subtype_id': self.ref('mail.mt_comment'), 'reply_to': False, 'body': 'Test follower', }, { 'author_id': self.contact_company.id, 'model': 'crm.lead', 'res_id': self.lead_w_partner.id, 'date': Datetime.now(), 'subtype_id': self.ref('mail.mt_comment'), 'reply_to': False, 'body': 'Test follower', }]) initial_followers = self.lead_w_contact.message_follower_ids leads = self.env['crm.lead'].browse( self.leads.ids)._sort_by_confidence_level(reverse=True) master_lead = leads._merge_opportunity(max_length=None) self.assertEqual(master_lead, self.lead_w_contact) # Check followers of the destination lead new_partner_followers = (master_lead.message_follower_ids - initial_followers).partner_id self.assertIn(self.contact_2, new_partner_followers, 'The partner must follow the destination lead') # "contact_company" posted a message 35 days ago on lead_2, so it's considered as inactive # "contact_company" posted a message now on lead_3, but he doesn't follow lead_3 # so this message is just ignored self.assertNotIn(self.contact_company, new_partner_followers, 'The partner was not active on the lead') self.assertIn( self.contact_1, master_lead.message_follower_ids.partner_id, 'Should not have removed follower of the destination lead')
def setUp(self): super(TestMailActivityTeam, self).setUp() self.env["mail.activity.team"].search([]).unlink() self.employee = self.env['res.users'].create({ 'company_id': self.env.ref("base.main_company").id, 'name': "Employee", 'login': "******", 'email': "*****@*****.**", 'groups_id': [(6, 0, [ self.env.ref('base.group_user').id, self.env.ref('base.group_partner_manager').id ])] }) self.employee2 = self.env['res.users'].create({ 'company_id': self.env.ref("base.main_company").id, 'name': "Employee 2", 'login': "******", 'email': "*****@*****.**", 'groups_id': [(6, 0, [self.env.ref('base.group_user').id])] }) self.partner_ir_model = self.env['ir.model']._get('res.partner') activity_type_model = self.env['mail.activity.type'] self.activity1 = activity_type_model.create({ 'name': 'Initial Contact', 'days': 5, 'summary': 'ACT 1 : Presentation, barbecue, ... ', 'res_model_id': self.partner_ir_model.id, }) self.activity2 = activity_type_model.create({ 'name': 'Call for Demo', 'days': 6, 'summary': 'ACT 2 : I want to show you my ERP !', 'res_model_id': self.partner_ir_model.id, }) self.partner_client = self.env.ref("base.res_partner_1") self.act1 = self.env['mail.activity'].sudo(self.employee).create({ 'activity_type_id': self.activity1.id, 'note': 'Partner activity 1.', 'res_id': self.partner_client.id, 'res_model_id': self.partner_ir_model.id, 'user_id': self.employee.id, }) self.team1 = self.env['mail.activity.team'].sudo().create({ 'name': 'Team 1', 'res_model_ids': [(6, 0, [self.partner_ir_model.id])], 'member_ids': [(6, 0, [self.employee.id])], }) self.team2 = self.env['mail.activity.team'].sudo().create({ 'name': 'Team 2', 'res_model_ids': [(6, 0, [self.partner_ir_model.id])], 'member_ids': [(6, 0, [self.employee.id, self.employee2.id])], }) self.act2 = self.env['mail.activity'].sudo(self.employee).create({ 'activity_type_id': self.activity2.id, 'note': 'Partner activity 2.', 'res_id': self.partner_client.id, 'res_model_id': self.partner_ir_model.id, 'user_id': self.employee.id, }) self.act3 = self.env['mail.activity'].sudo(self.employee).create({ 'activity_type_id': self.browse_ref('mail.mail_activity_data_meeting').id, 'note': 'Meeting activity 3.', 'res_id': self.partner_client.id, 'res_model_id': self.partner_ir_model.id, 'user_id': self.employee.id, 'team_id': self.team1.id, 'summary': 'Metting activity' }) self.start = Datetime.now() self.stop = Datetime.to_string( Datetime.from_string(self.start) + timedelta(hours=1))
def setUpClass(cls): super(TestTimesheetTimer, cls).setUpClass() User = cls.env['res.users'].with_context({'no_reset_password': True}) Factor = cls.env['hr_timesheet_invoice.factor'] Task = cls.env['project.task'] Timesheet = cls.env['account.analytic.line'] Project = cls.env['project.project'] user_group_employee = cls.env.ref('base.group_user') user_group_project_user = cls.env.ref('project.group_project_user') groups = [user_group_employee.id, user_group_project_user.id] cls.user_projectuser = User.create({ 'name': 'Armande ProjectUser', 'login': '******', 'email': '*****@*****.**', 'groups_id': [(6, 0, groups)] }) cls.no_discount = Factor.create({ 'name': 'No Discount', 'factor': 0.0, }) cls.full_discount = Factor.create({ 'name': 'Full Discount', 'factor': 100.0, }) cls.partner_1 = cls.env['res.partner'].create({ 'name': 'Bill Smith', 'email': '*****@*****.**', 'notify_email': 'always', }) cls.api_project = Project.create({ 'name': 'Timed Project', 'partner_id': cls.partner_1.id, }) cls.task = Task.create({ 'name': 'Bill for this work', 'partner_id': cls.partner_1.id, 'project_id': cls.api_project.id, }) # timesheet with 15 minutes on previous Start/Pause instance # and 15 minutes on the current instance Timesheet.create({ 'name': 'Worked on this briefly', 'date_start': Datetime.to_string(datetime.now() - timedelta(minutes=15)), 'user_id': cls.user_projectuser.id, 'task_id': cls.task.id, 'project_id': cls.api_project.id, 'factor': cls.no_discount.id, 'timer_status': 'stopped', 'amount': 40, 'full_duration': .25, 'unit_amount': .25, })
def setUp(self): super(TestUICommon, self).setUp() # Load pdf and img contents pdf_path = get_module_resource('website_slides', 'static', 'src', 'img', 'presentation.pdf') pdf_content = base64.b64encode(open(pdf_path, "rb").read()) img_path = get_module_resource('website_slides', 'static', 'src', 'img', 'slide_demo_gardening_1.jpg') img_content = base64.b64encode(open(img_path, "rb").read()) self.env['slide.channel'].create({ 'name': 'Basics of Gardening - Test', 'user_id': self.env.ref('base.user_admin').id, 'enroll': 'public', 'channel_type': 'training', 'allow_comment': True, 'promote_strategy': 'most_voted', 'is_published': True, 'description': 'Learn the basics of gardening !', 'create_date': Datetime.now() - relativedelta(days=8), 'slide_ids': [ (0, 0, { 'name': 'Gardening: The Know-How', 'sequence': 1, 'datas': pdf_content, 'slide_type': 'presentation', 'is_published': True, 'is_preview': True, }), (0, 0, { 'name': 'Home Gardening', 'sequence': 2, 'image_1920': img_content, 'slide_type': 'infographic', 'is_published': True, }), (0, 0, { 'name': 'Mighty Carrots', 'sequence': 3, 'image_1920': img_content, 'slide_type': 'infographic', 'is_published': True, }), (0, 0, { 'name': 'How to Grow and Harvest The Best Strawberries | Basics', 'sequence': 4, 'datas': pdf_content, 'slide_type': 'document', 'is_published': True, }), (0, 0, { 'name': 'Test your knowledge', 'sequence': 5, 'slide_type': 'quiz', 'is_published': True, 'question_ids': [ (0, 0, { 'question': 'What is a strawberry ?', 'answer_ids': [ (0, 0, { 'text_value': 'A fruit', 'is_correct': True, 'sequence': 1, }), (0, 0, { 'text_value': 'A vegetable', 'sequence': 2, }), (0, 0, { 'text_value': 'A table', 'sequence': 3, }) ] }), (0, 0, { 'question': 'What is the best tool to dig a hole for your plants ?', 'answer_ids': [ (0, 0, { 'text_value': 'A shovel', 'is_correct': True, 'sequence': 1, }), (0, 0, { 'text_value': 'A spoon', 'sequence': 2, }) ] }) ] }) ] })
def _check_presence(self): company = self.env.company if not company.hr_presence_last_compute_date or \ company.hr_presence_last_compute_date.day != Datetime.now().day: self.env['hr.employee'].search([ ('department_id.company_id', '=', company.id) ]).write({'hr_presence_state': 'to_define'}) employees = self.env['hr.employee'].search([ ('department_id.company_id', '=', company.id), ('user_id', '!=', False), ('hr_presence_state', '=', 'to_define') ]) # Remove employees on holidays leaves = self.env['hr.leave'].search([ ('state', '=', 'validate'), ('date_from', '<=', Datetime.to_string(Datetime.now())), ('date_to', '>=', Datetime.to_string(Datetime.now())) ]) employees_on_holiday = leaves.mapped('employee_id') employees_on_holiday.write({'hr_presence_state': 'absent'}) employees = employees - employees_on_holiday # Check on system login if self.env['ir.config_parameter'].sudo().get_param( 'hr_presence.hr_presence_control_login'): online_employees = employees.filtered( lambda employee: employee.user_id.im_status in ['away', 'online']) online_employees.write({'hr_presence_state': 'present'}) employees = employees - online_employees # Check on IP if self.env['ir.config_parameter'].sudo().get_param( 'hr_presence.hr_presence_control_ip'): ip_list = company.hr_presence_control_ip_list ip_list = ip_list.split(',') if ip_list else [] ip_employees = self.env['hr.employee'] for employee in employees: employee_ips = self.env['res.users.log'].search([ ('create_uid', '=', employee.user_id.id), ('ip', '!=', False), ('create_date', '>=', Datetime.to_string(Datetime.now().replace(hour=0, minute=0, second=0, microsecond=0))) ]).mapped('ip') if any([ip in ip_list for ip in employee_ips]): ip_employees |= employee ip_employees.write({'hr_presence_state': 'present'}) employees = employees - ip_employees # Check on sent emails if self.env['ir.config_parameter'].sudo().get_param( 'hr_presence.hr_presence_control_email'): email_employees = self.env['hr.employee'] threshold = company.hr_presence_control_email_amount for employee in employees: sent_emails = self.env['mail.message'].search_count([ ('author_id', '=', employee.user_id.partner_id.id), ('date', '>=', Datetime.to_string(Datetime.now().replace( hour=0, minute=0, second=0, microsecond=0))), ('date', '<=', Datetime.to_string(Datetime.now())) ]) if sent_emails >= threshold: email_employees |= employee email_employees.write({'hr_presence_state': 'present'}) employees = employees - email_employees company.hr_presence_last_compute_date = Datetime.now()
def setUpClass(cls): super(TestMailActivityTeam, cls).setUpClass() cls.env = cls.env(context=dict( cls.env.context, tracking_disable=True, no_reset_password=True)) cls.env["mail.activity.team"].search([]).unlink() cls.employee = cls.env['res.users'].create({ 'company_id': cls.env.ref("base.main_company").id, 'name': "Employee", 'login': "******", 'email': "*****@*****.**", 'groups_id': [(6, 0, [ cls.env.ref('base.group_user').id, cls.env.ref('base.group_partner_manager').id ])] }) cls.employee2 = cls.env['res.users'].create({ 'company_id': cls.env.ref("base.main_company").id, 'name': "Employee 2", 'login': "******", 'email': "*****@*****.**", 'groups_id': [(6, 0, [cls.env.ref('base.group_user').id])] }) cls.partner_ir_model = cls.env['ir.model']._get('res.partner') activity_type_model = cls.env['mail.activity.type'] cls.activity1 = activity_type_model.create({ 'name': 'Initial Contact', 'summary': 'ACT 1 : Presentation, barbecue, ... ', 'res_model_id': cls.partner_ir_model.id, }) cls.activity2 = activity_type_model.create({ 'name': 'Call for Demo', 'summary': 'ACT 2 : I want to show you my ERP !', 'res_model_id': cls.partner_ir_model.id, }) cls.partner_client = cls.env.ref("base.res_partner_1") cls.act1 = cls.env['mail.activity'].sudo(cls.employee).create({ 'activity_type_id': cls.activity1.id, 'note': 'Partner activity 1.', 'res_id': cls.partner_client.id, 'res_model_id': cls.partner_ir_model.id, 'user_id': cls.employee.id, }) cls.team1 = cls.env['mail.activity.team'].sudo().create({ 'name': 'Team 1', 'res_model_ids': [(6, 0, [cls.partner_ir_model.id])], 'member_ids': [(6, 0, [cls.employee.id])], }) cls.team2 = cls.env['mail.activity.team'].sudo().create({ 'name': 'Team 2', 'res_model_ids': [(6, 0, [cls.partner_ir_model.id])], 'member_ids': [(6, 0, [cls.employee.id, cls.employee2.id])], }) cls.act2 = cls.env['mail.activity'].sudo(cls.employee).create({ 'activity_type_id': cls.activity2.id, 'note': 'Partner activity 2.', 'res_id': cls.partner_client.id, 'res_model_id': cls.partner_ir_model.id, 'user_id': cls.employee.id, }) cls.act3 = cls.env['mail.activity'].sudo(cls.employee).create({ 'activity_type_id': cls.env.ref('mail.mail_activity_data_meeting').id, 'note': 'Meeting activity 3.', 'res_id': cls.partner_client.id, 'res_model_id': cls.partner_ir_model.id, 'user_id': cls.employee.id, 'team_id': cls.team1.id, 'summary': 'Metting activity' }) cls.start = Datetime.now() cls.stop = Datetime.to_string( Datetime.from_string(cls.start) + timedelta(hours=1))
def read_group(self, domain, fields, groupby, offset=0, limit=None, orderby=False, lazy=True): # Step 1: retrieve the standard read_group output. In case of inventory valuation, this # will be mostly used as a 'skeleton' since the inventory value needs to be computed based # on the individual lines. res = super(StockHistory, self).read_group(domain, fields, groupby, offset=offset, limit=limit, orderby=orderby, lazy=lazy) if "inventory_value" in fields: groupby_list = groupby[:1] if lazy else groupby date = self._context.get("history_date", fieldsDatetime.now()) # Step 2: retrieve the stock history lines. The result contains the 'expanded' # version of the read_group. We build the query manually for performance reason # (and avoid a costly 'WHERE id IN ...'). fields_2 = set([ "id", "product_id", "price_unit_on_quant", "company_id", "quantity" ] + groupby_list) query = self._where_calc(domain) self._apply_ir_rules(query, "read") tables, where_clause, where_clause_params = query.get_sql() select = "SELECT %s FROM %s WHERE %s " query = select % (",".join(fields_2), tables, where_clause) self._cr.execute(query, where_clause_params) # Step 3: match the lines retrieved at step 2 with the aggregated results of step 1. # In other words, we link each item of the read_group result with the corresponding # lines. stock_history_data = {} stock_histories_by_group = {} for line in self._cr.dictfetchall(): stock_history_data[line["id"]] = line key = tuple(line.get(g) or False for g in groupby_list) stock_histories_by_group.setdefault(key, []) stock_histories_by_group[key] += [line["id"]] histories_dict = {} # sudo() added here (QRTL) not_real_cost_method_products = ( self.env["product.product"].sudo().browse( record["product_id"] for record in stock_history_data.values()).filtered( lambda product: product.cost_method != "real")) if not_real_cost_method_products: self._cr.execute( """SELECT DISTINCT ON (product_id, company_id) product_id, company_id, cost FROM product_price_history WHERE product_id in %s AND datetime <= %s ORDER BY product_id, company_id, datetime DESC, id DESC""", (tuple(not_real_cost_method_products.ids), date), ) for history in self._cr.dictfetchall(): histories_dict[(history["product_id"], history["company_id"])] = history["cost"] for line in res: inv_value = 0.0 # Build the same keys than above, but need to take into account Many2one are tuples key = tuple(line[g] if g in line else False for g in groupby_list) key = tuple(k[0] if isinstance(k, tuple) else k for k in key) for stock_history in self.env["stock.history"].browse( stock_histories_by_group[key]): history_data = stock_history_data[stock_history.id] product_id = history_data["product_id"] if self.env["product.product"].browse( product_id).cost_method == "real": price = history_data["price_unit_on_quant"] else: price = histories_dict.get( (product_id, history_data["company_id"]), 0.0) inv_value += price * history_data["quantity"] line["inventory_value"] = inv_value return res
def generate_xlsx_report(self, workbook, data, attendances): row = 1 # Setup sheet and data report_name = datetime.today().strftime( "%Y-%m-%d") + "DAILY ABSENCE REPORT" attendances = self.env['zk.machine.attendance'].search([]) attendances = attendances.filtered( lambda attend: ODT.context_timestamp( attend, ODT.from_string(attend.punching_time)).strftime( '%Y-%m-%d') == data['form']['date']) employees = self.env['hr.employee'].sudo().search([]) employees = employees.filtered( lambda e: e.id not in attendances.mapped('employee_id.id')) 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}) t_heading = workbook.add_format({ 'align': 'center', 'bold': True, 'bg_color': '#BD5B5B', 'border': 1 }) sheet.set_column('C:C', 35) sheet.set_column('D:D', 30) sheet.set_column('E:E', 35) # Headings and titles sheet.merge_range(0, 1, 0, 4, 'HR DEPARTMENT', titles) sheet.merge_range(1, 1, 1, 4, 'DAILY ABSENCE REPORT', titles) sheet.merge_range(3, 1, 3, 4, 'DATE : ' + data['form']['date'], titles) sheet.write_row('B6', ['Emp ID', 'Name', 'Job Title', 'Department'], t_heading) for obj in employees: rgb_color = obj.department_id.color color = '#FFFFFF' if not rgb_color: rgb_color = "rgba(255,0,0,1)" 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 }) sheet.write_row('B' + str(row + 6), [row], emp_id) sheet.write_row('C' + str(row + 6), [ obj.name, obj.job_id.name or '-', obj.department_id.name or '-' ], attendance) row += 1
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, self.date_planned)))
def setUp(self): super().setUp() self.event_2 = self.env['event.event'].create({ 'name': 'Conference for Architects TEST', 'user_id': self.env.ref('base.user_admin').id, 'date_begin': (Datetime.today() + timedelta(days=5)).strftime('%Y-%m-%d 07:00:00'), 'date_end': (Datetime.today() + timedelta(days=5)).strftime('%Y-%m-%d 16:30:00'), }) self.env['event.event.ticket'].create([{ 'name': 'Standard', 'event_id': self.event_2.id, 'product_id': self.env.ref('event_sale.product_product_event').id, 'start_sale_date': (Datetime.today() - timedelta(days=5)).strftime('%Y-%m-%d 07:00:00'), 'end_sale_date': (Datetime.today() + timedelta(90)).strftime('%Y-%m-%d'), 'price': 1000.0, }, { 'name': 'VIP', 'event_id': self.event_2.id, 'product_id': self.env.ref('event_sale.product_product_event').id, 'end_sale_date': (Datetime.today() + timedelta(90)).strftime('%Y-%m-%d'), 'price': 1500.0, }]) (self.env.ref('base.partner_admin') + self.partner_demo).write({ 'street': '215 Vine St', 'city': 'Scranton', 'zip': '18503', 'country_id': self.env.ref('base.us').id, 'state_id': self.env.ref('base.state_us_39').id, 'phone': '+1 555-555-5555', 'email': '*****@*****.**', }) cash_journal = self.env['account.journal'].create({ 'name': 'Cash - Test', 'type': 'cash', 'code': 'CASH - Test' }) self.env.ref( 'payment.payment_acquirer_transfer').journal_id = cash_journal
def test_course_certification_employee(self): user_demo = self.user_demo user_demo.flush() # Avoid Billing/Shipping address page user_demo.write({ 'groups_id': [(5, 0), (4, self.env.ref('base.group_user').id)], 'street': '215 Vine St', 'city': 'Scranton', 'zip': '18503', 'country_id': self.env.ref('base.us').id, 'state_id': self.env.ref('base.state_us_39').id, 'phone': '+1 555-555-5555', 'email': '*****@*****.**', }) # Specify Accounting Data cash_journal = self.env['account.journal'].create({ 'name': 'Cash - Test', 'type': 'cash', 'code': 'CASH - Test' }) self.env['payment.acquirer'].search([('journal_id', '=', False) ]).journal_id = cash_journal a_recv = self.env['account.account'].create({ 'code': 'X1012', 'name': 'Debtors - (test)', 'reconcile': True, 'user_type_id': self.env.ref('account.data_account_type_receivable').id, }) a_pay = self.env['account.account'].create({ 'code': 'X1111', 'name': 'Creditors - (test)', 'user_type_id': self.env.ref('account.data_account_type_payable').id, 'reconcile': True, }) Property = self.env['ir.property'] Property._set_default('property_account_receivable_id', 'res.partner', a_recv, self.env.company) Property._set_default('property_account_payable_id', 'res.partner', a_pay, self.env.company) product_course_channel_6 = self.env['product.product'].create({ 'name': 'DIY Furniture Course', 'list_price': 100.0, 'type': 'service', 'is_published': True, }) furniture_survey = self.env['survey.survey'].create({ 'title': 'Furniture Creation Certification', 'access_token': '5632a4d7-48cf-aaaa-8c52-2174d58cf50b', 'state': 'open', 'access_mode': 'public', 'users_can_go_back': True, 'users_login_required': True, 'scoring_type': 'scoring_with_answers', 'certification': True, 'certification_mail_template_id': self.env.ref('survey.mail_template_certification').id, 'is_attempts_limited': True, 'attempts_limit': 3, 'description': "<p>Test your furniture knowledge!</p>", 'question_and_page_ids': [(0, 0, { 'title': 'Furniture', 'sequence': 1, 'is_page': True, 'description': "<p>Test your furniture knowledge!</p>", }), (0, 0, { 'title': 'What type of wood is the best for furniture?', 'sequence': 2, 'question_type': 'simple_choice', 'constr_mandatory': True, 'suggested_answer_ids': [(0, 0, { 'value': 'Fir', 'sequence': 1, }), (0, 0, { 'value': 'Oak', 'sequence': 2, 'is_correct': True, 'answer_score': 2.0, }), (0, 0, { 'value': 'Ash', 'sequence': 3, }), (0, 0, { 'value': 'Beech', 'sequence': 4, })] }), (0, 0, { 'title': 'Select all the furniture shown in the video', 'sequence': 3, 'question_type': 'multiple_choice', 'column_nb': '4', 'suggested_answer_ids': [(0, 0, { 'value': 'Chair', 'sequence': 1, 'is_correct': True, 'answer_score': 1.0, }), (0, 0, { 'value': 'Table', 'sequence': 2, 'answer_score': -1.0, }), (0, 0, { 'value': 'Desk', 'sequence': 3, 'is_correct': True, 'answer_score': 1.0, }), (0, 0, { 'value': 'Shelve', 'sequence': 4, 'is_correct': True, 'answer_score': 1.0, }), (0, 0, { 'value': 'Bed', 'sequence': 5, 'answer_score': -1.0, })] }), (0, 0, { 'title': 'What do you think about the content of the course? (not rated)', 'sequence': 4, 'question_type': 'text_box', })] }) slide_channel_demo_6_furn3 = self.env['slide.channel'].create({ 'name': 'DIY Furniture - TEST', 'user_id': self.env.ref('base.user_admin').id, 'enroll': 'payment', 'product_id': product_course_channel_6.id, 'channel_type': 'training', 'allow_comment': True, 'promote_strategy': 'most_voted', 'is_published': True, 'description': 'So much amazing certification.', 'create_date': Datetime.now() - relativedelta(days=2), 'slide_ids': [(0, 0, { 'name': 'DIY Furniture Certification', 'sequence': 1, 'slide_type': 'certification', 'category_id': False, 'is_published': True, 'is_preview': False, 'description': "It's time to test your knowledge!", 'survey_id': furniture_survey.id, })] }) self.browser_js( '/slides', 'odoo.__DEBUG__.services["web_tour.tour"].run("certification_member")', 'odoo.__DEBUG__.services["web_tour.tour"].tours.certification_member.ready', login=user_demo.login)
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 _compute_presence_state(self): super()._compute_presence_state() employees = self.filtered(lambda employee: employee.hr_presence_state != 'present' and not employee.is_absent) company = self.env.company for employee in employees: if not employee.is_absent and company.hr_presence_last_compute_date and company.hr_presence_last_compute_date.day == Datetime.now().day and \ (employee.email_sent or employee.ip_connected or employee.manually_set_present): employee.hr_presence_state = 'present'
def test_event_configuration_from_type(self): """ Test data computation of event coming from its event.type template. Some one2many notably are duplicated from type configuration and some advanced testing is required, notably mail schedulers. """ self.assertEqual(self.env.user.tz, 'Europe/Brussels') # ------------------------------------------------------------ # STARTING DATA # ------------------------------------------------------------ event_type = self.env['event.type'].browse(self.event_type_complex.id) event_type.write({ 'use_mail_schedule': False, 'use_ticket': False, }) self.assertEqual(event_type.event_type_mail_ids, self.env['event.type.mail']) self.assertEqual(event_type.event_type_ticket_ids, self.env['event.type.ticket']) event = self.env['event.event'].create({ 'name': 'Event Update Type', 'date_begin': FieldsDatetime.to_string(datetime.today() + timedelta(days=1)), 'date_end': FieldsDatetime.to_string(datetime.today() + timedelta(days=15)), }) self.assertEqual(event.date_tz, self.env.user.tz) self.assertFalse(event.seats_limited) self.assertFalse(event.auto_confirm) self.assertEqual(event.event_mail_ids, self.env['event.mail']) self.assertEqual(event.event_ticket_ids, self.env['event.event.ticket']) registration = self._create_registrations(event, 1) self.assertEqual(registration.state, 'draft') # event is not auto confirm # ------------------------------------------------------------ # FILL SYNC TEST # ------------------------------------------------------------ # change template to a one with mails -> fill event as it is void event_type.write({ 'use_mail_schedule': True, 'event_type_mail_ids': [(5, 0), (0, 0, { 'interval_nbr': 1, 'interval_unit': 'days', 'interval_type': 'before_event', 'template_id': self.env['ir.model.data'].xmlid_to_res_id( 'event.event_reminder') })], 'use_ticket': True, 'event_type_ticket_ids': [(5, 0), (0, 0, { 'name': 'TestRegistration' })], }) event.write({'event_type_id': event_type.id}) self.assertEqual(event.date_tz, 'Europe/Paris') self.assertTrue(event.seats_limited) self.assertEqual(event.seats_max, event_type.seats_max) self.assertTrue(event.auto_confirm) # check 2many fields being populated self.assertEqual(len(event.event_mail_ids), 1) self.assertEqual(event.event_mail_ids.interval_nbr, 1) self.assertEqual(event.event_mail_ids.interval_unit, 'days') self.assertEqual(event.event_mail_ids.interval_type, 'before_event') self.assertEqual(event.event_mail_ids.template_id, self.env.ref('event.event_reminder')) self.assertEqual(len(event.event_ticket_ids), 1) # update template, unlink from event -> should not impact event event_type.write({'has_seats_limitation': False}) self.assertEqual(event_type.seats_max, 0) self.assertTrue(event.seats_limited) self.assertEqual(event.seats_max, 30) # original template value event.write({'event_type_id': False}) self.assertEqual(event.event_type_id, self.env["event.type"]) # set template back -> update event event.write({'event_type_id': event_type.id}) self.assertFalse(event.seats_limited) self.assertEqual(event.seats_max, 0) self.assertEqual(len(event.event_ticket_ids), 1) event_ticket1 = event.event_ticket_ids[0] self.assertEqual(event_ticket1.name, 'TestRegistration') # ------------------------------------------------------------ # RESET TEST # ------------------------------------------------------------ # link registration to ticket registration.write({'event_ticket_id': event_ticket1.id}) self.assertEqual(registration.event_ticket_id, event_ticket1) # change template to a void one for mails -> reset event lines that are void # change template to a one with other tickets -> keep line linked to a registration event_type.write({ 'use_mail_schedule': False, 'event_type_mail_ids': [(5, 0)], 'event_type_ticket_ids': [(5, 0), (0, 0, { 'name': 'Registration1' }), (0, 0, { 'name': 'Registration2' })], }) event._compute_event_ticket_ids() event._compute_event_mail_ids() self.assertEqual(event.event_mail_ids, self.env['event.mail']) self.assertEqual(len(event.event_ticket_ids), 3) self.assertEqual( set(event.mapped('event_ticket_ids.name')), set(['TestRegistration', 'Registration1', 'Registration2'])) # registration loose its ticket self.assertEqual(registration.event_ticket_id, event_ticket1) # change template to a one with different mails -> reset event event_type.write({ 'use_mail_schedule': True, 'event_type_mail_ids': [(5, 0), (0, 0, { 'interval_nbr': 3, 'interval_unit': 'days', 'interval_type': 'after_event', 'template_id': self.env['ir.model.data'].xmlid_to_res_id( 'event.event_reminder') })] }) event._compute_event_ticket_ids() event._compute_event_mail_ids() self.assertEqual(len(event.event_mail_ids), 1) self.assertEqual(event.event_mail_ids.interval_nbr, 3) self.assertEqual(event.event_mail_ids.interval_type, 'after_event')
def test_calendar_leave_intervals_timezone(self): # _iter_leave_intervals takes UTC and outputs UTC # Leave is taken by user in US/Alaska timezone # It should be visible at the right time for every timezone 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) # Checking for 'Europe/Brussels' self.env.user.tz = 'Europe/Brussels' leaves = list( self.calendar._iter_leave_intervals( to_naive_utc(Datetime.from_string('2013-02-26 14:00:00'), self.env.user), to_naive_utc(Datetime.from_string('2013-02-26 15:30:00'), self.env.user), self.resource1_id)) self.assertEqual(len(leaves), 0) leaves = list( self.calendar._iter_leave_intervals( to_naive_utc(Datetime.from_string('2013-02-26 08:00:00'), self.env.user), to_naive_utc(Datetime.from_string('2013-02-26 11:00:00'), self.env.user), self.resource1_id))[0] self.assertEqual(len(leaves), 1) self.assertEqual(to_tuple(leaves[0]), (Datetime.from_string('2013-02-26 07:00:00'), Datetime.from_string('2013-02-26 10:00:00'))) leaves = list( self.calendar._iter_leave_intervals( to_naive_utc(Datetime.from_string('2013-02-22 08:00:00'), self.env.user), to_naive_utc(Datetime.from_string('2013-02-22 20:00:00'), self.env.user), self.resource1_id))[0] self.assertEqual(len(leaves), 2) self.assertEqual(to_tuple(leaves[0]), (Datetime.from_string('2013-02-22 07:00:00'), Datetime.from_string('2013-02-22 12:00:00'))) # Checking for 'Japan' self.env.user.tz = 'Japan' leaves = list( self.calendar._iter_leave_intervals( to_naive_utc(Datetime.from_string('2013-02-26 14:00:00'), self.env.user), to_naive_utc(Datetime.from_string('2013-02-26 15:30:00'), self.env.user), self.resource1_id)) self.assertEqual(len(leaves), 0) leaves = list( self.calendar._iter_leave_intervals( to_naive_utc(Datetime.from_string('2013-02-26 08:00:00'), self.env.user), to_naive_utc(Datetime.from_string('2013-02-26 11:00:00'), self.env.user), self.resource1_id))[0] self.assertEqual(len(leaves), 1) self.assertEqual(to_tuple(leaves[0]), (Datetime.from_string('2013-02-25 23:00:00'), Datetime.from_string('2013-02-26 02:00:00'))) leaves = list( self.calendar._iter_leave_intervals( to_naive_utc(Datetime.from_string('2013-02-22 08:00:00'), self.env.user), to_naive_utc(Datetime.from_string('2013-02-22 20:00:00'), self.env.user), self.resource1_id))[0] self.assertEqual(len(leaves), 2) self.assertEqual(to_tuple(leaves[0]), (Datetime.from_string('2013-02-21 23:00:00'), Datetime.from_string('2013-02-22 04:00:00')))
def _execute_email(self, traces): res_ids = [r for r in set(traces.mapped('res_id'))] mailing = self.mass_mailing_id.with_context( default_marketing_activity_id=self.ids[0], active_ids=res_ids, ) # we only allow to continue if the user has sufficient rights, as a sudo() follows if not self.env.is_superuser() and not self.user_has_groups( 'marketing_automation.group_marketing_automation_user'): raise AccessError( _('To use this feature you should be an administrator or belong to the marketing automation group.' )) try: mailing.sudo().action_send_mail(res_ids) except Exception as e: _logger.warning( 'Marketing Automation: activity <%s> encountered mass mailing issue %s', self.id, str(e), exc_info=True) traces.write({ 'state': 'error', 'schedule_date': Datetime.now(), 'state_msg': _('Exception in mass mailing: %s', str)(e), }) else: failed_stats = self.env['mailing.trace'].sudo().search([ ('marketing_trace_id', 'in', traces.ids), '|', ('exception', '!=', False), ('ignored', '!=', False) ]) ignored_doc_ids = [ stat.res_id for stat in failed_stats if stat.exception ] error_doc_ids = [ stat.res_id for stat in failed_stats if stat.ignored ] processed_traces = traces ignored_traces = traces.filtered( lambda trace: trace.res_id in ignored_doc_ids) error_traces = traces.filtered( lambda trace: trace.res_id in error_doc_ids) if ignored_traces: ignored_traces.write({ 'state': 'canceled', 'schedule_date': Datetime.now(), 'state_msg': _('Email ignored') }) processed_traces = processed_traces - ignored_traces if error_traces: error_traces.write({ 'state': 'error', 'schedule_date': Datetime.now(), 'state_msg': _('Email failed') }) processed_traces = processed_traces - error_traces if processed_traces: processed_traces.write({ 'state': 'processed', 'schedule_date': Datetime.now(), }) return True
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 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_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'].sudo(self.user_market) Activity = self.env['marketing.activity'].sudo(self.user_market) MassMail = self.env['mail.mass_mailing'].sudo(self.user_market) ServerAction = self.env['ir.actions.server'].sudo(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', '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', 'domain': '%s' % ([('name', 'ilike', 'Test')]), 'campaign_id': campaign.id, 'parent_id': act_0.id, 'activity_type': 'action', 'server_action_id': server_action.sudo(self.user_market).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 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 _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 _check_presence(self): company = self.env.company if not company.hr_presence_last_compute_date or \ company.hr_presence_last_compute_date.day != Datetime.now().day: self.env['hr.employee'].search([('company_id', '=', company.id) ]).write({ 'email_sent': False, 'ip_connected': False, 'manually_set_present': False }) employees = self.env['hr.employee'].search([('company_id', '=', company.id)]) all_employees = employees # Check on IP if self.env['ir.config_parameter'].sudo().get_param( 'hr_presence.hr_presence_control_ip'): ip_list = company.hr_presence_control_ip_list ip_list = ip_list.split(',') if ip_list else [] ip_employees = self.env['hr.employee'] for employee in employees: employee_ips = self.env['res.users.log'].search([ ('create_uid', '=', employee.user_id.id), ('ip', '!=', False), ('create_date', '>=', Datetime.to_string(Datetime.now().replace(hour=0, minute=0, second=0, microsecond=0))) ]).mapped('ip') if any([ip in ip_list for ip in employee_ips]): ip_employees |= employee ip_employees.write({'ip_connected': True}) employees = employees - ip_employees # Check on sent emails if self.env['ir.config_parameter'].sudo().get_param( 'hr_presence.hr_presence_control_email'): email_employees = self.env['hr.employee'] threshold = company.hr_presence_control_email_amount for employee in employees: sent_emails = self.env['mail.message'].search_count([ ('author_id', '=', employee.user_id.partner_id.id), ('date', '>=', Datetime.to_string(Datetime.now().replace( hour=0, minute=0, second=0, microsecond=0))), ('date', '<=', Datetime.to_string(Datetime.now())) ]) if sent_emails >= threshold: email_employees |= employee email_employees.write({'email_sent': True}) employees = employees - email_employees company.sudo().hr_presence_last_compute_date = Datetime.now() for employee in all_employees: employee.hr_presence_state_display = employee.hr_presence_state
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 _test_leave(self): # -------------------------------------------------- # Holiday manager: creates leave types # -------------------------------------------------- self.leave_type_1 = self.create_leave_type( user=self.hr_holidays_manager, name='Leave Type (no allocation, validation HR, day)', allocation='no', request_unit='day', validation='hr', ) self.leave_type_2 = self.create_leave_type( user=self.hr_holidays_manager, name='Leave Type (allocation by HR, no validation, half day)', allocation='fixed', request_unit='half_day', validation='no_validation', ) self.leave_type_3 = self.create_leave_type( user=self.hr_holidays_manager, name='Leave Type (allocation request, validation both, hour)', allocation='fixed_allocation', request_unit='hour', validation='both', ) # -------------------------------------------------- # Holiday user: Allocation # -------------------------------------------------- allocation_no_validation = self.create_allocation( user=self.hr_holidays_user, employee=self.user.employee_id, leave_type=self.leave_type_2, ) # Holiday user refuse allocation allocation_no_validation.action_refuse() self.assertEqual(allocation_no_validation.state, 'refuse') # Holiday manager reset to draft allocation_no_validation.with_user(self.hr_holidays_manager).action_draft() self.assertEqual(allocation_no_validation.state, 'draft') # Holiday user approve allocation allocation_no_validation.with_user(self.user).action_confirm() allocation_no_validation.action_approve() self.assertEqual(allocation_no_validation.state, 'validate') self.assertEqual(allocation_no_validation.first_approver_id, self.hr_holidays_user.employee_id) # -------------------------------------------------- # User: Allocation request # -------------------------------------------------- # User request an allocation allocation = self.create_allocation( user=self.user, employee=self.user.employee_id, leave_type=self.leave_type_3, ) self.assertEqual(allocation.state, 'confirm') # Holyday User approves allocation.with_user(self.hr_holidays_user).action_approve() self.assertEqual(allocation.state, 'validate1') self.assertEqual(allocation.first_approver_id, self.hr_holidays_user.employee_id) # Holiday Manager validates allocation.with_user(self.hr_holidays_manager).action_validate() self.assertEqual(allocation.state, 'validate') self.assertEqual(allocation.second_approver_id, self.hr_holidays_manager.employee_id) # -------------------------------------------------- # User: Leave request # -------------------------------------------------- # User request a leave which does not require validation leave_form = Form(self.env['hr.leave'].with_user(self.user)) leave_form.holiday_status_id = allocation_no_validation.holiday_status_id leave_form.request_unit_half = True leave_form.request_date_from = Date.today() + relativedelta(days=1) leave_form.request_date_from_period = 'am' self.assertEqual(leave_form.number_of_days, 0.5, "Onchange should have computed 0.5 days") leave = leave_form.save() self.assertEqual(leave.state, 'validate', "Should be automatically validated") # User request a leave that doesn't require allocation leave = self.create_leave( user=self.user, leave_type=self.leave_type_1, start=Datetime.now() + relativedelta(days=2), end=Datetime.now() + relativedelta(days=3) ) # User request a leave that require validation leave = self.create_leave( user=self.user, leave_type=allocation.holiday_status_id, start=Datetime.now() + relativedelta(days=6), end=Datetime.now() + relativedelta(days=8) ) self.assertEqual(leave.state, 'confirm', "Should be in `confirm` state") # Team leader approves leave.with_user(self.user_leave_team_leader).action_approve() self.assertEqual(leave.state, 'validate1') self.assertEqual(leave.first_approver_id, self.user_leave_team_leader.employee_id) # Holiday manager applies second approval leave.with_user(self.hr_holidays_manager).action_validate() self.assertEqual(leave.state, 'validate') self.assertEqual(leave.second_approver_id, self.hr_holidays_manager.employee_id)
def _compute_atn(self): now = Datetime.now() for model in self: model.default_atn = self.env['fleet.vehicle']._get_car_atn( now, model.default_car_value, model.default_fuel_type, model.default_co2)