diff --git a/addons/calendar/models/__init__.py b/addons/calendar/models/__init__.py index 3cacb6bca87..89acd141801 100644 --- a/addons/calendar/models/__init__.py +++ b/addons/calendar/models/__init__.py @@ -11,4 +11,5 @@ from . import calendar_contact from . import calendar_event_type from . import calendar_recurrence from . import mail_activity +from . import mail_activity_mixin from . import res_users diff --git a/addons/calendar/models/mail_activity_mixin.py b/addons/calendar/models/mail_activity_mixin.py new file mode 100644 index 00000000000..4e2b203bc76 --- /dev/null +++ b/addons/calendar/models/mail_activity_mixin.py @@ -0,0 +1,18 @@ +# -*- coding: utf-8 -*- +# Part of Odoo. See LICENSE file for full copyright and licensing details. + +from odoo import api, fields, models + +class MailActivityMixin(models.AbstractModel): + _inherit = 'mail.activity.mixin' + + activity_calendar_event_id = fields.Many2one( + 'calendar.event', string="Next Activity Calendar Event", + compute='_compute_activity_calendar_event_id', groups="base.group_user") + + @api.depends('activity_ids.calendar_event_id') + def _compute_activity_calendar_event_id(self): + """This computes the calendar event of the next activity. + It evaluates to false if there is no such event.""" + for record in self: + record.activity_calendar_event_id = record.activity_ids[:1].calendar_event_id diff --git a/addons/calendar/tests/__init__.py b/addons/calendar/tests/__init__.py index e16500942a3..409654f26f2 100644 --- a/addons/calendar/tests/__init__.py +++ b/addons/calendar/tests/__init__.py @@ -8,3 +8,4 @@ from . import test_calendar_controller from . import test_calendar_recurrent_event_case2 from . import test_event_recurrence from . import test_event_notifications +from . import test_mail_activity_mixin diff --git a/addons/calendar/tests/test_mail_activity_mixin.py b/addons/calendar/tests/test_mail_activity_mixin.py new file mode 100644 index 00000000000..826db01eb51 --- /dev/null +++ b/addons/calendar/tests/test_mail_activity_mixin.py @@ -0,0 +1,77 @@ +# -*- coding: utf-8 -*- +# Part of Odoo. See LICENSE file for full copyright and licensing details. + +from datetime import datetime, time +from dateutil.relativedelta import relativedelta + +import pytz + +from odoo import Command +from odoo import tests +from odoo.addons.mail.tests.common import MailCommon + + +@tests.tagged('mail_activity_mixin') +class TestMailActivityMixin(MailCommon): + + @classmethod + def setUpClass(cls): + super(TestMailActivityMixin, cls).setUpClass() + # using res.partner as the model inheriting from mail.activity.mixin + cls.test_record = cls.env['res.partner'].with_context(cls._test_context).create({'name': 'Test'}) + cls.activity_type_1 = cls.env['mail.activity.type'].create({ + 'name': 'Calendar Activity Test Default', + 'summary': 'default activity', + 'res_model_id': cls.env['ir.model']._get('base.res_partner').id, + }) + cls.env['ir.model.data'].create({ + 'name': cls.activity_type_1.name.lower().replace(' ', '_'), + 'module': 'calendar', + 'model': cls.activity_type_1._name, + 'res_id': cls.activity_type_1.id, + }) + # reset ctx + cls._reset_mail_context(cls.test_record) + + def test_activity_calendar_event_id(self): + """Test the computed field "activity_calendar_event_id" which is the event of the + next activity. It must evaluate to False if the next activity is not related to an event""" + def create_event(name, event_date): + return self.env['calendar.event'].create({ + 'name': name, + 'start': datetime.combine(event_date, time(12, 0, 0)), + 'stop': datetime.combine(event_date, time(14, 0, 0)), + }) + + def schedule_meeting_activity(record, date_deadline, calendar_event=False): + meeting = record.activity_schedule('calendar.calendar_activity_test_default', date_deadline=date_deadline) + meeting.calendar_event_id = calendar_event + return meeting + + group_partner_manager = self.env['ir.model.data'].xmlid_to_res_id('base.group_partner_manager') + self.user_employee.write({ + 'tz': self.user_admin.tz, + 'groups_id': [Command.link(group_partner_manager)] + }) + with self.with_user('employee'): + test_record = self.env['res.partner'].browse(self.test_record.id) + self.assertEqual(test_record.activity_ids, self.env['mail.activity']) + + now_utc = datetime.now(pytz.UTC) + now_user = now_utc.astimezone(pytz.timezone(self.env.user.tz or 'UTC')) + today_user = now_user.date() + + date1 = today_user + relativedelta(days=1) + date2 = today_user + relativedelta(days=2) + + ev1 = create_event('ev1', date1) + ev2 = create_event('ev2', date2) + + act1 = schedule_meeting_activity(test_record, date1) + schedule_meeting_activity(test_record, date2, ev2) + + self.assertFalse(test_record.activity_calendar_event_id, "The next activity does not have a calendar event") + + act1.calendar_event_id = ev1 + + self.assertEqual(test_record.activity_calendar_event_id.name, ev1.name, "This should be the calendar event of the next activity") diff --git a/addons/crm/models/crm_lead.py b/addons/crm/models/crm_lead.py index 64c443c3e0f..e5e85819024 100644 --- a/addons/crm/models/crm_lead.py +++ b/addons/crm/models/crm_lead.py @@ -946,6 +946,14 @@ class Lead(models.Model): } return action + def action_reschedule_meeting(self): + self.ensure_one() + action = self.action_schedule_meeting() + next_activity = self.activity_ids.filtered(lambda activity: activity.user_id == self.env.user)[:1] + if next_activity.calendar_event_id: + action['context']['initial_date'] = next_activity.calendar_event_id.start + return action + def action_snooze(self): self.ensure_one() today = date.today() diff --git a/addons/crm/views/crm_lead_views.xml b/addons/crm/views/crm_lead_views.xml index 83838fa8c5d..392c1f974f3 100644 --- a/addons/crm/views/crm_lead_views.xml +++ b/addons/crm/views/crm_lead_views.xml @@ -678,10 +678,11 @@ - + + @@ -696,9 +697,13 @@ -