From fac5f1ee3f63d3ceb66e834478237b3a1392f052 Mon Sep 17 00:00:00 2001
From: cubells
Date: Tue, 2 May 2017 18:11:53 +0200
Subject: [PATCH] [MIG][9.0] crm_action module
---
crm_action/README.rst | 22 ++-
crm_action/__openerp__.py | 17 +-
crm_action/data/email_reminder.xml | 60 +++---
crm_action/demo/demo.xml | 128 ++++++------
.../migrations/8.0.1.2.0/pre-migration.py | 14 --
crm_action/models/crm_action.py | 104 +++++-----
crm_action/models/crm_action_type.py | 20 +-
crm_action/models/crm_lead.py | 52 +++--
crm_action/security/ir_rule_data.xml | 40 ++--
crm_action/tests/__init__.py | 5 +
crm_action/tests/test_crm_action.py | 57 ++++++
crm_action/views/crm_action_type_view.xml | 91 +++++----
crm_action/views/crm_action_view.xml | 185 +++++++++---------
crm_action/views/crm_lead_view.xml | 91 +++++----
14 files changed, 487 insertions(+), 399 deletions(-)
delete mode 100644 crm_action/migrations/8.0.1.2.0/pre-migration.py
create mode 100644 crm_action/tests/__init__.py
create mode 100644 crm_action/tests/test_crm_action.py
diff --git a/crm_action/README.rst b/crm_action/README.rst
index 62b964e0970..7f3372bc8cc 100644
--- a/crm_action/README.rst
+++ b/crm_action/README.rst
@@ -7,7 +7,8 @@ CRM Action
==========
This module was written to extend CRM features.
-It delivers new object named "Actions" to follow history around leads and opportunities.
+It delivers new object named "Actions" to follow history around leads and
+opportunities.
Installation
============
@@ -17,9 +18,14 @@ Just install the module as usual (it only depends on the native *crm* module).
Configuration
=============
-Go to the menu *Sales > Configuration > Leads & Opportunities > Action Types* and create action types.
+Go to the menu *Sales > Configuration > Leads & Opportunities > Action Types*
+and create action types.
-If you want to have a daily email reminder of your CRM actions to do, go to the menu *Settings > Technical > Automation > Scheduled Actions* and activate the action *CRM Action email reminder* (it is inactive by default). You can customize the email template in the menu *Settings > Technical > Email > Templates* and select the email template named *CRM Action reminder*.
+If you want to have a daily email reminder of your CRM actions to do, go to
+the menu *Settings > Technical > Automation > Scheduled Actions* and activate
+the action *CRM Action email reminder* (it is inactive by default). You can
+customize the email template in the menu *Settings > Technical > Email >
+Templates* and select the email template named *CRM Action reminder*.
Usage
=====
@@ -30,11 +36,14 @@ To use this module, you need to :
#. create a new action by using the *Actions* button,
#. when the action is done, click on the button *Mark as done*.
-You can overview all actions for any lead or opportunity with the *Actions* menu entry. On the form view of an opportunity, you can see the next action to do and there is also a button to mark it as done (it will immediately display the new next action to do).
+You can overview all actions for any lead or opportunity with the *Actions*
+menu entry. On the form view of an opportunity, you can see the next action to
+do and there is also a button to mark it as done (it will immediately display
+the new next action to do).
.. image:: https://odoo-community.org/website/image/ir.attachment/5784_f2813bd/datas
:alt: Try me on Runbot
- :target: https://runbot.odoo-community.org/runbot/111/8.0
+ :target: https://runbot.odoo-community.org/runbot/111/9.0
Known issues / Roadmap
======================
@@ -50,8 +59,6 @@ help us smashing it by providing a detailed and welcomed feedback.
Credits
=======
-Module developed and tested with Odoo version 8.0
-
Contributors
------------
@@ -59,6 +66,7 @@ Contributors
* Jordi RIERA
* Bruno JOLIVEAU
* Alexis de Lattre
+* Vicent Cubells
Maintainer
----------
diff --git a/crm_action/__openerp__.py b/crm_action/__openerp__.py
index 922b1d969a7..bcf19991b1c 100644
--- a/crm_action/__openerp__.py
+++ b/crm_action/__openerp__.py
@@ -1,15 +1,20 @@
# -*- coding: utf-8 -*-
-# © 2015-2016 Savoir-faire Linux ()
+# Copyright 2015-2016 Savoir-faire Linux ()
+# Copyright 2017 Tecnativa - Vicent Cubells
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
{
'name': 'CRM Action',
- 'version': '8.0.1.2.0',
- 'author': 'Savoir-faire Linux,Odoo Community Association (OCA)',
+ 'version': '9.0.1.0.0',
+ 'author': 'Savoir-faire Linux, '
+ 'Tecnativa, '
+ 'Odoo Community Association (OCA)',
'license': 'AGPL-3',
'category': 'CRM',
'summary': 'Adds action management in CRM',
- 'depends': ['crm'],
+ 'depends': [
+ 'crm',
+ ],
'data': [
'security/ir.model.access.csv',
'security/ir_rule_data.xml',
@@ -18,7 +23,9 @@
'views/crm_lead_view.xml',
'data/email_reminder.xml',
],
- 'demo': ['demo/demo.xml'],
+ 'demo': [
+ 'demo/demo.xml',
+ ],
'installable': True,
'application': True,
}
diff --git a/crm_action/data/email_reminder.xml b/crm_action/data/email_reminder.xml
index 29f40b6e3dd..17b1ef533ad 100644
--- a/crm_action/data/email_reminder.xml
+++ b/crm_action/data/email_reminder.xml
@@ -1,36 +1,34 @@
+
+
+
+ CRM Action email reminder
+
+
+ 1
+ days
+ -1
+
+
+
+
+
+
+
-
-
-
-
- CRM Action email reminder
-
-
- 1
- days
- -1
-
-
-
-
-
-
-
-
-
-
- CRM Action Reminder
-
-
- ${ctx.get('company').email or 'odoo@example.com'}
- ${object.email}
- [${ctx.get('company').name}] Today's CRM actions
-
+ CRM Action Reminder
+
+
+ ${ctx.get('company').email or 'odoo@example.com'}
+ ${object.email}
+ [${ctx.get('company').name}] Today's CRM actions
+
Dear ${object.name},
@@ -70,7 +68,7 @@ Automatic e-mail sent by Odoo. Do not reply.
]]>
-
+
-
-
+
+
diff --git a/crm_action/demo/demo.xml b/crm_action/demo/demo.xml
index c73d1a47790..b787a944b48 100644
--- a/crm_action/demo/demo.xml
+++ b/crm_action/demo/demo.xml
@@ -1,77 +1,73 @@
-
-
+
+
+ Meeting
+
-
- Meeting
-
+
+ Followup
+
-
- Followup
-
+
+ Demo
+
-
- Demo
-
+
+ Get news about our quote
+
+
+
+
+
+ done
+
-
- Get news about our quote
-
-
-
-
-
- done
-
+
+ Meeting
+
+
+
+
+
+ draft
+
-
- Meeting
-
-
-
-
-
- draft
-
+
+ Organise a demo in our showroom
+
+
+
+
+
+ draft
+
-
- Organise a demo in our showroom
-
-
-
-
-
- draft
-
+
+ Get feedback about our quote
+
+
+
+
+ done
+
-
- Get feedback about our quote
-
-
-
-
- done
-
+
+ Meet in real life
+
+
+
+
+ draft
+
-
- Meet in real life
-
-
-
-
- draft
-
+
+ Organise a super demo to convince him that it is super easy and super fast
+
+
+
+
+ draft
+
-
- Organise a super demo to convince him that it is super easy and super fast
-
-
-
-
- draft
-
-
-
-
-
+
diff --git a/crm_action/migrations/8.0.1.2.0/pre-migration.py b/crm_action/migrations/8.0.1.2.0/pre-migration.py
deleted file mode 100644
index 4923bcada0d..00000000000
--- a/crm_action/migrations/8.0.1.2.0/pre-migration.py
+++ /dev/null
@@ -1,14 +0,0 @@
-# -*- coding: utf-8 -*-
-# © 2016 Akretion (Alexis de Lattre )
-# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
-
-
-def migrate(cr, version):
- if not version:
- return
-
- cr.execute(
- 'ALTER TABLE "crm_action_type" RENAME "is_active" TO "active"')
-
- cr.execute(
- 'ALTER TABLE "crm_action" RENAME "action_type" TO "action_type_id"')
diff --git a/crm_action/models/crm_action.py b/crm_action/models/crm_action.py
index 9163dc4f8a9..111a2591fa2 100644
--- a/crm_action/models/crm_action.py
+++ b/crm_action/models/crm_action.py
@@ -1,8 +1,9 @@
# -*- coding: utf-8 -*-
-# © 2015-2016 Savoir-faire Linux ()
+# Copyright 2015-2016 Savoir-faire Linux ()
+# Copyright 2017 Tecnativa - Vicent Cubells
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
-from openerp import models, fields, api
+from openerp import api, fields, models
import logging
logger = logging.getLogger(__name__)
@@ -14,8 +15,57 @@ class CrmAction(models.Model):
_order = 'date'
_rec_name = 'display_name'
+ def default_action_type(self):
+ action_types = self.search_action_types()
+ return action_types and action_types[0].id or False
+
lead_id = fields.Many2one(
- 'crm.lead', string='Lead', ondelete='cascade')
+ comodel_name='crm.lead',
+ string='Lead',
+ ondelete='cascade',
+ )
+ company_id = fields.Many2one(
+ comodel_name='res.company',
+ string='Company',
+ default=lambda self: self.env['res.company']._company_default_get(
+ 'crm.action'),
+ )
+ partner_id = fields.Many2one(
+ comodel_name='res.partner',
+ string='Customer',
+ )
+ date = fields.Date(
+ required=True,
+ default=fields.Date.context_today,
+ )
+ user_id = fields.Many2one(
+ comodel_name='res.users',
+ string='User',
+ required=True,
+ default=lambda self: self.env.user,
+ )
+ action_type_id = fields.Many2one(
+ comodel_name='crm.action.type',
+ string='Type',
+ required=True,
+ default=default_action_type,
+ )
+ details = fields.Text()
+ state = fields.Selection(
+ selection=[
+ ('draft', 'Todo'),
+ ('done', 'Done'),
+ ],
+ string='Status',
+ required=True,
+ readonly=True,
+ default="draft",
+ )
+ display_name = fields.Char(
+ compute='compute_display_name',
+ readonly=True,
+ store=True,
+ )
@api.onchange('lead_id')
def check_change(self):
@@ -24,41 +74,16 @@ def check_change(self):
self.partner_id = lead.partner_id
self.company_id = lead.company_id
- company_id = fields.Many2one(
- 'res.company', string='Company',
- default=lambda self: self.env['res.company']._company_default_get(
- 'crm.action'))
-
- partner_id = fields.Many2one(
- 'res.partner', string='Customer')
-
- date = fields.Date(
- 'Date', required=True,
- default=fields.Date.context_today)
-
- user_id = fields.Many2one(
- 'res.users', string='User', required=True,
- default=lambda self: self.env.user)
-
def search_action_types(self):
return self.env['crm.action.type'].search([], order='priority')
- def default_action_type(self):
- action_types = self.search_action_types()
- return action_types and action_types[0].id or False
-
- action_type_id = fields.Many2one(
- 'crm.action.type', string='Type', required=True,
- default=default_action_type)
-
- details = fields.Text('Details')
+ @api.multi
+ def button_confirm(self):
+ self.write({'state': 'done'})
- state = fields.Selection(
- [
- ('draft', 'Todo'),
- ('done', 'Done'),
- ], string='Status', required=True, readonly=True,
- default="draft")
+ @api.multi
+ def button_set_to_draft(self):
+ self.write({'state': 'draft'})
@api.multi
@api.depends('action_type_id.name', 'details')
@@ -70,17 +95,6 @@ def compute_display_name(self):
else:
action.display_name = u'[%s]' % action.action_type_id.name
- display_name = fields.Char(
- compute='compute_display_name', readonly=True, store=True)
-
- @api.multi
- def button_confirm(self):
- self.write({'state': 'done'})
-
- @api.multi
- def button_set_to_draft(self):
- self.write({'state': 'draft'})
-
@api.model
def _send_email_reminder(self):
today = fields.Date.context_today(self)
diff --git a/crm_action/models/crm_action_type.py b/crm_action/models/crm_action_type.py
index a07ca97aa50..e6058356dd0 100644
--- a/crm_action/models/crm_action_type.py
+++ b/crm_action/models/crm_action_type.py
@@ -1,16 +1,26 @@
# -*- coding: utf-8 -*-
-# © 2015-2016 Savoir-faire Linux ()
+# Copyright 2015-2016 Savoir-faire Linux ()
+# Copyright 2017 Tecnativa - Vicent Cubells
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
-from openerp import models, fields
+from openerp import fields, models
class CrmActionType(models.Model):
_name = 'crm.action.type'
_description = 'CRM Action Type'
- name = fields.Char('Name', translate=True, required=True)
- priority = fields.Integer('Priority', required=True, default=0)
- active = fields.Boolean('Active', default=True)
+ name = fields.Char(
+ string='Name',
+ translate=True,
+ required=True,
+ )
+ priority = fields.Integer(
+ string='Priority',
+ required=True, default=0,
+ )
+ active = fields.Boolean(
+ default=True,
+ )
_order = 'priority'
diff --git a/crm_action/models/crm_lead.py b/crm_action/models/crm_lead.py
index d85295408cf..554afb1e224 100644
--- a/crm_action/models/crm_lead.py
+++ b/crm_action/models/crm_lead.py
@@ -1,16 +1,44 @@
# -*- coding: utf-8 -*-
-# © 2015-2016 Savoir-faire Linux ()
+# Copyright 2015-2016 Savoir-faire Linux ()
+# Copyright 2017 Tecnativa - Vicent Cubells
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
-from openerp import models, fields, api
+from openerp import api, fields, models
class CrmLead(models.Model):
_inherit = 'crm.lead'
- def count_actions(self):
+ def compute_count_actions(self):
self.actions_count = len(self.action_ids)
+ actions_count = fields.Integer(
+ compute='compute_count_actions',
+ )
+ action_ids = fields.One2many(
+ comodel_name='crm.action',
+ inverse_name='lead_id',
+ string='Actions',
+ )
+ # replace native fields "date_action" (Next Action Date)
+ # and "title_action" (Next Action) by related fields
+ date_action = fields.Date(
+ related='next_action_id.date',
+ readonly=True,
+ store=True,
+ )
+ title_action = fields.Char(
+ related='next_action_id.display_name',
+ readonly=True,
+ store=True,
+ )
+ next_action_id = fields.Many2one(
+ comodel_name='crm.action',
+ string='Next Action',
+ compute='compute_next_action',
+ readonly=True, store=True,
+ )
+
@api.multi
@api.depends(
'action_ids.date', 'action_ids.display_name', 'action_ids.state')
@@ -27,20 +55,6 @@ def compute_next_action(self):
@api.multi
def next_action_done(self):
self.ensure_one()
- lead = self[0]
- if lead.next_action_id:
- lead.next_action_id.button_confirm()
+ if self.next_action_id:
+ self.next_action_id.button_confirm()
return True
-
- actions_count = fields.Integer(compute='count_actions')
- action_ids = fields.One2many(
- 'crm.action', 'lead_id', string='Actions')
- # replace native fields "date_action" (Next Action Date)
- # and "title_action" (Next Action) by related fields
- date_action = fields.Date(
- related='next_action_id.date', readonly=True, store=True)
- title_action = fields.Char(
- related='next_action_id.display_name', store=True, readonly=True)
- next_action_id = fields.Many2one(
- 'crm.action', string='Next Action',
- compute='compute_next_action', readonly=True, store=True)
diff --git a/crm_action/security/ir_rule_data.xml b/crm_action/security/ir_rule_data.xml
index 6c95ffeb3a6..1b853afd558 100644
--- a/crm_action/security/ir_rule_data.xml
+++ b/crm_action/security/ir_rule_data.xml
@@ -1,24 +1,22 @@
-
-
+
-
- Personal CRM Actions
-
- ['|', ('lead_id.user_id', '=', user.id), ('user_id', '=', user.id)]
-
-
-
- All CRM Actions
-
- [(1, '=', 1)]
-
-
-
- CRM Actions multi-company
-
- ['|', ('company_id', '=', False), ('company_id', 'child_of', [user.company_id.id])]
-
+
+ Personal CRM Actions
+
+ ['|', ('lead_id.user_id', '=', user.id), ('user_id', '=', user.id)]
+
+
+
+ All CRM Actions
+
+ [(1, '=', 1)]
+
+
+
+ CRM Actions multi-company
+
+ ['|', ('company_id', '=', False), ('company_id', 'child_of', [user.company_id.id])]
+
-
-
+
diff --git a/crm_action/tests/__init__.py b/crm_action/tests/__init__.py
new file mode 100644
index 00000000000..435d8c6af8d
--- /dev/null
+++ b/crm_action/tests/__init__.py
@@ -0,0 +1,5 @@
+# -*- coding: utf-8 -*-
+# Copyright 2017 Tecnativa - Vicent Cubells
+# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
+
+from . import test_crm_action
diff --git a/crm_action/tests/test_crm_action.py b/crm_action/tests/test_crm_action.py
new file mode 100644
index 00000000000..b15590d463f
--- /dev/null
+++ b/crm_action/tests/test_crm_action.py
@@ -0,0 +1,57 @@
+# -*- coding: utf-8 -*-
+# Copyright 2017 Vicent Cubells -
+# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
+from openerp.tests import common
+
+
+class TestCrmAction(common.SavepointCase):
+ @classmethod
+ def setUpClass(cls):
+ super(TestCrmAction, cls).setUpClass()
+ cls.partner = cls.env['res.partner'].create({
+ 'name': 'Test partner',
+ })
+ cls.pipeline = cls.env['crm.lead'].create({
+ 'name': 'Test lead',
+ 'partner_id': cls.partner.id,
+ })
+ cls.action1 = cls.env['crm.action'].create({
+ 'details': 'Test action #1',
+ })
+ cls.action2 = cls.env['crm.action'].create({
+ 'lead_id': cls.pipeline.id,
+ })
+
+ def test_crm_action(self):
+ self.action1.lead_id = self.pipeline.id
+ self.action1.check_change()
+ self.assertEqual(self.action1.partner_id, self.partner)
+
+ self.action1.button_confirm()
+ self.assertEqual(self.action1.state, 'done')
+
+ self.action1.button_set_to_draft()
+ self.assertEqual(self.action1.state, 'draft')
+
+ self.action1.button_confirm()
+
+ self.assertEqual(self.action2.state, 'draft')
+ self.assertEqual(
+ self.pipeline.next_action_id, self.action2)
+
+ self.action2.button_confirm()
+ self.assertEqual(len(self.pipeline.next_action_id), 0)
+
+ self.action2.button_set_to_draft()
+ self.assertEqual(
+ self.pipeline.next_action_id, self.action2)
+
+ self.pipeline.next_action_done()
+ self.assertEqual(
+ self.action2.state, 'done')
+
+ self.action2.button_set_to_draft()
+ self.assertTrue(self.action2._send_email_reminder())
+
+ self.action2.user_id.email = False
+ self.action2._send_email_reminder()
diff --git a/crm_action/views/crm_action_type_view.xml b/crm_action/views/crm_action_type_view.xml
index 9112c01f1ae..262ea957ad8 100644
--- a/crm_action/views/crm_action_type_view.xml
+++ b/crm_action/views/crm_action_type_view.xml
@@ -1,55 +1,52 @@
-
-
-
-
-
- crm.action.type.form
- crm.action.type
-
-
-
-
-
-
- crm.action.type.tree
- crm.action.type
-
-
+
+
+
+ crm.action.type.form
+ crm.action.type
+
+
-
-
+
+
+
+
-
- CRM - Actions
- crm.action.type
-
-
-
-
-
-
+
+ crm.action.type.tree
+ crm.action.type
+
+
+
+
+
+
+
+
+
+
+ CRM - Actions
+ crm.action.type
+
+
+
+
+
+
-
- Action Types
- crm.action.type
- tree
-
+
+ Action Types
+ crm.action.type
+ tree
+
-
+
-
-
+
diff --git a/crm_action/views/crm_action_view.xml b/crm_action/views/crm_action_view.xml
index d1319cd2937..3fd5509552d 100644
--- a/crm_action/views/crm_action_view.xml
+++ b/crm_action/views/crm_action_view.xml
@@ -1,100 +1,99 @@
-
-
-
- crm.action.form
- crm.action
-
-
-
-
+
-
- crm.action.tree
- crm.action
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+ crm.action.form
+ crm.action
+
+
+
+
-
- crm.action.calendar
- crm.action
-
-
-
-
-
-
-
+
+ crm.action.tree
+ crm.action
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
- CRM - Actions
- crm.action
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+ crm.action.calendar
+ crm.action
+
+
+
+
+
+
+
+
+
+ CRM - Actions
+ crm.action
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
- Actions
- crm.action
- tree,form,calendar
- {'search_default_user_me': 1}
-
+
+ Actions
+ crm.action
+ tree,form,calendar
+ {'search_default_user_me': 1}
+
-
+
-
-
+
diff --git a/crm_action/views/crm_lead_view.xml b/crm_action/views/crm_lead_view.xml
index 465d92354bb..0100c2702bf 100644
--- a/crm_action/views/crm_lead_view.xml
+++ b/crm_action/views/crm_lead_view.xml
@@ -1,51 +1,50 @@
-
-
+
-
- Actions
- crm.action
- tree,form,calendar
-
+
+ Actions
+ crm.action
+ tree,form,calendar
+
-
- CRM - Opportunity Form
- crm.lead
-
-
-
-
-
-
-
-
-
+
+ CRM - Opportunity Form
+ crm.lead
+
+
+
+
+
+
+
+
-
-
- CRM - Leads Action Button
- crm.lead
-
-
-
-
-
-
-
-
-
+
+
+
+ CRM - Leads Action Button
+ crm.lead
+
+
+
+
+
+
+
+
+