diff --git a/addons/calendar/__manifest__.py b/addons/calendar/__manifest__.py
index 11fb1122dc2..410b6400c6f 100644
--- a/addons/calendar/__manifest__.py
+++ b/addons/calendar/__manifest__.py
@@ -39,6 +39,8 @@ If you need to manage your meetings, you should install the CRM module.
'auto_install': False,
'assets': {
'web.assets_backend': [
+ 'calendar/static/src/models/activity/activity.js',
+ 'calendar/static/src/components/activity/activity.js',
'calendar/static/src/scss/calendar.scss',
'calendar/static/src/js/base_calendar.js',
'calendar/static/src/js/calendar_renderer.js',
@@ -53,6 +55,7 @@ If you need to manage your meetings, you should install the CRM module.
],
'web.assets_qweb': [
'calendar/static/src/xml/base_calendar.xml',
+ 'calendar/static/src/components/activity/activity.xml',
],
},
'license': 'LGPL-3',
diff --git a/addons/calendar/static/src/components/activity/activity.js b/addons/calendar/static/src/components/activity/activity.js
new file mode 100644
index 00000000000..a49260c49f4
--- /dev/null
+++ b/addons/calendar/static/src/components/activity/activity.js
@@ -0,0 +1,35 @@
+/** @odoo-module */
+
+import { Activity } from '@mail/components/activity/activity';
+import { patch } from 'web.utils';
+import Dialog from 'web.Dialog';
+import core from 'web.core';
+const _t = core._t;
+
+patch(Activity.prototype, 'calendar/static/src/components/activity/activity.js', {
+ //--------------------------------------------------------------------------
+ // Handlers
+ //--------------------------------------------------------------------------
+
+ /**
+ * Small override that asks for confirmation in case there is a meeting linked to this activity.
+ *
+ * @override
+ */
+ _onClickCancel(ev) {
+ const superMethod = this._super;
+ if (!this.activity.calendar_event_id){
+ this._super(ev);
+ } else {
+ Dialog.confirm(
+ this,
+ _t("The activity is linked to a meeting. Deleting it will remove the meeting as well. Do you want to proceed ?"), {
+ confirm_callback: function () {
+ superMethod(ev);
+ },
+ }
+ );
+ }
+ }
+
+});
diff --git a/addons/calendar/static/src/components/activity/activity.xml b/addons/calendar/static/src/components/activity/activity.xml
new file mode 100644
index 00000000000..5cffc8e2415
--- /dev/null
+++ b/addons/calendar/static/src/components/activity/activity.xml
@@ -0,0 +1,17 @@
+
+
+
+
+
+ !activity.calendar_event_id
+
+
+
+
+
+
+
+
+
diff --git a/addons/calendar/static/src/models/activity/activity.js b/addons/calendar/static/src/models/activity/activity.js
new file mode 100644
index 00000000000..7dbb4dfbf36
--- /dev/null
+++ b/addons/calendar/static/src/models/activity/activity.js
@@ -0,0 +1,63 @@
+/** @odoo-module **/
+
+import {
+ registerClassPatchModel,
+ registerInstancePatchModel,
+ registerFieldPatchModel
+} from'@mail/model/model_core';
+import { attr } from '@mail/model/model_field';
+
+registerFieldPatchModel('mail.activity', 'calendar/static/src/models/activity/activity.js', {
+ calendar_event_id: attr({ default: false }),
+});
+
+registerClassPatchModel('mail.activity', 'calendar/static/src/models/activity/activity.js', {
+ /**
+ * @override
+ */
+ convertData(data) {
+ const res = this._super(data);
+ if ('calendar_event_id' in data) {
+ res.calendar_event_id = data.calendar_event_id[0];
+ }
+ return res;
+ },
+});
+
+registerInstancePatchModel('mail.activity', 'calendar/static/src/models/activity/activity.js', {
+ /**
+ * @override
+ */
+ async deleteServerRecord() {
+ if (!this.calendar_event_id){
+ await this._super();
+ } else {
+ await this.async(() => this.env.services.rpc({
+ model: 'mail.activity',
+ method: 'unlink_w_meeting',
+ args: [[this.id]],
+ }));
+ this.delete();
+ }
+ },
+
+ /**
+ * In case the activity is linked to a meeting, we want to open the calendar view instead.
+ *
+ * @override
+ */
+ async edit() {
+ if (!this.calendar_event_id){
+ this._super();
+ } else {
+ const action = await this.async(() => this.env.services.rpc({
+ model: 'mail.activity',
+ method: 'action_create_calendar_event',
+ args: [[this.id]],
+ }));
+ this.env.bus.trigger('do-action', {
+ action
+ });
+ }
+ }
+});
diff --git a/addons/calendar/views/mail_activity_views.xml b/addons/calendar/views/mail_activity_views.xml
index d3681be20b1..a434a4943a4 100644
--- a/addons/calendar/views/mail_activity_views.xml
+++ b/addons/calendar/views/mail_activity_views.xml
@@ -12,21 +12,21 @@
{'invisible': [('activity_category', '=', 'meeting')]}
-
- {'invisible': ['|', ('activity_category', '=', 'meeting'), ('id', '!=', False)]}
+
+ {'invisible': ['|', ('activity_category', 'in', ['meeting', 'phonecall']), ('id', '!=', False)]}
+
+
+ {'invisible': [('activity_category', '!=', 'phonecall'), ('id', '=', False)]}
{'invisible': ['|', ('activity_category', '=', 'meeting'), ('chaining_type', '=', 'trigger')]}
-
- {'invisible': [('activity_category', '=', 'meeting')]}
-
{'invisible': [('activity_category', '=', 'meeting')]}
diff --git a/addons/crm/data/mail_activity_demo.xml b/addons/crm/data/mail_activity_demo.xml
index 33a44207475..e1257f8ff8a 100644
--- a/addons/crm/data/mail_activity_demo.xml
+++ b/addons/crm/data/mail_activity_demo.xml
@@ -12,11 +12,13 @@
crm.lead
15
+
Call for Demo
fa-phone
crm.lead
10
+ phonecall
diff --git a/addons/crm/models/__init__.py b/addons/crm/models/__init__.py
index 2282f96b1d3..edf953a4730 100644
--- a/addons/crm/models/__init__.py
+++ b/addons/crm/models/__init__.py
@@ -15,3 +15,4 @@ from . import digest
from . import crm_lead_scoring_frequency
from . import utm
from . import crm_recurring_plan
+from . import mail_activity
diff --git a/addons/crm/models/mail_activity.py b/addons/crm/models/mail_activity.py
new file mode 100644
index 00000000000..85f7e45016f
--- /dev/null
+++ b/addons/crm/models/mail_activity.py
@@ -0,0 +1,26 @@
+# -*- coding: utf-8 -*-
+# Part of Odoo. See LICENSE file for full copyright and licensing details.
+
+from odoo import models
+
+
+class MailActivity(models.Model):
+ _inherit = "mail.activity"
+
+ def action_create_calendar_event(self):
+ """ Small override of the action that creates a calendar.
+
+ If the activity is linked to a crm.lead through the "opportunity_id" field, we include in
+ the action context the default values used when scheduling a meeting from the crm.lead form
+ view.
+ e.g: It will set the partner_id of the crm.lead as default attendee of the meeting. """
+
+ action = super(MailActivity, self).action_create_calendar_event()
+ opportunity = self.calendar_event_id.opportunity_id
+ if opportunity:
+ opportunity_action_context = opportunity.action_schedule_meeting(smart_calendar=False).get('context', {})
+ opportunity_action_context['initial_date'] = self.calendar_event_id.start
+
+ action['context'].update(opportunity_action_context)
+
+ return action
diff --git a/addons/mail/data/mail_activity_data.xml b/addons/mail/data/mail_activity_data.xml
index 04acedaec7c..97a173705fa 100644
--- a/addons/mail/data/mail_activity_data.xml
+++ b/addons/mail/data/mail_activity_data.xml
@@ -9,6 +9,7 @@
Call
fa-phone
+ phonecall
2
6
diff --git a/addons/mail/models/mail_activity_type.py b/addons/mail/models/mail_activity_type.py
index c305919c804..20c2a7f44d2 100644
--- a/addons/mail/models/mail_activity_type.py
+++ b/addons/mail/models/mail_activity_type.py
@@ -63,7 +63,9 @@ class MailActivityType(models.Model):
domain="['|', ('res_model', '=', False), ('res_model', '=', res_model)]",
string='Preceding Activities')
category = fields.Selection([
- ('default', 'None'), ('upload_file', 'Upload Document')
+ ('default', 'None'),
+ ('upload_file', 'Upload Document'),
+ ('phonecall', 'Phonecall')
], default='default', string='Action',
help='Actions may trigger specific behavior like opening calendar view or automatically mark as done when a document is uploaded')
mail_template_ids = fields.Many2many('mail.template', string='Email templates')
diff --git a/addons/mail/views/mail_activity_views.xml b/addons/mail/views/mail_activity_views.xml
index 6883a4c63ed..1b5f10ae6b4 100644
--- a/addons/mail/views/mail_activity_views.xml
+++ b/addons/mail/views/mail_activity_views.xml
@@ -129,9 +129,9 @@