summaryrefslogtreecommitdiff
path: root/addons/test_mail/tests/test_mail_activity.py
diff options
context:
space:
mode:
authorstephanchrst <stephanchrst@gmail.com>2022-05-10 21:51:50 +0700
committerstephanchrst <stephanchrst@gmail.com>2022-05-10 21:51:50 +0700
commit3751379f1e9a4c215fb6eb898b4ccc67659b9ace (patch)
treea44932296ef4a9b71d5f010906253d8c53727726 /addons/test_mail/tests/test_mail_activity.py
parent0a15094050bfde69a06d6eff798e9a8ddf2b8c21 (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.py434
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"])
+