From 83fc5dc03ce92df9b920386f9215cdc5504c3be1 Mon Sep 17 00:00:00 2001 From: XavierDo Date: Wed, 1 Aug 2018 12:13:46 +0200 Subject: [PATCH] [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 --- addons/crm/data/mail_activity_demo.xml | 6 ++-- addons/crm/tests/test_crm_activity.py | 6 ++-- addons/mail/data/mail_activity_data.xml | 4 +-- addons/mail/models/mail_activity.py | 34 +++++++++++++++---- addons/mail/static/src/js/activity.js | 23 +++++++++---- addons/mail/views/mail_activity_views.xml | 12 ++++--- addons/note/data/mail_activity_data.xml | 2 +- .../data/product_expiry_data.xml | 2 +- 8 files changed, 62 insertions(+), 27 deletions(-) diff --git a/addons/crm/data/mail_activity_demo.xml b/addons/crm/data/mail_activity_demo.xml index d18dd3a0e0c..4dad17022ff 100644 --- a/addons/crm/data/mail_activity_demo.xml +++ b/addons/crm/data/mail_activity_demo.xml @@ -4,18 +4,18 @@ Follow-up Quote fa-file-text-o - 30 + 30 Make Quote fa-file-text-o - 15 + 15 Call for Demo fa-phone - 10 + 10 diff --git a/addons/crm/tests/test_crm_activity.py b/addons/crm/tests/test_crm_activity.py index d3d847612d4..3bb9bae9a48 100644 --- a/addons/crm/tests/test_crm_activity.py +++ b/addons/crm/tests/test_crm_activity.py @@ -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, }) diff --git a/addons/mail/data/mail_activity_data.xml b/addons/mail/data/mail_activity_data.xml index f8f1f8b09ca..7309c991b6c 100644 --- a/addons/mail/data/mail_activity_data.xml +++ b/addons/mail/data/mail_activity_data.xml @@ -9,7 +9,7 @@ Call fa-phone - 2 + 2 6 @@ -20,7 +20,7 @@ To Do fa-tasks - 5 + 5 12 diff --git a/addons/mail/models/mail_activity.py b/addons/mail/models/mail_activity.py index dcb60831ef2..fda0b5f88de 100644 --- a/addons/mail/models/mail_activity.py +++ b/addons/mail/models/mail_activity.py @@ -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, ) diff --git a/addons/mail/static/src/js/activity.js b/addons/mail/static/src/js/activity.js index acd15cbef20..dbff89c76db 100644 --- a/addons/mail/static/src/js/activity.js +++ b/addons/mail/static/src/js/activity.js @@ -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()), }); }); diff --git a/addons/mail/views/mail_activity_views.xml b/addons/mail/views/mail_activity_views.xml index 6284a4e3d89..7b92502934f 100644 --- a/addons/mail/views/mail_activity_views.xml +++ b/addons/mail/views/mail_activity_views.xml @@ -24,15 +24,17 @@ - diff --git a/addons/product_expiry/data/product_expiry_data.xml b/addons/product_expiry/data/product_expiry_data.xml index ca621cef17e..f0effeaaa77 100644 --- a/addons/product_expiry/data/product_expiry_data.xml +++ b/addons/product_expiry/data/product_expiry_data.xml @@ -9,7 +9,7 @@ default fa-tasks - 0 + 0