diff options
| author | stephanchrst <stephanchrst@gmail.com> | 2022-05-10 21:51:50 +0700 |
|---|---|---|
| committer | stephanchrst <stephanchrst@gmail.com> | 2022-05-10 21:51:50 +0700 |
| commit | 3751379f1e9a4c215fb6eb898b4ccc67659b9ace (patch) | |
| tree | a44932296ef4a9b71d5f010906253d8c53727726 /addons/test_mail/tests/test_mail_activity.py | |
| parent | 0a15094050bfde69a06d6eff798e9a8ddf2b8c21 (diff) | |
initial commit 2
Diffstat (limited to 'addons/test_mail/tests/test_mail_activity.py')
| -rw-r--r-- | addons/test_mail/tests/test_mail_activity.py | 434 |
1 files changed, 434 insertions, 0 deletions
diff --git a/addons/test_mail/tests/test_mail_activity.py b/addons/test_mail/tests/test_mail_activity.py new file mode 100644 index 00000000..e6d4b003 --- /dev/null +++ b/addons/test_mail/tests/test_mail_activity.py @@ -0,0 +1,434 @@ +# -*- coding: utf-8 -*- +# Part of Odoo. See LICENSE file for full copyright and licensing details. + +from datetime import date, datetime, timedelta +from dateutil.relativedelta import relativedelta +from unittest.mock import patch +from unittest.mock import DEFAULT + +import pytz + +from odoo import fields, exceptions, tests +from odoo.addons.test_mail.tests.common import TestMailCommon +from odoo.addons.test_mail.models.test_mail_models import MailTestActivity +from odoo.tools import mute_logger +from odoo.tests.common import Form + + +class TestActivityCommon(TestMailCommon): + + @classmethod + def setUpClass(cls): + super(TestActivityCommon, cls).setUpClass() + cls.test_record = cls.env['mail.test.activity'].with_context(cls._test_context).create({'name': 'Test'}) + # reset ctx + cls._reset_mail_context(cls.test_record) + + +@tests.tagged('mail_activity') +class TestActivityRights(TestActivityCommon): + + @mute_logger('odoo.addons.mail.models.mail_mail') + def test_activity_security_user_access_other(self): + activity = self.test_record.with_user(self.user_employee).activity_schedule( + 'test_mail.mail_act_test_todo', + user_id=self.user_admin.id) + self.assertTrue(activity.can_write) + activity.write({'user_id': self.user_employee.id}) + + @mute_logger('odoo.addons.mail.models.mail_mail') + def test_activity_security_user_access_own(self): + activity = self.test_record.with_user(self.user_employee).activity_schedule( + 'test_mail.mail_act_test_todo') + self.assertTrue(activity.can_write) + activity.write({'user_id': self.user_admin.id}) + + @mute_logger('odoo.addons.mail.models.mail_mail') + def test_activity_security_user_noaccess_automated(self): + def _employee_crash(*args, **kwargs): + """ If employee is test employee, consider he has no access on document """ + recordset = args[0] + if recordset.env.uid == self.user_employee.id: + raise exceptions.AccessError('Hop hop hop Ernest, please step back.') + return DEFAULT + + with patch.object(MailTestActivity, 'check_access_rights', autospec=True, side_effect=_employee_crash): + activity = self.test_record.activity_schedule( + 'test_mail.mail_act_test_todo', + user_id=self.user_employee.id) + + activity2 = self.test_record.activity_schedule('test_mail.mail_act_test_todo') + activity2.write({'user_id': self.user_employee.id}) + + def test_activity_security_user_noaccess_manual(self): + def _employee_crash(*args, **kwargs): + """ If employee is test employee, consider he has no access on document """ + recordset = args[0] + if recordset.env.uid == self.user_employee.id: + raise exceptions.AccessError('Hop hop hop Ernest, please step back.') + return DEFAULT + + # cannot create activities for people that cannot access record + with patch.object(MailTestActivity, 'check_access_rights', autospec=True, side_effect=_employee_crash): + with self.assertRaises(exceptions.UserError): + activity = self.env['mail.activity'].create({ + 'activity_type_id': self.env.ref('test_mail.mail_act_test_todo').id, + 'res_model_id': self.env.ref('test_mail.model_mail_test_activity').id, + 'res_id': self.test_record.id, + 'user_id': self.user_employee.id, + }) + + # cannot create activities if no access to the document + with patch.object(MailTestActivity, 'check_access_rights', autospec=True, side_effect=_employee_crash): + with self.assertRaises(exceptions.AccessError): + activity = self.test_record.with_user(self.user_employee).activity_schedule( + 'test_mail.mail_act_test_todo', + user_id=self.user_admin.id) + + +@tests.tagged('mail_activity') +class TestActivityFlow(TestActivityCommon): + + def test_activity_flow_employee(self): + with self.with_user('employee'): + test_record = self.env['mail.test.activity'].browse(self.test_record.id) + self.assertEqual(test_record.activity_ids, self.env['mail.activity']) + + # employee record an activity and check the deadline + self.env['mail.activity'].create({ + 'summary': 'Test Activity', + 'date_deadline': date.today() + relativedelta(days=1), + 'activity_type_id': self.env.ref('mail.mail_activity_data_email').id, + 'res_model_id': self.env['ir.model']._get(test_record._name).id, + 'res_id': test_record.id, + }) + self.assertEqual(test_record.activity_summary, 'Test Activity') + self.assertEqual(test_record.activity_state, 'planned') + + test_record.activity_ids.write({'date_deadline': date.today() - relativedelta(days=1)}) + test_record.invalidate_cache() # TDE note: should not have to do it I think + self.assertEqual(test_record.activity_state, 'overdue') + + test_record.activity_ids.write({'date_deadline': date.today()}) + test_record.invalidate_cache() # TDE note: should not have to do it I think + self.assertEqual(test_record.activity_state, 'today') + + # activity is done + test_record.activity_ids.action_feedback(feedback='So much feedback') + self.assertEqual(test_record.activity_ids, self.env['mail.activity']) + self.assertEqual(test_record.message_ids[0].subtype_id, self.env.ref('mail.mt_activities')) + + @mute_logger('odoo.addons.mail.models.mail_mail') + def test_activity_notify_other_user(self): + self.user_admin.notification_type = 'email' + rec = self.test_record.with_user(self.user_employee) + with self.assertSinglePostNotifications( + [{'partner': self.partner_admin, 'type': 'email'}], + message_info={'content': 'assigned you an activity', 'subtype': 'mail.mt_note', 'message_type': 'user_notification'}): + activity = rec.activity_schedule( + 'test_mail.mail_act_test_todo', + user_id=self.user_admin.id) + self.assertEqual(activity.create_uid, self.user_employee) + self.assertEqual(activity.user_id, self.user_admin) + + def test_activity_notify_same_user(self): + self.user_employee.notification_type = 'email' + rec = self.test_record.with_user(self.user_employee) + with self.assertNoNotifications(): + activity = rec.activity_schedule( + 'test_mail.mail_act_test_todo', + user_id=self.user_employee.id) + self.assertEqual(activity.create_uid, self.user_employee) + self.assertEqual(activity.user_id, self.user_employee) + + @mute_logger('odoo.addons.mail.models.mail_mail') + def test_activity_dont_notify_no_user_change(self): + self.user_employee.notification_type = 'email' + activity = self.test_record.activity_schedule('test_mail.mail_act_test_todo', user_id=self.user_employee.id) + with self.assertNoNotifications(): + activity.with_user(self.user_admin).write({'user_id': self.user_employee.id}) + self.assertEqual(activity.user_id, self.user_employee) + + @mute_logger('odoo.addons.mail.models.mail_mail') + def test_activity_summary_sync(self): + """ Test summary from type is copied on activities if set (currently only in form-based onchange) """ + ActivityType = self.env['mail.activity.type'] + email_activity_type = ActivityType.create({ + 'name': 'email', + 'summary': 'Email Summary', + }) + call_activity_type = ActivityType.create({'name': 'call'}) + with Form(self.env['mail.activity'].with_context(default_res_model_id=self.env.ref('base.model_res_partner'))) as ActivityForm: + ActivityForm.res_model_id = self.env.ref('base.model_res_partner') + + ActivityForm.activity_type_id = call_activity_type + # activity summary should be empty + self.assertEqual(ActivityForm.summary, False) + + ActivityForm.activity_type_id = email_activity_type + # activity summary should be replaced with email's default summary + self.assertEqual(ActivityForm.summary, email_activity_type.summary) + + ActivityForm.activity_type_id = call_activity_type + # activity summary remains unchanged from change of activity type as call activity doesn't have default summary + self.assertEqual(ActivityForm.summary, email_activity_type.summary) + + def test_action_feedback_attachment(self): + Partner = self.env['res.partner'] + Activity = self.env['mail.activity'] + Attachment = self.env['ir.attachment'] + Message = self.env['mail.message'] + + partner = self.env['res.partner'].create({ + 'name': 'Tester', + }) + + activity = Activity.create({ + 'summary': 'Test', + 'activity_type_id': 1, + 'res_model_id': self.env.ref('base.model_res_partner').id, + 'res_id': partner.id, + }) + + attachments = Attachment + attachments += Attachment.create({ + 'name': 'test', + 'res_name': 'test', + 'res_model': 'mail.activity', + 'res_id': activity.id, + 'datas': 'test', + }) + attachments += Attachment.create({ + 'name': 'test2', + 'res_name': 'test', + 'res_model': 'mail.activity', + 'res_id': activity.id, + 'datas': 'testtest', + }) + + # Checking if the attachment has been forwarded to the message + # when marking an activity as "Done" + activity.action_feedback() + activity_message = Message.search([], order='id desc', limit=1) + self.assertEqual(set(activity_message.attachment_ids.ids), set(attachments.ids)) + for attachment in attachments: + self.assertEqual(attachment.res_id, activity_message.id) + self.assertEqual(attachment.res_model, activity_message._name) + + +@tests.tagged('mail_activity') +class TestActivityMixin(TestActivityCommon): + + @mute_logger('odoo.addons.mail.models.mail_mail') + def test_activity_mixin(self): + self.user_employee.tz = self.user_admin.tz + with self.with_user('employee'): + self.test_record = self.env['mail.test.activity'].browse(self.test_record.id) + self.assertEqual(self.test_record.env.user, self.user_employee) + + now_utc = datetime.now(pytz.UTC) + now_user = now_utc.astimezone(pytz.timezone(self.env.user.tz or 'UTC')) + today_user = now_user.date() + + # Test various scheduling of activities + act1 = self.test_record.activity_schedule( + 'test_mail.mail_act_test_todo', + today_user + relativedelta(days=1), + user_id=self.user_admin.id) + self.assertEqual(act1.automated, True) + + act_type = self.env.ref('test_mail.mail_act_test_todo') + self.assertEqual(self.test_record.activity_summary, act_type.summary) + self.assertEqual(self.test_record.activity_state, 'planned') + self.assertEqual(self.test_record.activity_user_id, self.user_admin) + + act2 = self.test_record.activity_schedule( + 'test_mail.mail_act_test_meeting', + today_user + relativedelta(days=-1)) + self.assertEqual(self.test_record.activity_state, 'overdue') + # `activity_user_id` is defined as `fields.Many2one('res.users', 'Responsible User', related='activity_ids.user_id')` + # it therefore relies on the natural order of `activity_ids`, according to which activity comes first. + # As we just created the activity, its not yet in the right order. + # We force it by invalidating it so it gets fetched from database, in the right order. + self.test_record.invalidate_cache(['activity_ids']) + self.assertEqual(self.test_record.activity_user_id, self.user_employee) + + act3 = self.test_record.activity_schedule( + 'test_mail.mail_act_test_todo', + today_user + relativedelta(days=3), + user_id=self.user_employee.id) + self.assertEqual(self.test_record.activity_state, 'overdue') + # `activity_user_id` is defined as `fields.Many2one('res.users', 'Responsible User', related='activity_ids.user_id')` + # it therefore relies on the natural order of `activity_ids`, according to which activity comes first. + # As we just created the activity, its not yet in the right order. + # We force it by invalidating it so it gets fetched from database, in the right order. + self.test_record.invalidate_cache(['activity_ids']) + self.assertEqual(self.test_record.activity_user_id, self.user_employee) + + self.test_record.invalidate_cache(ids=self.test_record.ids) + self.assertEqual(self.test_record.activity_ids, act1 | act2 | act3) + + # Perform todo activities for admin + self.test_record.activity_feedback( + ['test_mail.mail_act_test_todo'], + user_id=self.user_admin.id, + feedback='Test feedback',) + self.assertEqual(self.test_record.activity_ids, act2 | act3) + + # Reschedule all activities, should update the record state + self.assertEqual(self.test_record.activity_state, 'overdue') + self.test_record.activity_reschedule( + ['test_mail.mail_act_test_meeting', 'test_mail.mail_act_test_todo'], + date_deadline=today_user + relativedelta(days=3) + ) + self.assertEqual(self.test_record.activity_state, 'planned') + + # Perform todo activities for remaining people + self.test_record.activity_feedback( + ['test_mail.mail_act_test_todo'], + feedback='Test feedback') + + # Setting activities as done should delete them and post messages + self.assertEqual(self.test_record.activity_ids, act2) + self.assertEqual(len(self.test_record.message_ids), 2) + self.assertEqual(self.test_record.message_ids.mapped('subtype_id'), self.env.ref('mail.mt_activities')) + + # Perform meeting activities + self.test_record.activity_unlink(['test_mail.mail_act_test_meeting']) + + # Canceling activities should simply remove them + self.assertEqual(self.test_record.activity_ids, self.env['mail.activity']) + self.assertEqual(len(self.test_record.message_ids), 2) + + @mute_logger('odoo.addons.mail.models.mail_mail') + def test_activity_mixin_archive(self): + rec = self.test_record.with_user(self.user_employee) + new_act = rec.activity_schedule( + 'test_mail.mail_act_test_todo', + user_id=self.user_admin.id) + self.assertEqual(rec.activity_ids, new_act) + rec.toggle_active() + self.assertEqual(rec.active, False) + self.assertEqual(rec.activity_ids, self.env['mail.activity']) + rec.toggle_active() + self.assertEqual(rec.active, True) + self.assertEqual(rec.activity_ids, self.env['mail.activity']) + + @mute_logger('odoo.addons.mail.models.mail_mail') + def test_activity_mixin_reschedule_user(self): + rec = self.test_record.with_user(self.user_employee) + rec.activity_schedule( + 'test_mail.mail_act_test_todo', + user_id=self.user_admin.id) + self.assertEqual(rec.activity_ids[0].user_id, self.user_admin) + + # reschedule its own should not alter other's activities + rec.activity_reschedule( + ['test_mail.mail_act_test_todo'], + user_id=self.user_employee.id, + new_user_id=self.user_employee.id) + self.assertEqual(rec.activity_ids[0].user_id, self.user_admin) + + rec.activity_reschedule( + ['test_mail.mail_act_test_todo'], + user_id=self.user_admin.id, + new_user_id=self.user_employee.id) + self.assertEqual(rec.activity_ids[0].user_id, self.user_employee) + + @mute_logger('odoo.addons.mail.models.mail_mail') + def test_my_activity_flow_employee(self): + Activity = self.env['mail.activity'] + date_today = date.today() + activity_1 = Activity.create({ + 'activity_type_id': self.env.ref('test_mail.mail_act_test_todo').id, + 'date_deadline': date_today, + 'res_model_id': self.env.ref('test_mail.model_mail_test_activity').id, + 'res_id': self.test_record.id, + 'user_id': self.user_admin.id, + }) + activity_2 = Activity.create({ + 'activity_type_id': self.env.ref('test_mail.mail_act_test_call').id, + 'date_deadline': date_today + relativedelta(days=1), + 'res_model_id': self.env.ref('test_mail.model_mail_test_activity').id, + 'res_id': self.test_record.id, + 'user_id': self.user_employee.id, + }) + + test_record_1 = self.env['mail.test.activity'].with_context(self._test_context).create({'name': 'Test 1'}) + activity_3 = Activity.create({ + 'activity_type_id': self.env.ref('test_mail.mail_act_test_todo').id, + 'date_deadline': date_today, + 'res_model_id': self.env.ref('test_mail.model_mail_test_activity').id, + 'res_id': test_record_1.id, + 'user_id': self.user_employee.id, + }) + with self.with_user('employee'): + record = self.env['mail.test.activity'].search([('my_activity_date_deadline', '=', date_today)]) + self.assertEqual(test_record_1, record) + +class TestReadProgressBar(tests.TransactionCase): + """Test for read_progress_bar""" + + def test_week_grouping(self): + """The labels associated to each record in read_progress_bar should match + the ones from read_group, even in edge cases like en_US locale on sundays + """ + model = self.env['mail.test.activity'].with_context(lang='en_US') + + # Don't mistake fields date and date_deadline: + # * date is just a random value + # * date_deadline defines activity_state + model.create({ + 'date': '2021-05-02', + 'name': "Yesterday, all my troubles seemed so far away", + }).activity_schedule( + 'test_mail.mail_act_test_todo', + summary="Make another test super asap (yesterday)", + date_deadline=fields.Date.context_today(model) - timedelta(days=7), + ) + model.create({ + 'date': '2021-05-09', + 'name': "Things we said today", + }).activity_schedule( + 'test_mail.mail_act_test_todo', + summary="Make another test asap", + date_deadline=fields.Date.context_today(model), + ) + model.create({ + 'date': '2021-05-16', + 'name': "Tomorrow Never Knows", + }).activity_schedule( + 'test_mail.mail_act_test_todo', + summary="Make a test tomorrow", + date_deadline=fields.Date.context_today(model) + timedelta(days=7), + ) + + domain = [('date', "!=", False)] + groupby = "date:week" + progress_bar = { + 'field': 'activity_state', + 'colors': { + "overdue": 'danger', + "today": 'warning', + "planned": 'success', + } + } + + # call read_group to compute group names + groups = model.read_group(domain, fields=['date'], groupby=[groupby]) + progressbars = model.read_progress_bar(domain, group_by=groupby, progress_bar=progress_bar) + self.assertEqual(len(groups), 3) + self.assertEqual(len(progressbars), 3) + + # format the read_progress_bar result to get a dictionary under this + # format: {activity_state: group_name}; the original format + # (after read_progress_bar) is {group_name: {activity_state: count}} + pg_groups = { + next(state for state, count in data.items() if count): group_name + for group_name, data in progressbars.items() + } + + self.assertEqual(groups[0][groupby], pg_groups["overdue"]) + self.assertEqual(groups[1][groupby], pg_groups["today"]) + self.assertEqual(groups[2][groupby], pg_groups["planned"]) + |
