[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:
XavierDo
2018-08-20 16:00:09 +02:00
committed by RomainLibert
co-authored by RomainLibert
parent c90ff2afd8
commit 0be33db68a
10 changed files with 529 additions and 317 deletions
+1 -1
View File
@@ -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,
+189 -304
View File
@@ -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
+1 -1
View File
@@ -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 {
+4 -4
View File
@@ -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>
+316
View File
@@ -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();
});
});
});
+4 -4
View File
@@ -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();
+2
View File
@@ -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>