[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
This commit is contained in:
Pierre Paridans
2018-08-08 17:35:34 +02:00
committed by Yannick Tivisse
parent e4381d9f1b
commit 7309981426
3 changed files with 91 additions and 1 deletions
+57 -1
View File
@@ -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
+21
View File
@@ -7,6 +7,27 @@
<field name="model">ir.actions.server</field>
<field name="inherit_id" ref="base.view_server_action_form"/>
<field name="arch" type="xml">
<notebook position="inside">
<page string="Activity" name="next_activity" autofocus="autofocus" attrs="{'invisible': [('state', '!=', 'next_activity')]}">
<group>
<group>
<field name="activity_type_id" options="{'no_create': True, 'no_open': True}" attrs="{'required': [('state', '=', 'next_activity')]}"/>
<field name="activity_summary" placeholder="e.g. Discuss proposal"/>
</group>
<group>
<label for="activity_date_deadline_range"/>
<div class="o_row">
<field name="activity_date_deadline_range"/>
<field name="activity_date_deadline_range_type"/>
</div>
<field name="activity_user_type"/>
<field name="activity_user_field_name" attrs="{'invisible': [('activity_user_type', '=', 'specific')], 'required': [('activity_user_type', '=', 'generic')]}"/>
<field name="activity_user_id" attrs="{'invisible': [('activity_user_type', '=', 'generic')], 'required': [('activity_user_type', '=', 'specific')]}"/>
</group>
</group>
<field name="activity_note" placeholder="Log a note..."/>
</page>
</notebook>
<field name="link_field_id" position="after">
<field name="partner_ids" widget="many2many_tags"
attrs="{'invisible': [('state', '!=', 'followers')]}"/>
+13
View File
@@ -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)