[IMP] mail: add more powerfull delays on activity.

It was possible to define a delay in days on activity type
to reschedule next activity. It is now possible to specify a unit
(days, weeks, months) and a starting point for the delay
(as before, from the moment when the new activity is scheduled,
but also after the deadline of the previous activity).

We realy need to have all javascript action triggering a done
and schedule next to call the python corresponding method on
activities. A part of the work have been there but some
cleaning could still be done in activity.js.

Task: #1870662
PR: #26272
This commit is contained in:
XavierDo
2018-08-10 15:20:37 +02:00
parent f2b8b38fb4
commit 83fc5dc03c
8 changed files with 62 additions and 27 deletions
+3 -3
View File
@@ -4,18 +4,18 @@
<field name="name">Follow-up Quote</field>
<field name="icon">fa-file-text-o</field>
<field name="res_model_id" ref="crm.model_crm_lead"/>
<field name="days">30</field>
<field name="delay_count">30</field>
</record>
<record id="mail_activity_demo_make_quote" model="mail.activity.type">
<field name="name">Make Quote</field>
<field name="icon">fa-file-text-o</field>
<field name="res_model_id" ref="crm.model_crm_lead"/>
<field name="days">15</field>
<field name="delay_count">15</field>
</record>
<record id="mail_activity_demo_call_demo" model="mail.activity.type">
<field name="name">Call for Demo</field>
<field name="icon">fa-phone</field>
<field name="res_model_id" ref="crm.model_crm_lead"/>
<field name="days">10</field>
<field name="delay_count">10</field>
</record>
</odoo>
+3 -3
View File
@@ -15,19 +15,19 @@ class TestCrmMailActivity(TestCrmCases):
ActivityType = self.env['mail.activity.type']
self.activity3 = ActivityType.create({
'name': 'Celebrate the sale',
'days': 3,
'delay_count': 3,
'summary': 'ACT 3 : Beers for everyone because I am a good salesman !',
'res_model_id': lead_model_id,
})
self.activity2 = ActivityType.create({
'name': 'Call for Demo',
'days': 6,
'delay_count': 6,
'summary': 'ACT 2 : I want to show you my ERP !',
'res_model_id': lead_model_id,
})
self.activity1 = ActivityType.create({
'name': 'Initial Contact',
'days': 5,
'delay_count': 5,
'summary': 'ACT 1 : Presentation, barbecue, ... ',
'res_model_id': lead_model_id,
})
+2 -2
View File
@@ -9,7 +9,7 @@
<record id="mail_activity_data_call" model="mail.activity.type">
<field name="name">Call</field>
<field name="icon">fa-phone</field>
<field name="days">2</field>
<field name="delay_count">2</field>
<field name="sequence">6</field>
</record>
<record id="mail_activity_data_meeting" model="mail.activity.type">
@@ -20,7 +20,7 @@
<record id="mail_activity_data_todo" model="mail.activity.type">
<field name="name">To Do</field>
<field name="icon">fa-tasks</field>
<field name="days">5</field>
<field name="delay_count">5</field>
<field name="sequence">12</field>
</record>
</data>
+28 -6
View File
@@ -1,7 +1,9 @@
# -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.
from datetime import date, datetime, timedelta
from collections import defaultdict
from datetime import date, datetime
from dateutil.relativedelta import relativedelta
import pytz
from odoo import api, exceptions, fields, models, _
@@ -29,9 +31,16 @@ class MailActivityType(models.Model):
summary = fields.Char('Summary', translate=True)
sequence = fields.Integer('Sequence', default=10)
active = fields.Boolean(default=True)
days = fields.Integer(
'Planned in', default=0,
help='Number of days before executing the action. It allows to plan the action deadline.')
delay_count = fields.Integer(
'After', default=0, oldname='days',
help='Number of days/week/month before executing the action. It allows to plan the action deadline.')
delay_unit = fields.Selection([
('days', 'days'),
('weeks', 'weeks'),
('months', 'months')], string="Delay units", help="Unit of delay", required=True, default='days')
delay_from = fields.Selection([
('current_date', 'after validation date'),
('previous_activity', 'after previous activity deadline')], string="Delay Type", help="Type of delay", required=True, default='previous_activity')
icon = fields.Char('Icon', help="Font awesome icon e.g. fa-tasks")
decoration_type = fields.Selection([
('warning', 'Alert'),
@@ -42,6 +51,8 @@ class MailActivityType(models.Model):
domain=['&', ('is_mail_thread', '=', True), ('transient', '=', False)],
help='Specify a model if the activity should be specific to a model'
' and not available when managing activities for other models.')
default_next_type_id = fields.Many2one('mail.activity.type', 'Default Next Activity',
domain="['|', ('res_model_id', '=', False), ('res_model_id', '=', res_model_id)]")
next_type_ids = fields.Many2many(
'mail.activity.type', 'mail_activity_rel', 'activity_id', 'recommended_id',
domain="['|', ('res_model_id', '=', False), ('res_model_id', '=', res_model_id)]",
@@ -141,6 +152,13 @@ class MailActivity(models.Model):
def _compute_has_recommended_activities(self):
for record in self:
record.has_recommended_activities = bool(record.previous_activity_type_id.next_type_ids)
@api.multi
@api.onchange('previous_activity_type_id')
def _onchange_previous_activity_type_id(self):
for record in self:
if record.previous_activity_type_id.default_next_type_id:
record.activity_type_id = record.previous_activity_type_id.default_next_type_id
@api.depends('res_model', 'res_id')
def _compute_res_name(self):
@@ -174,7 +192,10 @@ class MailActivity(models.Model):
self.summary = self.activity_type_id.summary
# Date.context_today is correct because date_deadline is a Date and is meant to be
# expressed in user TZ
self.date_deadline = fields.Date.context_today(self) + timedelta(days=self.activity_type_id.days)
base = fields.Date.context_today(self)
if self.activity_type_id.delay_from == 'previous_activity' and 'activity_previous_deadline' in self.env.context:
base = fields.Date.from_string(self.env.context.get('activity_previous_deadline'))
self.date_deadline = base + relativedelta(**{self.activity_type_id.delay_unit: self.activity_type_id.delay_count})
@api.onchange('recommended_activity_type_id')
def _onchange_recommended_activity_type_id(self):
@@ -336,10 +357,11 @@ class MailActivity(models.Model):
return message.ids and message.ids[0] or False
@api.multi
def action_done_schedule_next(self):
def action_done_schedule_next(self, feedback=False):
wizard_ctx = dict(
self.env.context,
default_previous_activity_type_id=self.activity_type_id.id,
activity_previous_deadline=self.date_deadline,
default_res_id=self.res_id,
default_res_model=self.res_model,
)
+16 -7
View File
@@ -132,16 +132,27 @@ var AbstractActivityField = AbstractField.extend({
* @private
* @param {Object} params
* @param {integer} params.activityID
* @param {integer} params.activityTypeID
* @param {string} params.feedback
*/
_markActivityDoneAndScheduleNext: function(params) {
var activityID = params.activityID;
var activityTypeID = params.activityTypeID;
var feedback = params.feedback;
this._sendActivityFeedback(activityID, feedback)
.then(this.scheduleActivity.bind(this, activityTypeID));
var self = this;
this._rpc({
model: 'mail.activity',
method: 'action_done_schedule_next',
args: [[activityID]],
kwargs: {feedback: feedback},
context: this.record.getContext(),
}).then(
function(rslt_action) {
self.do_action(rslt_action, {
on_close: function () {
self.trigger_up('reload');
},
});
}
);
},
/**
* @private
@@ -410,7 +421,6 @@ var Activity = AbstractActivityField.extend({
$popover.on('click', '.o_activity_popover_done_next', function () {
self._markActivityDoneAndScheduleNext({
activityID: activityID,
activityTypeID: $popoverElement.data('previous-activity-type-id'),
feedback: _.escape($popover.find('#activity_feedback').val()),
});
});
@@ -583,7 +593,6 @@ var KanbanActivity = AbstractActivityField.extend({
ev.stopPropagation();
self._markActivityDoneAndScheduleNext({
activityID: activityID,
activityTypeID: $popoverElement.data('previous-activity-type-id'),
feedback: _.escape($popover.find('#activity_feedback').val()),
});
});
+8 -4
View File
@@ -24,15 +24,17 @@
<field name="summary"/>
<field name="icon" groups="base.group_no_one"/>
<field name="decoration_type" groups="base.group_no_one"/>
<label for="days"/>
<label for="delay_count"/>
<div>
<field name="days" class="oe_inline"/>
<span class="oe_inline ml4">days</span>
<field name="delay_count" class="oe_inline"/>&amp;nbsp;
<field name="delay_unit" class="oe_inline"/>&amp;nbsp;
<field name="delay_from" class="oe_inline"/>
</div>
</group>
<group>
<field name="next_type_ids" widget="many2many_tags"
context="{'default_res_model_id': res_model_id}"/>
<field name="default_next_type_id" context="{'default_res_model_id': res_model_id}"/>
<field name="mail_template_ids" widget="many2many_tags"
domain="[('model_id', '=', res_model_id)]"
attrs="{'invisible': [('res_model_id', '=', False)]}"
@@ -64,7 +66,9 @@
<field name="sequence" widget="handle"/>
<field name="name"/>
<field name="summary"/>
<field name="days" string="Planned in (days)"/>
<field name="delay_count" string="Planned in"/>
<field name="delay_unit" string="Unit"/>
<field name="delay_from" string="Type"/>
<field name="res_model_id" groups="base.group_no_one"/>
<field name="icon" groups="base.group_no_one"/>
</tree>
+1 -1
View File
@@ -5,7 +5,7 @@
<field name="name">Reminder</field>
<field name="category">reminder</field>
<field name="icon">fa-tasks</field>
<field name="days">0</field>
<field name="delay_count">0</field>
<field name="sequence">20</field>
</record>
</data>
@@ -9,7 +9,7 @@
<field name="category">default</field>
<field name="res_model_id" ref="stock.model_stock_production_lot"/>
<field name="icon">fa-tasks</field>
<field name="days">0</field>
<field name="delay_count">0</field>
</record>
</odoo>