[IMP] crm: add a reschedule action for activities
* Replace the "Snooze 7d" action for lead-related activities linked to
a calendar event by a "Reschedule" action, which will redirect the user
to the calendar view with the focus on the next event related to the
opportunity
- The "Snooze 7d" action only impacted the activity and not the meeting,
and snoozing a meeting is not very logical anyway. The "Reschedule" fits
better in this use case.
* It was discussed to show only a modal allowing to reschedule the next
calendar event, but that could lead to inconsistent states (out of order
sequence of scheduled events, if the first is rescheduled after the
second).
* The reschedule option will be shown next to any activity related to a
calendar_event regardless of its activity type. There are some edge cases
that we may want to change in the future :
- When changing the activity type of a 'meeting' activity associated to
a calendar event to any other activity type, but without removing the
calendar event, the reschedule action is still showing (since the event
is still ongoing and was not deleted from the calendar).
- Conversely, with a meeting which is not (yet?) related to a calendar event,
the reschedule action will not be available.
* Add a new field to MailActivityMixin in the calendar module context. This
field is the event linked to the next activity, if there is one such event.
It is used to check whether the reschedule action should be available to the user.
* Add a test for this new field to validate the expected behavior.
* Add the priority widget to the priority field in the opportunity tree view
Task ID : 2410217
PR : https://github.com/odoo/odoo/pull/63370
This commit is contained in:
committed by
Damien (abd)
parent
67c7460be1
commit
b0134452c0
@@ -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
|
||||
|
||||
@@ -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
|
||||
@@ -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
|
||||
|
||||
@@ -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")
|
||||
@@ -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()
|
||||
|
||||
@@ -678,10 +678,11 @@
|
||||
<field name="user_id" widget="many2one_avatar_user" optional="show"
|
||||
domain="[('share', '=', False)]"/>
|
||||
<field name="team_id" optional="hide"/>
|
||||
<field name="priority" optional="hide"/>
|
||||
<field name="priority" optional="hide" widget="priority"/>
|
||||
<field name="activity_ids" widget="list_activity"/>
|
||||
<field name="activity_user_id" optional="hide" string="Activity by" widget="many2one_avatar_user"/>
|
||||
<field name="activity_date_deadline_my" string="My Deadline" widget="remaining_days" options="{'allow_order': '1'}"/>
|
||||
<field name="activity_calendar_event_id" invisible="1"/>
|
||||
<field name="campaign_id" optional="hide"/>
|
||||
<field name="medium_id" optional="hide"/>
|
||||
<field name="source_id" optional="hide"/>
|
||||
@@ -696,9 +697,13 @@
|
||||
<field name="tag_ids" optional="hide" widget="many2many_tags" options="{'color_field': 'color'}"/>
|
||||
<field name="referred" invisible="1"/>
|
||||
<field name="message_needaction" invisible="1"/>
|
||||
<button name="action_snooze" class="text-warning" type="object" string="Snooze 7d" icon="fa-bell-slash"
|
||||
attrs="{'invisible': [('activity_date_deadline_my', '=', False)]}"/>
|
||||
<button name="%(crm.action_lead_mail_compose)d" type="action" string="Email" icon="fa-envelope"/>
|
||||
<button name="action_reschedule_meeting" class="text-warning" type="object" string="Reschedule"
|
||||
icon="fa-calendar" attrs="{'invisible': ['|', ('activity_date_deadline_my', '=', False),
|
||||
('activity_calendar_event_id', '=', False)]}"/>
|
||||
<button name="action_snooze" class="text-warning" type="object" string="Snooze 7d"
|
||||
icon="fa-bell-slash" attrs="{'invisible': ['|', ('activity_date_deadline_my', '=', False),
|
||||
('activity_calendar_event_id', '!=', False)]}"/>
|
||||
</tree>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
Reference in New Issue
Block a user