[MERGE] mail, crm: improve monetary tracking field

# Purpose

Add the currency symbol in the message for the monetary tracking field.

For example, if we have a record with a monetary field displaying
"$ 500". If we modify the currency and the value to have "450 €",
the message containing the tracking values will display:
"500 € -> 450 €".

# Specifications

Add the currency symbol for the monetary tracking field to better
represent the change of a monetary field.
The currency will be fetch from the currency defined in the
monetary field or on the record's company in case there is not.

We only use one field to track the currency of a monetary field.
Indeed, in the case where the currency is changed with the value
of a monetary field, only the new currency is tracked. We focus
on the fact that the more important thing is the new value.

Furthermore, when modifying a currency of a monetary field, the
user can already see the new currency before saving the changes.
This allows him to adapt the value of the field if he needs it.
(N.B. we assume that this case will happen very rarely)

Using only one field takes also into account that there are
millions of record for this model and adding a new field would
take a lot of memory.

task-2387268
odoo/upgrade#2060

closes odoo/odoo#61999

Signed-off-by: Thibault Delavallee (tde) <tde@openerp.com>
This commit is contained in:
Odoo's Mergebot
2021-02-02 10:40:44 +01:00
committed by GitHub
11 changed files with 134 additions and 2 deletions
+1 -1
View File
@@ -147,7 +147,7 @@ class Lead(models.Model):
# Revenues
expected_revenue = fields.Monetary('Expected Revenue', currency_field='company_currency', tracking=True)
prorated_revenue = fields.Monetary('Prorated Revenue', currency_field='company_currency', store=True, compute="_compute_prorated_revenue")
recurring_revenue = fields.Monetary('Recurring Revenues', currency_field='company_currency', groups="crm.group_use_recurring_revenues")
recurring_revenue = fields.Monetary('Recurring Revenues', currency_field='company_currency', groups="crm.group_use_recurring_revenues", tracking=True)
recurring_plan = fields.Many2one('crm.recurring.plan', string="Recurring Plan", groups="crm.group_use_recurring_revenues")
recurring_revenue_monthly = fields.Monetary('Expected MRR', currency_field='company_currency', store=True,
compute="_compute_recurring_revenue_monthly",
+1
View File
@@ -985,6 +985,7 @@ class Message(models.Model):
'old_value': tracking.get_old_display_value()[0],
'new_value': tracking.get_new_display_value()[0],
'field_type': tracking.field_type,
'currency_id': tracking.currency_id.id,
})
vals.update({
@@ -31,6 +31,9 @@ class MailTracking(models.Model):
new_value_text = fields.Text('New Value Text', readonly=1)
new_value_datetime = fields.Datetime('New Value Datetime', readonly=1)
currency_id = fields.Many2one('res.currency', 'Currency', readonly=True, ondelete='set null',
help="Used to display the currency when tracking monetary values")
mail_message_id = fields.Many2one('mail.message', 'Message ID', required=True, index=True, ondelete='cascade')
tracking_sequence = fields.Integer('Tracking field sequence', readonly=1, default=100)
+2
View File
@@ -46,6 +46,8 @@ class BaseModel(models.AbstractModel):
tracking_sequence = 100
tracking = self.env['mail.tracking.value'].create_tracking_values(initial_value, new_value, col_name, col_info, tracking_sequence, self._name)
if tracking:
if tracking['field_type'] == 'monetary':
tracking['currency_id'] = getattr(self, col_info.get('currency_field', ''), self.company_id.currency_id).id
tracking_value_ids.append([0, 0, tracking])
changes.add(col_name)
@@ -15,6 +15,7 @@ const useStore = require('mail/static/src/component_hooks/use_store/use_store.js
const useUpdate = require('mail/static/src/component_hooks/use_update/use_update.js');
const { _lt } = require('web.core');
const { format } = require('web.field_utils');
const { getLangDatetimeFormat } = require('web.time');
const { Component, useState } = owl;
@@ -310,6 +311,14 @@ class Message extends Component {
if (value.new_value !== undefined){
value.new_value = value.new_value ? this.env._t("True") : this.env._t("False");
}
} else if (value.field_type === 'monetary' && value.currency_id) {
const currency_id = this.env.session.currencies[value.currency_id]
if (value.old_value !== undefined) {
value.old_value = format.monetary(value.old_value, null, { currency: currency_id, forceString: true });
}
if (value.new_value !== undefined) {
value.new_value = format.monetary(value.new_value, null, { currency: currency_id, forceString: true });
}
}
return value;
});
@@ -1212,6 +1212,71 @@ QUnit.test('rendering of tracked field with change of value from empty to string
);
});
QUnit.test('basic rendering of tracking value (monetary type)', async function (assert) {
assert.expect(8);
await this.start({
env: {
session: {
currencies: { 1: { symbol: '$', position: 'before' } },
},
},
});
const message = this.env.models['mail.message'].create({
id: 11,
tracking_value_ids: [{
changed_field: "Revenue",
currency_id: 1,
field_type: "monetary",
id: 6,
new_value: 500,
old_value: 1000,
}],
});
await this.createMessageComponent(message);
assert.containsOnce(
document.body,
'.o_Message_trackingValue',
"should display a tracking value"
);
assert.containsOnce(
document.body,
'.o_Message_trackingValueFieldName',
"should display the name of the tracked field"
);
assert.strictEqual(
document.querySelector('.o_Message_trackingValueFieldName').textContent,
"Revenue:",
"should display the correct tracked field name (Revenue)",
);
assert.containsOnce(
document.body,
'.o_Message_trackingValueOldValue',
"should display the old value"
);
assert.strictEqual(
document.querySelector('.o_Message_trackingValueOldValue').innerHTML,
"$ 1000.00",
"should display the correct old value with the currency symbol ($ 1000.00)",
);
assert.containsOnce(
document.body,
'.o_Message_trackingValueSeparator',
"should display the separator"
);
assert.containsOnce(
document.body,
'.o_Message_trackingValueNewValue',
"should display the new value"
);
assert.strictEqual(
document.querySelector('.o_Message_trackingValueNewValue').innerHTML,
"$ 500.00",
"should display the correct new value with the currency symbol ($ 500.00)",
);
});
});
});
});
+3
View File
@@ -662,6 +662,9 @@ class MailCase(MockEmail):
self.assertEqual(tracking.new_value_integer, new_value and new_value.id or False)
self.assertEqual(tracking.old_value_char, old_value and old_value.display_name or '')
self.assertEqual(tracking.new_value_char, new_value and new_value.display_name or '')
elif value_type in ('monetary'):
self.assertEqual(tracking.old_value_monetary, old_value)
self.assertEqual(tracking.new_value_monetary, new_value)
else:
self.assertEqual(1, 0)
@@ -42,6 +42,15 @@ class MailTestTrackCompute(models.Model):
partner_email = fields.Char(related='partner_id.email', store=True, tracking=True)
partner_phone = fields.Char(related='partner_id.phone', tracking=True)
class MailTestTrackMonetary(models.Model):
_name = 'mail.test.track.monetary'
_description = 'Test tracking monetary field'
_inherit = ['mail.thread']
company_id = fields.Many2one('res.company')
company_currency = fields.Many2one("res.currency", string='Currency', related='company_id.currency_id', readonly=True, tracking=True)
revenue = fields.Monetary('Revenue', currency_field='company_currency', tracking=True)
class MailTestMultiCompany(models.Model):
""" This model can be used in multi company tests"""
@@ -18,3 +18,4 @@ access_mail_test_cc_user,mail.test.cc.user,model_mail_test_cc,base.group_user,1,
access_mail_test_multi_company_user,mail.test.multi.company.user,model_mail_test_multi_company,base.group_user,1,1,1,1
access_mail_test_multi_company_portal,mail.test.multi.company.portal,model_mail_test_multi_company,base.group_portal,1,0,0,0
access_mail_test_track_compute,mail.test.track.compute,model_mail_test_track_compute,base.group_user,1,1,1,1
access_mail_test_track_monetary,mail.test.track.monetary,model_mail_test_track_monetary,base.group_user,1,1,1,1
1 id name model_id:id group_id:id perm_read perm_write perm_create perm_unlink
18 access_mail_test_multi_company_user mail.test.multi.company.user model_mail_test_multi_company base.group_user 1 1 1 1
19 access_mail_test_multi_company_portal mail.test.multi.company.portal model_mail_test_multi_company base.group_portal 1 0 0 0
20 access_mail_test_track_compute mail.test.track.compute model_mail_test_track_compute base.group_user 1 1 1 1
21 access_mail_test_track_monetary mail.test.track.monetary model_mail_test_track_monetary base.group_user 1 1 1 1
+1
View File
@@ -43,6 +43,7 @@ class TestMailMultiCompanyCommon(MailCommon):
super(TestMailMultiCompanyCommon, cls).setUpClass()
cls.company_2 = cls.env['res.company'].create({
'name': 'Second Test Company',
'currency_id': 2,
})
+39 -1
View File
@@ -3,7 +3,7 @@
from unittest.mock import patch
from odoo.addons.test_mail.tests.common import TestMailCommon
from odoo.addons.test_mail.tests.common import TestMailCommon, TestMailMultiCompanyCommon
from odoo.tests.common import tagged
from odoo.tests import Form
@@ -283,6 +283,44 @@ class TestTracking(TestMailCommon):
('partner_email', 'char', 'foo@example.com', 'bar@example.com'),
])
@tagged('mail_track')
class TestTrackingMonetary(TestMailMultiCompanyCommon):
def setUp(self):
super(TestTrackingMonetary, self).setUp()
record = self.env['mail.test.track.monetary'].with_user(self.user_employee).with_context(self._test_context).create({
'company_id': self.user_employee.company_id.id,
})
self.flush_tracking()
self.record = record.with_context(mail_notrack=False)
def test_message_track_monetary(self):
""" Update a record with a tracked monetary field """
# Check if the tracking value have the correct currency and values
self.record.write({
'revenue': 100,
})
self.flush_tracking()
self.assertEqual(len(self.record.message_ids), 1)
self.assertTracking(self.record.message_ids[0], [
('revenue', 'monetary', 0, 100),
])
# Check if the tracking value have the correct currency and values after changing the value and the company
self.record.write({
'revenue': 200,
'company_id': self.company_2.id,
})
self.flush_tracking()
self.assertEqual(len(self.record.message_ids), 2)
self.assertTracking(self.record.message_ids[0], [
('revenue', 'monetary', 100, 200),
('company_currency', 'many2one', self.user_employee.company_id.currency_id, self.company_2.currency_id)
])
@tagged('mail_track')
class TestTrackingInternals(TestMailCommon):