Browse Source
[10.0] Improving the mail tracking value (#170)
[10.0] Improving the mail tracking value (#170)
Improve the tracking of changed values on database fields ("mail.tracking.value" functionality) by adding many2many and one2many support. As well as a more user friendly view to consult changes recorded.pull/362/head
Thierry Ducrest
7 years ago
committed by
Holger Brunn
8 changed files with 417 additions and 0 deletions
-
77mail_improved_tracking_value/README.rst
-
5mail_improved_tracking_value/__init__.py
-
23mail_improved_tracking_value/__manifest__.py
-
5mail_improved_tracking_value/models/__init__.py
-
78mail_improved_tracking_value/models/mail_tracking_value.py
-
1mail_improved_tracking_value/tests/__init__.py
-
154mail_improved_tracking_value/tests/test_improved_tracking_value.py
-
74mail_improved_tracking_value/views/mail_tracking_value.xml
@ -0,0 +1,77 @@ |
|||
.. image:: https://img.shields.io/badge/licence-AGPL--3-blue.svg |
|||
:target: http://www.gnu.org/licenses/agpl-3.0-standalone.html |
|||
:alt: License: AGPL-3 |
|||
|
|||
============================== |
|||
Tracking value change improved |
|||
============================== |
|||
|
|||
This module extends the mail_tracking_value functionality that records |
|||
value changes on predefined fields. |
|||
It adds support for many2many and one2many fields, which are not handled |
|||
well by default. |
|||
It also implements a new view (little bit more user friendly than the |
|||
existing one) to watch for changes |
|||
|
|||
Installation |
|||
============ |
|||
|
|||
To install this module, you need to: |
|||
|
|||
#. Just install the module |
|||
|
|||
Configuration |
|||
============= |
|||
|
|||
To configure this module, you need to: |
|||
|
|||
# No configuration is necessary |
|||
|
|||
Usage |
|||
===== |
|||
|
|||
To access the new view displaying value changes : |
|||
|
|||
Settings -> Technical -> Improved tracking values |
|||
|
|||
|
|||
Known issues / Roadmap |
|||
====================== |
|||
|
|||
* Improve rendering of values depending of type using qweb widgets |
|||
|
|||
Bug Tracker |
|||
=========== |
|||
|
|||
Bugs are tracked on `GitHub Issues |
|||
<https://github.com/OCA/mail_improved_tracking_value/issues>`_. In case of trouble, please |
|||
check there if your issue has already been reported. If you spotted it first, |
|||
help us smash it by providing detailed and welcomed feedback. |
|||
|
|||
Credits |
|||
======= |
|||
|
|||
Images |
|||
------ |
|||
|
|||
* Odoo Community Association: `Icon <https://github.com/OCA/maintainer-tools/blob/master/template/module/static/description/icon.svg>`_. |
|||
|
|||
Contributors |
|||
------------ |
|||
|
|||
* Thierry Ducrest <thierry.ducrest@camptocamp.com> |
|||
|
|||
Maintainer |
|||
---------- |
|||
|
|||
.. image:: https://odoo-community.org/logo.png |
|||
:alt: Odoo Community Association |
|||
:target: https://odoo-community.org |
|||
|
|||
This module is maintained by the OCA. |
|||
|
|||
OCA, or the Odoo Community Association, is a nonprofit organization whose |
|||
mission is to support the collaborative development of Odoo features and |
|||
promote its widespread use. |
|||
|
|||
To contribute to this module, please visit https://odoo-community.org. |
@ -0,0 +1,5 @@ |
|||
# -*- coding: utf-8 -*- |
|||
# Copyright 2017 Camptocamp SA |
|||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). |
|||
|
|||
from . import models |
@ -0,0 +1,23 @@ |
|||
# -*- coding: utf-8 -*- |
|||
# Copyright 2017 Camptocamp SA |
|||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). |
|||
|
|||
{ |
|||
'name': 'Improved tracking value change', |
|||
'version': '10.0.1.0.0', |
|||
'summary': 'Improves tracking changed values for certain type of fields.' |
|||
'Adds a user-friendly view to consult them.', |
|||
'author': 'Camptocamp, Odoo Community Association (OCA)', |
|||
'license': 'AGPL-3', |
|||
'category': 'Tools', |
|||
'website': 'http://www.camptocamp.com', |
|||
'depends': [ |
|||
'base', |
|||
'mail' |
|||
], |
|||
'data': [ |
|||
'views/mail_tracking_value.xml' |
|||
], |
|||
'installable': True, |
|||
'auto_install': False, |
|||
} |
@ -0,0 +1,5 @@ |
|||
# -*- coding: utf-8 -*- |
|||
# Copyright 2017 Camptocamp SA |
|||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). |
|||
|
|||
from . import mail_tracking_value |
@ -0,0 +1,78 @@ |
|||
# -*- coding: utf-8 -*- |
|||
# Copyright 2017 Camptocamp SA |
|||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). |
|||
|
|||
import json |
|||
|
|||
from odoo import api, fields, models |
|||
|
|||
|
|||
class MailTrackingValue(models.Model): |
|||
|
|||
_inherit = "mail.tracking.value" |
|||
|
|||
new_value_formatted = fields.Char(compute='_compute_formatted_value', |
|||
string='New value') |
|||
old_value_formatted = fields.Char(compute='_compute_formatted_value', |
|||
string='Old value') |
|||
record_name = fields.Char(related='mail_message_id.record_name') |
|||
model = fields.Char(related='mail_message_id.model', store='True', |
|||
string='Model') |
|||
|
|||
@api.depends('new_value_char', 'new_value_integer', 'new_value_float', |
|||
'new_value_text', 'new_value_datetime', 'new_value_monetary', |
|||
'old_value_char', 'old_value_integer', 'old_value_float', |
|||
'old_value_text', 'old_value_datetime', 'old_value_monetary') |
|||
def _compute_formatted_value(self): |
|||
""" Sets the value formatted field used in the view """ |
|||
# Could be improved, by styling in the view depending on type of field |
|||
for record in self: |
|||
if record.field_type in ('many2many', 'one2many', 'char'): |
|||
record.new_value_formatted = record.new_value_char |
|||
record.old_value_formatted = record.old_value_char |
|||
elif record.field_type == 'integer': |
|||
record.new_value_formatted = str(record.new_value_integer) |
|||
record.old_value_formatted = str(record.old_value_integer) |
|||
elif record.field_type == 'float': |
|||
record.new_value_formatted = str(record.new_value_float) |
|||
record.old_value_formatted = str(record.old_value_float) |
|||
elif record.field_type == 'monetary': |
|||
record.new_value_formatted = str(record.new_value_monetary) |
|||
record.old_value_formatted = str(record.old_value_monetary) |
|||
elif record.field_type == 'datetime': |
|||
record.new_value_formatted = str(record.new_value_datetime) |
|||
record.old_value_formatted = str(record.old_value_datetime) |
|||
elif record.field_type == 'text': |
|||
record.new_value_formatted = record.new_value_text |
|||
record.old_value_formatted = record.old_value_text |
|||
|
|||
@api.model |
|||
def create_tracking_values(self, old_value, new_value, col_name, col_info): |
|||
""" Add tacking capabilities for many2many and one2many fields """ |
|||
if col_info['type'] in ('many2many', 'one2many'): |
|||
|
|||
def get_values(source, prefix): |
|||
if source: |
|||
names = ', '.join(source.mapped('display_name')) |
|||
json_ids = json.dumps(source.ids) |
|||
else: |
|||
names = '' |
|||
json_ids = json.dumps([]) |
|||
return { |
|||
'{}_value_char'.format(prefix): names, |
|||
'{}_value_text'.format(prefix): json_ids, |
|||
} |
|||
|
|||
values = { |
|||
'field': col_name, |
|||
'field_desc': col_info['string'], |
|||
'field_type': col_info['type'], |
|||
} |
|||
values.update(get_values(old_value, 'old')) |
|||
values.update(get_values(new_value, 'new')) |
|||
return values |
|||
else: |
|||
return super(MailTrackingValue, self).create_tracking_values( |
|||
old_value, new_value, |
|||
col_name, col_info |
|||
) |
@ -0,0 +1 @@ |
|||
from . import test_improved_tracking_value |
@ -0,0 +1,154 @@ |
|||
# -*- coding: utf-8 -*- |
|||
# Copyright 2018 Camptocamp SA |
|||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html) |
|||
|
|||
import json |
|||
from odoo.tests.common import TransactionCase |
|||
|
|||
|
|||
class TestImproveTrackingValue(TransactionCase): |
|||
|
|||
def setUp(self): |
|||
super(TestImproveTrackingValue, self).setUp() |
|||
self.model = self.env['mail.tracking.value'] |
|||
self.msg = self.env['mail.message'].create({ |
|||
'message_type': 'email' |
|||
}) |
|||
self.mr = self.env.ref('base.res_partner_title_mister') |
|||
self.dr = self.env.ref('base.res_partner_title_doctor') |
|||
self.mm = self.env.ref('base.res_partner_title_madam') |
|||
self.pf = self.env.ref('base.res_partner_title_prof') |
|||
|
|||
def test_change_one2many(self): |
|||
"""Test tracking one2many changes""" |
|||
tracking = self.model.create_tracking_values( |
|||
self.mr, self.dr, 'testing_col', |
|||
{'string': 'TestingField', 'type': 'one2many'}) |
|||
self.assertEqual(tracking['old_value_char'], self.mr.display_name) |
|||
self.assertEqual(tracking['new_value_char'], self.dr.display_name) |
|||
self.assertEqual(tracking['old_value_text'], json.dumps([self.mr.id])) |
|||
self.assertEqual(tracking['new_value_text'], json.dumps([self.dr.id])) |
|||
|
|||
def test_change_one2many_empty(self): |
|||
"""Test tracking one2many changes emtpy""" |
|||
tracking = self.model.create_tracking_values( |
|||
self.mr, None, 'testing_col', |
|||
{'string': 'TestingField', 'type': 'one2many'}) |
|||
self.assertEqual(tracking['old_value_char'], self.mr.display_name) |
|||
self.assertEqual(tracking['new_value_char'], '') |
|||
self.assertEqual(tracking['old_value_text'], json.dumps([self.mr.id])) |
|||
self.assertEqual(tracking['new_value_text'], json.dumps([])) |
|||
|
|||
def test_change_many2many(self): |
|||
"""Test tracking many2many changes""" |
|||
oldvalue = self.env['res.partner.title'].browse([self.mr.id, |
|||
self.dr.id]) |
|||
newvalue = self.env['res.partner.title'].browse([self.mm.id, |
|||
self.pf.id]) |
|||
tracking = self.model.create_tracking_values( |
|||
oldvalue, newvalue, 'testing_col', |
|||
{'string': 'TestingField', 'type': 'many2many'}) |
|||
self.assertEqual(tracking['old_value_char'], |
|||
self.mr.display_name + ', ' + self.dr.display_name) |
|||
self.assertEqual(tracking['new_value_char'], |
|||
self.mm.display_name + ', ' + self.pf.display_name) |
|||
self.assertEqual(tracking['old_value_text'], |
|||
json.dumps(oldvalue.ids)) |
|||
self.assertEqual(tracking['new_value_text'], |
|||
json.dumps(newvalue.ids)) |
|||
|
|||
def test_char_tracking_value(self): |
|||
r = self.model.create({ |
|||
'mail_message_id': self.msg.id, |
|||
'field_type': 'char', |
|||
'old_value_char': 'weakness', |
|||
'new_value_char': 'strength', |
|||
'field': 'test', |
|||
'field_desc': 'desc', |
|||
}) |
|||
self.assertEqual(r.old_value_formatted, 'weakness') |
|||
self.assertEqual(r.new_value_formatted, 'strength') |
|||
|
|||
def test_many2many_tracking_value(self): |
|||
r = self.model.create({ |
|||
'mail_message_id': self.msg.id, |
|||
'field_type': 'many2many', |
|||
'old_value_char': '123', |
|||
'new_value_char': '456', |
|||
'field': 'test', |
|||
'field_desc': 'desc', |
|||
}) |
|||
self.assertEqual(r.old_value_formatted, '123') |
|||
self.assertEqual(r.new_value_formatted, '456') |
|||
|
|||
def test_one2many_tracking_value(self): |
|||
r = self.model.create({ |
|||
'mail_message_id': self.msg.id, |
|||
'field_type': 'one2many', |
|||
'old_value_char': '123', |
|||
'new_value_char': '456', |
|||
'field': 'test', |
|||
'field_desc': 'desc', |
|||
}) |
|||
self.assertEqual(r.old_value_formatted, '123') |
|||
self.assertEqual(r.new_value_formatted, '456') |
|||
|
|||
def test_integer_tracking_value(self): |
|||
r = self.model.create({ |
|||
'mail_message_id': self.msg.id, |
|||
'field_type': 'integer', |
|||
'old_value_integer': 1, |
|||
'new_value_integer': 3, |
|||
'field': 'test', |
|||
'field_desc': 'desc', |
|||
}) |
|||
self.assertEqual(r.old_value_formatted, str(1)) |
|||
self.assertEqual(r.new_value_formatted, str(3)) |
|||
|
|||
def test_float_tracking_value(self): |
|||
r = self.model.create({ |
|||
'mail_message_id': self.msg.id, |
|||
'field_type': 'float', |
|||
'old_value_float': 1.1, |
|||
'new_value_float': 3.14159, |
|||
'field': 'test', |
|||
'field_desc': 'desc', |
|||
}) |
|||
self.assertEqual(r.old_value_formatted, str(1.1)) |
|||
self.assertEqual(r.new_value_formatted, str(3.14159)) |
|||
|
|||
def test_monetary_tracking_value(self): |
|||
r = self.model.create({ |
|||
'mail_message_id': self.msg.id, |
|||
'field_type': 'monetary', |
|||
'old_value_monetary': 3.45, |
|||
'new_value_monetary': 5.45, |
|||
'field': 'test', |
|||
'field_desc': 'desc', |
|||
}) |
|||
self.assertEqual(r.old_value_formatted, str(3.45)) |
|||
self.assertEqual(r.new_value_formatted, str(5.45)) |
|||
|
|||
def test_datetime_tracking_value(self): |
|||
r = self.model.create({ |
|||
'mail_message_id': self.msg.id, |
|||
'field_type': 'datetime', |
|||
'old_value_datetime': '2018-01-01', |
|||
'new_value_datetime': '2018-01-04', |
|||
'field': 'test', |
|||
'field_desc': 'desc', |
|||
}) |
|||
self.assertEqual(r.old_value_formatted, '2018-01-01 00:00:00') |
|||
self.assertEqual(r.new_value_formatted, '2018-01-04 00:00:00') |
|||
|
|||
def test_text_tracking_value(self): |
|||
r = self.model.create({ |
|||
'mail_message_id': self.msg.id, |
|||
'field_type': 'text', |
|||
'old_value_text': 'previous', |
|||
'new_value_text': 'next', |
|||
'field': 'test', |
|||
'field_desc': 'desc', |
|||
}) |
|||
self.assertEqual(r.old_value_formatted, 'previous') |
|||
self.assertEqual(r.new_value_formatted, 'next') |
@ -0,0 +1,74 @@ |
|||
<?xml version="1.0" encoding="utf-8"?> |
|||
<odoo> |
|||
|
|||
<record id="tracking_change_list" model="ir.ui.view"> |
|||
<field name="name">Tracking change list"</field> |
|||
<field name="model">mail.tracking.value</field> |
|||
<field name="arch" type="xml"> |
|||
<tree string="Tracking change list" default_order="create_date desc" |
|||
create="false" edit="false" delete="false"> |
|||
<field name="create_date" string="On"/> |
|||
<field name="record_name" string="For"/> |
|||
<field name="field_desc" string="Field changed"/> |
|||
<field name="old_value_formatted"/> |
|||
<field name="new_value_formatted"/> |
|||
<field name="model"/> |
|||
</tree> |
|||
</field> |
|||
</record> |
|||
|
|||
<record id="tracking_change_form_view" model="ir.ui.view"> |
|||
<field name="name">Tracking change form</field> |
|||
<field name="model">mail.tracking.value</field> |
|||
<field name="priority" eval="20"/> |
|||
<field name="arch" type="xml"> |
|||
<form> |
|||
<sheet> |
|||
<field name="create_date" class="oe-inline"/> |
|||
<group> |
|||
<group string=""> |
|||
<field name="record_name" string="For"/> |
|||
<field name="field_desc" string="Field changed"/> |
|||
<field name="old_value_formatted"/> |
|||
<field name="new_value_formatted"/> |
|||
<field name="model"/> |
|||
</group> |
|||
</group> |
|||
</sheet> |
|||
</form> |
|||
</field> |
|||
</record> |
|||
|
|||
<record id="tracking_change_list_filter" model="ir.ui.view"> |
|||
<field name="name">Tracking change list filter</field> |
|||
<field name="model">mail.tracking.value</field> |
|||
<field name="arch" type="xml"> |
|||
<search string="Search"> |
|||
<group> |
|||
<field name="model"/> |
|||
</group> |
|||
<group expand="0" string="Group by"> |
|||
<filter group_by="group_by_model" string="Model" context="{'group_by':'model'}"/> |
|||
</group> |
|||
</search> |
|||
</field> |
|||
</record> |
|||
|
|||
<record id="action_view_tracking_changes" model="ir.actions.act_window"> |
|||
<field name="name">View last tracked changes</field> |
|||
<field name="res_model">mail.tracking.value</field> |
|||
<field name="view_mode">tree,form</field> |
|||
<field name="view_ids" eval="[(5, 0, 0), |
|||
(0, 0, {'view_mode': 'tree', 'view_id': ref('tracking_change_list')}), |
|||
(0, 0, {'view_mode': 'form', 'view_id': ref('tracking_change_form_view')})]" |
|||
/> |
|||
</record> |
|||
|
|||
<menuitem action="action_view_tracking_changes" |
|||
id ="menu_action_view_tracking_changes" |
|||
name="Improved tracking values" |
|||
parent="base.menu_email" |
|||
sequence="10" |
|||
/> |
|||
|
|||
</odoo> |
Write
Preview
Loading…
Cancel
Save
Reference in new issue