From 730998142678dc753fc77fb95df1643d0ccb7526 Mon Sep 17 00:00:00 2001 From: Pierre Paridans Date: Tue, 7 Aug 2018 09:39:13 +0200 Subject: [PATCH] [IMP] mail: Add 'Next Activity' in server action type Purpose ======= As a server action could add followers on a record, here the goal is to be able to add a next activity on a record. Specification ============= Based on the configured trigger, we can add a next activity on a record by specifying : - The activity type - A summary - A note - A due date in x days/weeks/months - A responsible --- addons/mail/models/ir_actions.py | 58 ++++++++++++++++++++++- addons/mail/views/ir_actions_views.xml | 21 ++++++++ addons/test_mail/tests/test_ir_actions.py | 13 +++++ 3 files changed, 91 insertions(+), 1 deletion(-) diff --git a/addons/mail/models/ir_actions.py b/addons/mail/models/ir_actions.py index bd4b03f3a4c..16abdfeaf8e 100644 --- a/addons/mail/models/ir_actions.py +++ b/addons/mail/models/ir_actions.py @@ -1,6 +1,9 @@ # -*- coding: utf-8 -*- # Part of Odoo. See LICENSE file for full copyright and licensing details. +from datetime import date +from dateutil.relativedelta import relativedelta + from odoo import _, api, fields, models from odoo.exceptions import UserError, ValidationError @@ -12,7 +15,8 @@ class ServerActions(models.Model): state = fields.Selection(selection_add=[ ('email', 'Send Email'), - ('followers', 'Add Followers') + ('followers', 'Add Followers'), + ('next_activity', 'Create Next Activity'), ]) # Followers partner_ids = fields.Many2many('res.partner', string='Add Followers') @@ -22,6 +26,29 @@ class ServerActions(models.Model): 'mail.template', 'Email Template', ondelete='set null', domain="[('model_id', '=', model_id)]", ) + # Next Activity + activity_type_id = fields.Many2one( + 'mail.activity.type', string='Activity', + domain="['|', ('res_model_id', '=', False), ('res_model_id', '=', model_id)]") + activity_summary = fields.Char('Summary') + activity_note = fields.Html('Note') + activity_date_deadline_range = fields.Integer(string='Due Date In') + activity_date_deadline_range_type = fields.Selection([ + ('days', 'Days'), + ('weeks', 'Weeks'), + ('months', 'Months'), + ], string='Due type', default='days') + activity_user_type = fields.Selection([ + ('specific', 'Specific User'), + ('generic', 'Generic User From Record')], default="specific", required=True, + help="Use 'Specific User' to always assign the same user on the next activity. Use 'Generic User From Record' to specify the field name of the user to choose on the record.") + activity_user_id = fields.Many2one('res.users', string='Responsible') + activity_user_field_name = fields.Char('User field name', help="Technical name of the user on the record", default="user_id") + + @api.onchange('activity_date_deadline_range') + def _onchange_activity_date_deadline_range(self): + if self.activity_date_deadline_range < 0: + raise UserError(_("The 'Due Date In' value can't be negative.")) @api.onchange('template_id') def on_change_template_id(self): @@ -35,6 +62,12 @@ class ServerActions(models.Model): if action.state == 'followers' and not action.model_id.is_mail_thread: raise ValidationError(_("Add Followers can only be done on a mail thread model")) + @api.constrains('state', 'model_id') + def _check_activity_mixin(self): + for action in self: + if action.state == 'next_activity' and not issubclass(self.pool[action.model_id.model], self.pool['mail.thread']): + raise ValidationError(_("A next activity can only be planned on models that use the chatter")) + @api.model def run_action_followers_multi(self, action, eval_context=None): Model = self.env[action.model_id.model] @@ -51,6 +84,29 @@ class ServerActions(models.Model): action.template_id.send_mail(self._context.get('active_id'), force_send=False, raise_exception=False) return False + @api.model + def run_action_next_activity(self, action, eval_context=None): + if not action.activity_type_id or not self._context.get('active_id'): + return False + + records = self.env[action.model_id.model].browse(self._context.get('active_ids', self._context.get('active_id'))) + vals = { + 'summary': action.activity_summary or '', + 'note': action.activity_note or '', + 'activity_type_id': action.activity_type_id.id, + } + if action.activity_date_deadline_range > 0: + vals['date_deadline'] = date.today() + relativedelta(**{action.activity_date_deadline_range_type: action.activity_date_deadline_range}) + for record in records: + if action.activity_user_type == 'specific': + user = action.activity_user_id + elif action.activity_user_type == 'generic' and action.activity_user_field_name in record: + user = record[action.activity_user_field_name] + if user: + vals['user_id'] = user.id + record.activity_schedule(**vals) + return False + @api.model def _get_eval_context(self, action=None): """ Override the method giving the evaluation context but also the diff --git a/addons/mail/views/ir_actions_views.xml b/addons/mail/views/ir_actions_views.xml index 381310bf69c..a5a7a0dd6bd 100644 --- a/addons/mail/views/ir_actions_views.xml +++ b/addons/mail/views/ir_actions_views.xml @@ -7,6 +7,27 @@ ir.actions.server + + + + + + + + + + + + + diff --git a/addons/test_mail/tests/test_ir_actions.py b/addons/test_mail/tests/test_ir_actions.py index 543c27d4a21..f54b07b18e0 100644 --- a/addons/test_mail/tests/test_ir_actions.py +++ b/addons/test_mail/tests/test_ir_actions.py @@ -34,3 +34,16 @@ class TestServerActionsEmail(TestServerActionsBase): self.action.with_context(self.context).run() self.assertEqual(self.test_partner.message_partner_ids, self.env.ref('base.partner_root') | self.env.ref('base.partner_demo')) self.assertEqual(self.test_partner.message_channel_ids, self.env.ref('mail.channel_all_employees')) + + def test_action_next_activity(self): + self.action.write({ + 'state': 'next_activity', + 'activity_user_type': 'specific', + 'activity_type_id': self.env.ref('mail.mail_activity_data_meeting').id, + 'activity_summary': 'TestNew', + }) + before_count = self.env['mail.activity'].search_count([]) + run_res = self.action.with_context(self.context).run() + self.assertFalse(run_res, 'ir_actions_server: create next activity action correctly finished should return False') + self.assertEqual(self.env['mail.activity'].search_count([]), before_count + 1) + self.assertEqual(self.env['mail.activity'].search_count([('summary', '=', 'TestNew')]), 1)