[IMP] mail: refactor activity.js and add some test
activity.js was a little dirty with a lot of copy paste. Most of the common logic is now in a BasicModel. This commit also add some tests on activity view Co-authored-by: RomainLibert <rli@odoo.com>
This commit is contained in:
committed by
RomainLibert
co-authored by
RomainLibert
parent
c90ff2afd8
commit
0be33db68a
@@ -409,7 +409,7 @@ class MailActivity(models.Model):
|
||||
default_res_id=self.res_id,
|
||||
default_res_model=self.res_model,
|
||||
)
|
||||
self.action_done()
|
||||
self.action_feedback(feedback)
|
||||
return {
|
||||
'name': _('Schedule an Activity'),
|
||||
'context': wizard_ctx,
|
||||
|
||||
@@ -40,10 +40,8 @@ function _readActivities(self, ids) {
|
||||
activity.create_date = moment(time.auto_str_to_date(activity.create_date));
|
||||
activity.date_deadline = moment(time.auto_str_to_date(activity.date_deadline));
|
||||
});
|
||||
|
||||
// sort activities by due date
|
||||
// sort activities by due date
|
||||
activities = _.sortBy(activities, 'date_deadline');
|
||||
|
||||
return activities;
|
||||
});
|
||||
}
|
||||
@@ -103,7 +101,32 @@ var setDelayLabel = function (activities){
|
||||
return activities;
|
||||
};
|
||||
|
||||
var AbstractActivityField = AbstractField.extend({
|
||||
var BasicActivity = AbstractField.extend({
|
||||
events: {
|
||||
'click .o_edit_activity': '_onEditActivity',
|
||||
'click .o_mark_as_done': '_onMarkActivityDone',
|
||||
'click .o_activity_template_preview': '_onPreviewMailTemplate',
|
||||
'click .o_schedule_activity': '_onScheduleActivity',
|
||||
'click .o_activity_template_send': '_onSendMailTemplate',
|
||||
'click .o_unlink_activity': '_onUnlinkActivity',
|
||||
},
|
||||
init: function () {
|
||||
this._super.apply(this, arguments);
|
||||
this._draftFeedback = {};
|
||||
},
|
||||
|
||||
//------------------------------------------------------------
|
||||
// Public
|
||||
//------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* @param {integer} previousActivityTypeID
|
||||
* @return {$.Promise}
|
||||
*/
|
||||
scheduleActivity: function () {
|
||||
var callback = this._reload.bind(this, { activity: true, thread: true });
|
||||
return this._openActivityForm(false, callback);
|
||||
},
|
||||
|
||||
//------------------------------------------------------------
|
||||
// Private
|
||||
@@ -159,9 +182,9 @@ var AbstractActivityField = AbstractField.extend({
|
||||
* @param {integer} id
|
||||
* @param {integer} previousActivityTypeID
|
||||
* @param {function} callback
|
||||
* @return {$.Promise}
|
||||
* @return {$.Deferred}
|
||||
*/
|
||||
_scheduleActivity: function (id, previousActivityTypeID, callback) {
|
||||
_openActivityForm: function (id, callback) {
|
||||
var action = {
|
||||
type: 'ir.actions.act_window',
|
||||
res_model: 'mail.activity',
|
||||
@@ -172,7 +195,6 @@ var AbstractActivityField = AbstractField.extend({
|
||||
context: {
|
||||
default_res_id: this.res_id,
|
||||
default_res_model: this.model,
|
||||
default_previous_activity_type_id: previousActivityTypeID,
|
||||
},
|
||||
res_id: id || false,
|
||||
};
|
||||
@@ -193,43 +215,173 @@ var AbstractActivityField = AbstractField.extend({
|
||||
context: this.record.getContext(),
|
||||
});
|
||||
},
|
||||
|
||||
//------------------------------------------------------------
|
||||
// Handlers
|
||||
//------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @param {MouseEvent} ev
|
||||
* @returns {$.Promise}
|
||||
*/
|
||||
_onEditActivity: function (ev) {
|
||||
ev.preventDefault();
|
||||
var activityID = $(ev.currentTarget).data('activity-id');
|
||||
return this._openActivityForm(activityID, this._reload.bind(this));
|
||||
},
|
||||
/**
|
||||
* Called when marking an activity as done
|
||||
*
|
||||
* It lets the current user write a feedback in a popup menu.
|
||||
* After writing the feedback and confirm mark as done
|
||||
* is sent, it marks this activity as done for good with the feedback linked
|
||||
* to it.
|
||||
*
|
||||
* @private
|
||||
* @param {MouseEvent} ev
|
||||
*/
|
||||
_onMarkActivityDone: function (ev) {
|
||||
ev.stopPropagation();
|
||||
ev.preventDefault();
|
||||
var self = this;
|
||||
var $popoverElement = $(ev.currentTarget);
|
||||
var activityID = $popoverElement.data('activity-id');
|
||||
var previousActivityTypeID = $popoverElement.data('previous-activity-type-id');
|
||||
if (!$popoverElement.data('bs.popover')) {
|
||||
$popoverElement.popover({
|
||||
template: $(Popover.Default.template).addClass('o_mail_activity_feedback')[0].outerHTML, // Ugly but cannot find another way
|
||||
container: $popoverElement,
|
||||
title : _t("Feedback"),
|
||||
html: true,
|
||||
trigger:'click',
|
||||
placement: 'right', // FIXME: this should work, maybe a bug in the popper lib
|
||||
content : function () {
|
||||
var $popover = $(QWeb.render('mail.activity_feedback_form', { previous_activity_type_id: previousActivityTypeID }));
|
||||
$popover.find('#activity_feedback').val(self._draftFeedback[activityID]);
|
||||
$popover.on('click', '.o_activity_popover_done', function (ev) {
|
||||
ev.stopPropagation();
|
||||
self._markActivityDone({
|
||||
activityID: activityID,
|
||||
feedback: _.escape($popover.find('#activity_feedback').val()),
|
||||
});
|
||||
});
|
||||
$popover.on('click', '.o_activity_popover_done_next', function (ev) {
|
||||
ev.stopPropagation();
|
||||
self._markActivityDoneAndScheduleNext({
|
||||
activityID: activityID,
|
||||
feedback: _.escape($popover.find('#activity_feedback').val()),
|
||||
});
|
||||
});
|
||||
$popover.on('click', '.o_activity_popover_discard', function (ev) {
|
||||
ev.stopPropagation();
|
||||
$popoverElement.popover('hide');
|
||||
});
|
||||
return $popover;
|
||||
},
|
||||
}).on('shown.bs.popover', function () {
|
||||
var $popover = $($(this).data("bs.popover").tip);
|
||||
$(".o_mail_activity_feedback.popover").not($popover).popover("hide");
|
||||
$popover.addClass('o_mail_activity_feedback').attr('tabindex', 0);
|
||||
$popover.find('#activity_feedback').focus();
|
||||
$popover.off('focusout');
|
||||
$popover.focusout(function (e) {
|
||||
// outside click of popover hide the popover
|
||||
// e.relatedTarget is the element receiving the focus
|
||||
if (!$popover.is(e.relatedTarget) && !$popover.find(e.relatedTarget).length) {
|
||||
self._draftFeedback[activityID] = $popover.find('#activity_feedback').val();
|
||||
$popover.popover('hide');
|
||||
}
|
||||
});
|
||||
}).popover('show');
|
||||
}
|
||||
},
|
||||
/**
|
||||
* @private
|
||||
* @param {MouseEvent} ev
|
||||
* @returns {$.Deferred}
|
||||
*/
|
||||
_onPreviewMailTemplate: function (ev) {
|
||||
ev.stopPropagation();
|
||||
var templateID = $(ev.currentTarget).data('template-id');
|
||||
var action = {
|
||||
name: _t('Compose Email'),
|
||||
type: 'ir.actions.act_window',
|
||||
res_model: 'mail.compose.message',
|
||||
views: [[false, 'form']],
|
||||
target: 'new',
|
||||
context: {
|
||||
default_res_id: this.res_id,
|
||||
default_model: this.model,
|
||||
default_use_template: true,
|
||||
default_template_id: templateID,
|
||||
force_email: true,
|
||||
},
|
||||
};
|
||||
return this.do_action(action, { on_close: function () {} });
|
||||
},
|
||||
/**
|
||||
* @private
|
||||
* @param {MouseEvent} ev
|
||||
* @returns {$.Promise}
|
||||
*/
|
||||
_onSendMailTemplate: function (ev) {
|
||||
ev.stopPropagation();
|
||||
var templateID = $(ev.currentTarget).data('template-id');
|
||||
return this._rpc({
|
||||
model: this.model,
|
||||
method: 'activity_send_mail',
|
||||
args: [[this.res_id], templateID],
|
||||
})
|
||||
.then(this._reload.bind(this, {activity: true, thread: true, followers: true}));
|
||||
},
|
||||
/**
|
||||
* @private
|
||||
* @param {MouseEvent} ev
|
||||
* @returns {$.Deferred}
|
||||
*/
|
||||
_onScheduleActivity: function (ev) {
|
||||
ev.preventDefault();
|
||||
return this._openActivityForm(false, this._reload.bind(this));
|
||||
},
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @param {MouseEvent} ev
|
||||
* @param {Object} options
|
||||
* @returns {$.Promise}
|
||||
*/
|
||||
_onUnlinkActivity: function (ev, options) {
|
||||
ev.preventDefault();
|
||||
var activityID = $(ev.currentTarget).data('activity-id');
|
||||
options = _.defaults(options || {}, {
|
||||
model: 'mail.activity',
|
||||
args: [[activityID]],
|
||||
});
|
||||
return this._rpc({
|
||||
model: options.model,
|
||||
method: 'unlink',
|
||||
args: options.args,
|
||||
})
|
||||
.then(this._reload.bind(this, {activity: true}));
|
||||
},
|
||||
});
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Activities Widget for Form views ('mail_activity' widget)
|
||||
// -----------------------------------------------------------------------------
|
||||
var Activity = AbstractActivityField.extend({
|
||||
var Activity = BasicActivity.extend({
|
||||
className: 'o_mail_activity',
|
||||
events: {
|
||||
events:_.extend({}, BasicActivity.prototype.events, {
|
||||
'click a': '_onClickRedirect',
|
||||
'click .o_activity_edit': '_onEditActivity',
|
||||
'click .o_activity_unlink': '_onUnlinkActivity',
|
||||
'click .o_activity_done': '_onMarkActivityDone',
|
||||
'click .o_activity_template_preview': '_onPreviewMailTemplate',
|
||||
'click .o_activity_template_send': '_onSendMailTemplate',
|
||||
},
|
||||
}),
|
||||
specialData: '_fetchSpecialActivity',
|
||||
|
||||
/**
|
||||
* @override
|
||||
*/
|
||||
init: function () {
|
||||
this._super.apply(this, arguments);
|
||||
this._activities = this.record.specialData[this.name];
|
||||
this._draftFeedback = {};
|
||||
},
|
||||
|
||||
//------------------------------------------------------------
|
||||
// Public
|
||||
//------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* @param {integer} previousActivityTypeID
|
||||
* @return {$.Promise}
|
||||
*/
|
||||
scheduleActivity: function (previousActivityTypeID) {
|
||||
var callback = this._reload.bind(this, { activity: true, thread: true });
|
||||
return this._scheduleActivity(false, previousActivityTypeID, callback);
|
||||
},
|
||||
|
||||
//------------------------------------------------------------
|
||||
@@ -293,173 +445,28 @@ var Activity = AbstractActivityField.extend({
|
||||
* @param {MouseEvent} ev
|
||||
*/
|
||||
_onClickRedirect: function (ev) {
|
||||
var id = $(ev.target).data('oe-id');
|
||||
var id = $(ev.currentTarget).data('oe-id');
|
||||
if (id) {
|
||||
ev.preventDefault();
|
||||
var model = $(ev.target).data('oe-model');
|
||||
var model = $(ev.currentTarget).data('oe-model');
|
||||
this.trigger_up('redirect', {
|
||||
res_id: id,
|
||||
res_model: model,
|
||||
});
|
||||
}
|
||||
},
|
||||
/**
|
||||
* @private
|
||||
* @param {MouseEvent} ev
|
||||
* @param {Object} options
|
||||
*/
|
||||
_onEditActivity: function (ev, options) {
|
||||
ev.preventDefault();
|
||||
var self = this;
|
||||
var activity_id = $(ev.currentTarget).data('activity-id');
|
||||
var action = _.defaults(options || {}, {
|
||||
type: 'ir.actions.act_window',
|
||||
res_model: 'mail.activity',
|
||||
view_mode: 'form',
|
||||
view_type: 'form',
|
||||
views: [[false, 'form']],
|
||||
target: 'new',
|
||||
context: {
|
||||
default_res_id: this.res_id,
|
||||
default_res_model: this.model,
|
||||
},
|
||||
res_id: activity_id,
|
||||
});
|
||||
return this.do_action(action, {
|
||||
on_close: function () {
|
||||
self._reload({activity: true, thread: true});
|
||||
},
|
||||
});
|
||||
},
|
||||
/**
|
||||
* @private
|
||||
* @param {MouseEvent} ev
|
||||
*/
|
||||
_onPreviewMailTemplate: function (ev) {
|
||||
var templateID = $(ev.target).data('template-id');
|
||||
var action = {
|
||||
name: _t('Compose Email'),
|
||||
type: 'ir.actions.act_window',
|
||||
res_model: 'mail.compose.message',
|
||||
views: [[false, 'form']],
|
||||
target: 'new',
|
||||
context: {
|
||||
default_res_id: this.res_id,
|
||||
default_model: this.model,
|
||||
default_use_template: true,
|
||||
default_template_id: templateID,
|
||||
force_email: true,
|
||||
},
|
||||
};
|
||||
return this.do_action(action, { on_close: function () {} });
|
||||
},
|
||||
/**
|
||||
* @private
|
||||
* @param {MouseEvent} ev
|
||||
*/
|
||||
_onSendMailTemplate: function (ev) {
|
||||
var templateID = $(ev.target).data('template-id');
|
||||
return this._rpc({
|
||||
model: this.model,
|
||||
method: 'activity_send_mail',
|
||||
args: [[this.res_id], templateID],
|
||||
})
|
||||
.then(this._reload.bind(this, {activity: true, thread: true, followers: true}));
|
||||
},
|
||||
/**
|
||||
* @private
|
||||
* @param {MouseEvent} ev
|
||||
* @param {Object} options
|
||||
*/
|
||||
_onUnlinkActivity: function (ev, options) {
|
||||
ev.preventDefault();
|
||||
var activityID = $(ev.currentTarget).data('activity-id');
|
||||
options = _.defaults(options || {}, {
|
||||
model: 'mail.activity',
|
||||
args: [[activityID]],
|
||||
});
|
||||
return this._rpc({
|
||||
model: options.model,
|
||||
method: 'unlink',
|
||||
args: options.args,
|
||||
})
|
||||
.then(this._reload.bind(this, {activity: true}));
|
||||
},
|
||||
/**
|
||||
* Called when marking an activity as done from the Chatter.
|
||||
*
|
||||
* It lets the current user write a feedback in a popup menu.
|
||||
* After writing the feedback and confirm mark as done
|
||||
* is sent, it marks this activity as done for good with the feedback linked
|
||||
* to it.
|
||||
*
|
||||
* @private
|
||||
* @param {MouseEvent} ev
|
||||
*/
|
||||
_onMarkActivityDone: function (ev) {
|
||||
ev.preventDefault();
|
||||
var self = this;
|
||||
var $popoverElement = $(ev.currentTarget);
|
||||
var activityID = $popoverElement.data('activity-id');
|
||||
var previousActivityTypeID = $popoverElement.data('previous-activity-type-id');
|
||||
if (!$popoverElement.data('bs.popover')) {
|
||||
$popoverElement.popover({
|
||||
template: $(Popover.Default.template).addClass('o_mail_activity_feedback')[0].outerHTML, // Ugly but cannot find another way
|
||||
container: $popoverElement.parent(), // FIXME Ugly and should probably be in the body as by default but form view should handle destroying popovers
|
||||
title : _t("Feedback"),
|
||||
html: true,
|
||||
trigger:'click',
|
||||
content : function () {
|
||||
var $popover = $(QWeb.render('mail.activity_feedback_form', { 'previous_activity_type_id': previousActivityTypeID }));
|
||||
$popover.find('#activity_feedback').val(self._draftFeedback[activityID]);
|
||||
$popover.on('click', '.o_activity_popover_done', function () {
|
||||
self._markActivityDone({
|
||||
activityID: activityID,
|
||||
feedback: _.escape($popover.find('#activity_feedback').val()),
|
||||
});
|
||||
});
|
||||
$popover.on('click', '.o_activity_popover_done_next', function () {
|
||||
self._markActivityDoneAndScheduleNext({
|
||||
activityID: activityID,
|
||||
feedback: _.escape($popover.find('#activity_feedback').val()),
|
||||
});
|
||||
});
|
||||
$popover.on('click', '.o_activity_popover_discard', function () {
|
||||
$popoverElement.popover('hide');
|
||||
});
|
||||
return $popover;
|
||||
},
|
||||
}).on('shown.bs.popover', function () {
|
||||
var $popover = $($(this).data("bs.popover").tip);
|
||||
$(".o_mail_activity_feedback.popover").not($popover).popover("hide");
|
||||
$popover.addClass('o_mail_activity_feedback').attr('tabindex', 0);
|
||||
$popover.find('#activity_feedback').focus();
|
||||
$popover.off('focusout');
|
||||
$popover.focusout(function (e) {
|
||||
// outside click of popover hide the popover
|
||||
// e.relatedTarget is the element receiving the focus
|
||||
if (!$popover.is(e.relatedTarget) && !$popover.find(e.relatedTarget).length) {
|
||||
self._draftFeedback[activityID] = $popover.find('#activity_feedback').val();
|
||||
$popover.popover('hide');
|
||||
}
|
||||
});
|
||||
}).popover('show');
|
||||
}
|
||||
},
|
||||
|
||||
});
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Activities Widget for Kanban views ('kanban_activity' widget)
|
||||
// -----------------------------------------------------------------------------
|
||||
var KanbanActivity = AbstractActivityField.extend({
|
||||
var KanbanActivity = BasicActivity.extend({
|
||||
className: 'o_mail_activity_kanban',
|
||||
template: 'mail.KanbanActivity',
|
||||
events: {
|
||||
events:_.extend({}, BasicActivity.prototype.events, {
|
||||
'show.bs.dropdown': '_onDropdownShow',
|
||||
'click .o_schedule_activity': '_onScheduleActivity',
|
||||
'click .o_mark_as_done': '_onMarkActivityDone',
|
||||
'click .o_activity_template_preview': '_onPreviewMailTemplate',
|
||||
'click .o_activity_template_send': '_onSendMailTemplate',
|
||||
},
|
||||
}),
|
||||
|
||||
/**
|
||||
* @override
|
||||
@@ -472,7 +479,6 @@ var KanbanActivity = AbstractActivityField.extend({
|
||||
});
|
||||
this.selection = selection;
|
||||
this._setState(record);
|
||||
this._draftFeedback = {};
|
||||
},
|
||||
|
||||
//------------------------------------------------------------
|
||||
@@ -534,20 +540,6 @@ var KanbanActivity = AbstractActivityField.extend({
|
||||
this.activityState = this.recordData.activity_state;
|
||||
},
|
||||
|
||||
|
||||
//------------------------------------------------------------
|
||||
// Public
|
||||
//------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* @param {integer} previousActivityTypeID
|
||||
* @return {$.Promise}
|
||||
*/
|
||||
scheduleActivity: function (previousActivityTypeID) {
|
||||
var callback = this._reload.bind(this, { activity: true, thread: true });
|
||||
return this._scheduleActivity(false, previousActivityTypeID, callback);
|
||||
},
|
||||
|
||||
//------------------------------------------------------------
|
||||
// Handlers
|
||||
//------------------------------------------------------------
|
||||
@@ -558,113 +550,6 @@ var KanbanActivity = AbstractActivityField.extend({
|
||||
_onDropdownShow: function () {
|
||||
this._renderDropdown();
|
||||
},
|
||||
/**
|
||||
* @private
|
||||
* @param {MouseEvent} ev
|
||||
*/
|
||||
_onMarkActivityDone: function (ev) {
|
||||
ev.stopPropagation();
|
||||
var self = this;
|
||||
var $popoverElement = $(ev.currentTarget);
|
||||
var activityID = $popoverElement.data('activity-id');
|
||||
var previousActivityTypeID = $popoverElement.data('previous-activity-type-id');
|
||||
|
||||
if (!$popoverElement.data('bs.popover')) {
|
||||
$popoverElement.popover({
|
||||
template: $(Popover.Default.template).addClass('o_mail_activity_feedback')[0].outerHTML, // Ugly but cannot find another way
|
||||
container: $popoverElement.parent(), // FIXME Ugly and should probably be in the body as by default but form view should handle destroying popovers
|
||||
title : _t("Feedback"),
|
||||
html: true,
|
||||
trigger:'click',
|
||||
content : function () {
|
||||
var $popover = $(QWeb.render('mail.activity_feedback_form', { 'previous_activity_type_id': previousActivityTypeID }));
|
||||
$popover.find('#activity_feedback').val(self._draftFeedback[activityID]);
|
||||
$popover.on('click', function (ev) {
|
||||
ev.stopPropagation();
|
||||
});
|
||||
$popover.on('click', '.o_activity_popover_done', function (ev) {
|
||||
ev.stopPropagation();
|
||||
self._markActivityDone({
|
||||
activityID: activityID,
|
||||
feedback: _.escape($popover.find('#activity_feedback').val()),
|
||||
});
|
||||
});
|
||||
$popover.on('click', '.o_activity_popover_done_next', function (ev) {
|
||||
ev.stopPropagation();
|
||||
self._markActivityDoneAndScheduleNext({
|
||||
activityID: activityID,
|
||||
feedback: _.escape($popover.find('#activity_feedback').val()),
|
||||
});
|
||||
});
|
||||
$popover.on('click', '.o_activity_popover_discard', function (ev) {
|
||||
ev.stopPropagation();
|
||||
$popoverElement.popover('hide');
|
||||
});
|
||||
return $popover;
|
||||
},
|
||||
}).on('shown.bs.popover', function () {
|
||||
var $popover = $($(this).data("bs.popover").tip);
|
||||
$(".o_mail_activity_feedback.popover").not($popover).popover("hide");
|
||||
$popover.addClass('o_mail_activity_feedback').attr('tabindex', 0);
|
||||
$popover.find('#activity_feedback').focus();
|
||||
$popover.off('focusout');
|
||||
$popover.focusout(function (e) {
|
||||
// outside click of popover hide the popover
|
||||
// e.relatedTarget is the element receiving the focus
|
||||
if (!$popover.is(e.relatedTarget) && !$popover.find(e.relatedTarget).length) {
|
||||
self._draftFeedback[activityID] = $popover.find('#activity_feedback').val();
|
||||
$popover.popover('hide');
|
||||
}
|
||||
});
|
||||
}).popover('show');
|
||||
}
|
||||
},
|
||||
/**
|
||||
* @private
|
||||
* @param {MouseEvent} ev
|
||||
* @returns {$.Promise}
|
||||
*/
|
||||
_onScheduleActivity: function (ev) {
|
||||
var activityID = $(ev.currentTarget).data('activity-id') || false;
|
||||
return this._scheduleActivity(activityID, false, this._reload.bind(this));
|
||||
},
|
||||
/**
|
||||
* @private
|
||||
* @param {MouseEvent} ev
|
||||
*/
|
||||
_onPreviewMailTemplate: function (ev) {
|
||||
ev.stopPropagation();
|
||||
var templateID = $(ev.target).data('template-id');
|
||||
var action = {
|
||||
name: _t('Compose Email'),
|
||||
type: 'ir.actions.act_window',
|
||||
res_model: 'mail.compose.message',
|
||||
views: [[false, 'form']],
|
||||
target: 'new',
|
||||
context: {
|
||||
default_res_id: this.res_id,
|
||||
default_model: this.model,
|
||||
default_use_template: true,
|
||||
default_template_id: templateID,
|
||||
force_email: true,
|
||||
},
|
||||
};
|
||||
return this.do_action(action, { on_close: function () {} });
|
||||
},
|
||||
/**
|
||||
* @private
|
||||
* @param {MouseEvent} ev
|
||||
*/
|
||||
_onSendMailTemplate: function (ev) {
|
||||
ev.stopPropagation();
|
||||
var templateID = $(ev.target).data('template-id');
|
||||
return this._rpc({
|
||||
model: this.model,
|
||||
method: 'activity_send_mail',
|
||||
args: [[this.res_id], templateID],
|
||||
})
|
||||
.then(this._reload.bind(this, {activity: true, thread: true, followers: true}));
|
||||
},
|
||||
});
|
||||
|
||||
field_registry
|
||||
|
||||
@@ -440,7 +440,7 @@ var Chatter = Widget.extend({
|
||||
* @private
|
||||
*/
|
||||
_onScheduleActivity: function () {
|
||||
this.fields.activity.scheduleActivity(false);
|
||||
this.fields.activity.scheduleActivity();
|
||||
},
|
||||
});
|
||||
|
||||
|
||||
@@ -200,7 +200,7 @@
|
||||
background-color: $o-brand-lightsecondary;
|
||||
}
|
||||
|
||||
&.o_schedule_activity {
|
||||
&.o_edit_activity {
|
||||
padding: 8px 10px 8px 0px;
|
||||
vertical-align: middle;
|
||||
&:hover {
|
||||
|
||||
@@ -75,13 +75,13 @@
|
||||
</div>
|
||||
</t>
|
||||
<div class="o_thread_message_tools btn-group">
|
||||
<a role="button" href="#" class="btn btn-link btn-success text-muted o_activity_done o_activity_link mr8" t-att-data-activity-id="activity.id" t-att-data-previous-activity-type-id="activity.activity_type_id[0]" data-toggle="popover">
|
||||
<span class="o_mark_as_done" data-toggle="popover" t-att-data-activity-id="activity.id" t-att-data-previous-activity-type-id="activity.activity_type_id[0]"><a role="button" href="#" class="btn btn-link btn-success text-muted o_activity_link mr8">
|
||||
<i class="fa fa-check"/> Mark Done
|
||||
</a>
|
||||
<a role="button" href="#" class="btn btn-link btn-secondary text-muted o_activity_edit o_activity_link" t-att-data-activity-id="activity.id">
|
||||
</a></span>
|
||||
<a role="button" href="#" class="btn btn-link btn-secondary text-muted o_edit_activity o_activity_link" t-att-data-activity-id="activity.id">
|
||||
<i class="fa fa-pencil"/> Edit
|
||||
</a>
|
||||
<a role="button" href="#" class="btn btn-link btn-danger text-muted o_activity_unlink o_activity_link" t-att-data-activity-id="activity.id">
|
||||
<a role="button" href="#" class="btn btn-link btn-danger text-muted o_unlink_activity o_activity_link" t-att-data-activity-id="activity.id">
|
||||
<i class="fa fa-times"/> Cancel
|
||||
</a>
|
||||
</div>
|
||||
|
||||
@@ -29,7 +29,7 @@
|
||||
<t t-esc="selection[key]" /> (<t t-esc="logs.length"/>)
|
||||
</strong>
|
||||
</li>
|
||||
<li t-foreach="logs" t-as="log" t-att-data-activity-id="log.id" class="nav-item o_schedule_activity" role="menuitem">
|
||||
<li t-foreach="logs" t-as="log" t-att-data-activity-id="log.id" class="nav-item o_edit_activity" role="menuitem">
|
||||
<div class="o_activity_title float-left">
|
||||
<span t-attf-class="fa #{log.icon} fa-fw" role="img" aria-label="Log" title="Log"/>
|
||||
<strong>
|
||||
|
||||
@@ -0,0 +1,316 @@
|
||||
odoo.define('mail.activity_view_tests', function (require) {
|
||||
'use strict';
|
||||
|
||||
var ActivityView = require('mail.ActivityView');
|
||||
var testUtils = require('web.test_utils');
|
||||
|
||||
var createView = testUtils.createView;
|
||||
var ACTIVITY_DATA = {
|
||||
"grouped_activities":{
|
||||
"13":{
|
||||
"1":{
|
||||
"count":1,
|
||||
"state":"planned",
|
||||
"o_closest_deadline":"2018-08-16",
|
||||
"ids":[
|
||||
1
|
||||
]
|
||||
}
|
||||
},
|
||||
"30":{
|
||||
"1":{
|
||||
"count":1,
|
||||
"state":"today",
|
||||
"o_closest_deadline":"2018-08-16",
|
||||
"ids":[
|
||||
2
|
||||
]
|
||||
},
|
||||
"2":{
|
||||
"count":2,
|
||||
"state":"overdue",
|
||||
"o_closest_deadline":"2018-09-16",
|
||||
"ids":[
|
||||
3
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
"activity_types":[
|
||||
[
|
||||
1,
|
||||
"Email",
|
||||
[
|
||||
{
|
||||
"id":9,
|
||||
"name":"Task: Rating Request"
|
||||
},
|
||||
{
|
||||
"id":8,
|
||||
"name":"Task: Reception Acknowledgment"
|
||||
}
|
||||
]
|
||||
],
|
||||
[
|
||||
2,
|
||||
"Call",
|
||||
[]
|
||||
]
|
||||
],
|
||||
"model":"task",
|
||||
"res_ids":[
|
||||
[
|
||||
30,
|
||||
"Office planning"
|
||||
],
|
||||
[
|
||||
13,
|
||||
"Meeting Room Furnitures"
|
||||
]
|
||||
]
|
||||
};
|
||||
|
||||
QUnit.module('mail', {}, function () {
|
||||
QUnit.module('activity view', {
|
||||
beforeEach: function () {
|
||||
this.data = {
|
||||
task: {
|
||||
fields: {
|
||||
id: {string: 'ID', type: 'integer'},
|
||||
},
|
||||
records: [
|
||||
{id: 13},
|
||||
{id: 30},
|
||||
]
|
||||
},
|
||||
partner: {
|
||||
fields: {
|
||||
display_name: { string: "Displayed name", type: "char" },
|
||||
},
|
||||
records: [{
|
||||
id: 2,
|
||||
display_name: "first partner",
|
||||
}]
|
||||
},
|
||||
'mail.activity': {
|
||||
fields: {
|
||||
activity_type_id: { string: "Activity type", type: "many2one", relation: "mail.activity.type" },
|
||||
display_name: { string: "Display name", type: "char" },
|
||||
date_deadline: { string: "Due Date", type: "date" },
|
||||
state: {
|
||||
string: 'State',
|
||||
type: 'selection',
|
||||
selection: [['overdue', 'Overdue'], ['today', 'Today'], ['planned', 'Planned']],
|
||||
},
|
||||
mail_template_ids: { string: "Mail templates", type: "many2many", relation: "mail.template" },
|
||||
user_id: { string: "Assigned to", type: "many2one", relation: 'partner' },
|
||||
},
|
||||
records:[
|
||||
{
|
||||
id: 1,
|
||||
display_name: "An activity",
|
||||
date_deadline: moment().add(3, "days").format("YYYY-MM-DD"), // now
|
||||
state: "planned",
|
||||
activity_type_id: 1,
|
||||
mail_template_ids: [8, 9],
|
||||
user_id:2,
|
||||
},{
|
||||
id: 2,
|
||||
display_name: "An activity",
|
||||
date_deadline: moment().format("YYYY-MM-DD"), // now
|
||||
state: "today",
|
||||
activity_type_id: 1,
|
||||
mail_template_ids: [8, 9],
|
||||
user_id:2,
|
||||
},{
|
||||
id: 3,
|
||||
display_name: "An activity",
|
||||
date_deadline: moment().subtract(2, "days").format("YYYY-MM-DD"), // now
|
||||
state: "overdue",
|
||||
activity_type_id: 2,
|
||||
mail_template_ids: [],
|
||||
user_id:2,
|
||||
}
|
||||
],
|
||||
},
|
||||
'mail.template': {
|
||||
fields: {
|
||||
name: { string: "Name", type: "char" },
|
||||
},
|
||||
records: [
|
||||
{ id: 8, name: "Template1" },
|
||||
{ id: 9, name: "Template2" },
|
||||
],
|
||||
},
|
||||
'mail.activity.type': {
|
||||
fields: {
|
||||
name: { string: "Name", type: "char" },
|
||||
},
|
||||
records: [
|
||||
{ id: 1, name: "Email" },
|
||||
{ id: 2, name: "Call" },
|
||||
],
|
||||
},
|
||||
};
|
||||
}
|
||||
});
|
||||
|
||||
QUnit.test('activity view: simple activity rendering', function (assert) {
|
||||
assert.expect(7);
|
||||
var activity = createView({
|
||||
View: ActivityView,
|
||||
model: 'task',
|
||||
data: this.data,
|
||||
arch: '<activity string="Task"/>',
|
||||
mockRPC: function(route, args) {
|
||||
if (args.method === 'get_activity_data') {
|
||||
return $.when(ACTIVITY_DATA);
|
||||
}
|
||||
return this._super(route, args);
|
||||
}
|
||||
});
|
||||
|
||||
assert.strictEqual(activity.$('table').length, 1,
|
||||
'should have a table');
|
||||
assert.ok(activity.$('table thead tr:first th:nth-child(2) span:first:contains(Email)').length,
|
||||
'should contain "Email" in header of first column');
|
||||
assert.ok(activity.$('table thead tr:first th:nth-child(3) span:first:contains(Call)').length,
|
||||
'should contain "Call" in header of second column');
|
||||
assert.ok(activity.$('table tbody tr:first td:first:contains(Office planning)').length,
|
||||
'should contain "Office planning" in first colum of first row');
|
||||
assert.ok(activity.$('table tbody tr:nth-child(2) td:first:contains(Meeting Room Furnitures)').length,
|
||||
'should contain "Meeting Room Furnitures" in first colum of second row');
|
||||
assert.ok(activity.$('table tbody tr:first td:nth-child(2).today .o_closest_deadline:contains(Aug 16)').length,
|
||||
'should contain an activity for today with date Aug 16 in second cell of first line');
|
||||
assert.ok(activity.$('table tbody tr:nth-child(2) td:nth-child(2).planned .o_closest_deadline:contains(Aug 16)').length,
|
||||
'should contain a planned activity with date Aug 16 in second cell of second line');
|
||||
activity.destroy();
|
||||
});
|
||||
|
||||
QUnit.test('activity view: batch send mail on activity', function (assert) {
|
||||
assert.expect(6);
|
||||
var activity = createView({
|
||||
View: ActivityView,
|
||||
model: 'task',
|
||||
data: this.data,
|
||||
arch: '<activity string="Task"/>',
|
||||
mockRPC: function(route, args) {
|
||||
if (args.method === 'activity_send_mail'){
|
||||
assert.step(args.args);
|
||||
return $.when();
|
||||
}
|
||||
if (args.method === 'get_activity_data') {
|
||||
return $.when(ACTIVITY_DATA);
|
||||
}
|
||||
return this._super(route, args);
|
||||
},
|
||||
});
|
||||
assert.notOk(activity.$('table thead tr:first th:nth-child(2) span:nth-child(2) .dropdown-menu.show').length,
|
||||
'dropdown shouldn\'t be displayed');
|
||||
|
||||
activity.$('table thead tr:first th:nth-child(2) span:nth-child(2) i.fa-ellipsis-v').click();
|
||||
assert.ok(activity.$('table thead tr:first th:nth-child(2) span:nth-child(2) .dropdown-menu.show').length,
|
||||
'dropdown should have appeared');
|
||||
|
||||
activity.$('table thead tr:first th:nth-child(2) span:nth-child(2) .dropdown-menu.show .o_send_mail_template:first:contains(Task: Rating Request)').click();
|
||||
assert.notOk(activity.$('table thead tr:first th:nth-child(2) span:nth-child(2) .dropdown-menu.show').length,
|
||||
'dropdown shouldn\'t be displayed');
|
||||
|
||||
activity.$('table thead tr:first th:nth-child(2) span:nth-child(2) i.fa-ellipsis-v').click();
|
||||
activity.$('table thead tr:first th:nth-child(2) span:nth-child(2) .dropdown-menu.show .o_send_mail_template:nth-child(2):contains(Task: Reception Acknowledgment)').click();
|
||||
assert.verifySteps([
|
||||
[[13, 30], 9], //send mail template 9 on tasl 13 and 30
|
||||
[[13, 30], 8] //send mail template 8 on tasl 13 and 30
|
||||
]);
|
||||
|
||||
activity.destroy();
|
||||
});
|
||||
|
||||
QUnit.test('activity view: activity widget', function (assert) {
|
||||
assert.expect(16);
|
||||
var activity = createView({
|
||||
View: ActivityView,
|
||||
model: 'task',
|
||||
data: this.data,
|
||||
arch: '<activity string="Task"/>',
|
||||
mockRPC: function(route, args) {
|
||||
if (args.method === 'activity_send_mail'){
|
||||
assert.deepEqual([[30],8],args.args, "Should send template 8 on record 30");
|
||||
assert.step('activity_send_mail');
|
||||
return $.when();
|
||||
}
|
||||
if (args.method === 'action_done_schedule_next'){
|
||||
assert.deepEqual([[3]],args.args, "Should execute action_done_schedule_next on activity 3 only ");
|
||||
assert.equal(args.kwargs.feedback, "feedback2");
|
||||
assert.step('action_done_schedule_next');
|
||||
return $.when({serverGeneratedAction: true});
|
||||
}
|
||||
if (args.method === 'get_activity_data') {
|
||||
return $.when(ACTIVITY_DATA);
|
||||
}
|
||||
return this._super(route, args);
|
||||
},
|
||||
intercepts: {
|
||||
do_action: function (ev) {
|
||||
var action = ev.data.action;
|
||||
if (action.serverGeneratedAction) {
|
||||
assert.step('serverGeneratedAction');
|
||||
} else if (action.res_model === 'mail.compose.message') {
|
||||
assert.deepEqual({
|
||||
default_model: "task",
|
||||
default_res_id: 30,
|
||||
default_template_id: 8,
|
||||
default_use_template: true,
|
||||
force_email: true
|
||||
}, action.context);
|
||||
assert.step("do_action_compose");
|
||||
} else if (action.res_model === 'mail.activity') {
|
||||
assert.deepEqual({
|
||||
"default_res_id": 30,
|
||||
"default_res_model": "task"
|
||||
}, action.context);
|
||||
assert.step("do_action_activity");
|
||||
} else {
|
||||
assert.step("Unexpected action");
|
||||
}
|
||||
},
|
||||
}
|
||||
});
|
||||
var today = activity.$('table tbody tr:first td:nth-child(2).today');
|
||||
var dropdown = today.find('.dropdown-menu.o_activity');
|
||||
|
||||
today.find('.o_closest_deadline').click();
|
||||
assert.ok(dropdown.hasClass('show'), "dropdown should be displayed");
|
||||
assert.ok(dropdown.find('.o_activity_color_today:contains(Today)').length, "Title should be today");
|
||||
assert.ok(dropdown.find('.o_activity_title div div div:first span:contains(template8)').length,
|
||||
"template8 should be available");
|
||||
assert.ok(dropdown.find('.o_activity_title div div div:nth-child(2) span:contains(template9)').length,
|
||||
"template9 should be available");
|
||||
|
||||
dropdown.find('.o_activity_title div div div:first .o_activity_template_preview').click();
|
||||
dropdown.find('.o_activity_title div div div:first .o_activity_template_send').click();
|
||||
var overdue = activity.$('table tbody tr:first td:nth-child(3).overdue');
|
||||
overdue.find('.o_closest_deadline').click();
|
||||
dropdown = overdue.find('.dropdown-menu.o_activity');
|
||||
assert.notOk(dropdown.find('.o_activity_title div div div:first span').length,
|
||||
"No template should be available");
|
||||
|
||||
dropdown.find('.o_schedule_activity').click();
|
||||
overdue.find('.o_closest_deadline').click();
|
||||
dropdown.find('.o_mark_as_done').click();
|
||||
dropdown.find('#activity_feedback').val("feedback2");
|
||||
|
||||
dropdown.find('.o_activity_popover_done_next').click();
|
||||
assert.verifySteps([
|
||||
"do_action_compose",
|
||||
"activity_send_mail",
|
||||
"do_action_activity",
|
||||
"action_done_schedule_next",
|
||||
"serverGeneratedAction"
|
||||
]);
|
||||
|
||||
activity.destroy();
|
||||
});
|
||||
|
||||
});
|
||||
});
|
||||
@@ -1240,7 +1240,7 @@ QUnit.test('form activity widget: schedule next activity', function (assert) {
|
||||
},
|
||||
});
|
||||
//Schedule next activity
|
||||
form.$('.o_mail_activity .o_activity_done[data-activity-id=1]').click();
|
||||
form.$('.o_mail_activity .o_mark_as_done[data-activity-id=1]').click();
|
||||
assert.strictEqual(form.$('.o_mail_activity_feedback.popover').length, 1,
|
||||
"a feedback popover should be visible");
|
||||
$('.o_mail_activity_feedback.popover textarea').val('everything is ok'); // write a feedback
|
||||
@@ -1445,16 +1445,16 @@ QUnit.test('form activity widget: mark as done and remove', function (assert) {
|
||||
"there should be two activities");
|
||||
|
||||
// remove activity 1
|
||||
form.$('.o_mail_activity .o_activity_unlink[data-activity-id=1]').click();
|
||||
form.$('.o_mail_activity .o_unlink_activity[data-activity-id=1]').click();
|
||||
assert.strictEqual(form.$('.o_mail_activity .o_thread_message').length, 1,
|
||||
"there should be one remaining activity");
|
||||
assert.ok(!form.$('.o_mail_activity .o_activity_unlink[data-activity-id=1]').length,
|
||||
assert.ok(!form.$('.o_mail_activity .o_unlink_activity[data-activity-id=1]').length,
|
||||
"activity 1 should have been removed");
|
||||
|
||||
// mark activity done
|
||||
assert.ok(!form.$('.o_mail_thread .o_thread_message').length,
|
||||
"there should be no chatter message");
|
||||
form.$('.o_mail_activity .o_activity_done[data-activity-id=2]').click();
|
||||
form.$('.o_mail_activity .o_mark_as_done[data-activity-id=2]').click();
|
||||
assert.strictEqual(form.$('.o_mail_activity_feedback.popover').length, 1,
|
||||
"a feedback popover should be visible");
|
||||
$('.o_mail_activity_feedback.popover textarea').val('everything is ok'); // write a feedback
|
||||
|
||||
@@ -168,7 +168,16 @@ MockServer.include({
|
||||
return $.when(this._mockMessageFormat(args));
|
||||
}
|
||||
if (args.method === 'activity_format') {
|
||||
return $.when(this._mockRead(args.model, args.args, args.kwargs));
|
||||
var res = this._mockRead(args.model, args.args, args.kwargs);
|
||||
res = res.map(function(record) {
|
||||
if (record.mail_template_ids) {
|
||||
record.mail_template_ids = record.mail_template_ids.map(function(template_id) {
|
||||
return {id:template_id, name:"template"+template_id};
|
||||
});
|
||||
}
|
||||
return record;
|
||||
});
|
||||
return $.when(res);
|
||||
}
|
||||
if (args.method === 'set_message_done') {
|
||||
return $.when();
|
||||
|
||||
@@ -113,6 +113,8 @@
|
||||
<script type="text/javascript" src="/mail/static/tests/models/cc_throttle_function_tests.js"></script>
|
||||
<script type="text/javascript" src="/mail/static/tests/models/timer_tests.js"></script>
|
||||
<script type="text/javascript" src="/mail/static/tests/models/timers_tests.js"></script>
|
||||
<!-- activity view -->
|
||||
<script type="text/javascript" src="/mail/static/tests/activity_tests.js"></script>
|
||||
</xpath>
|
||||
</template>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user