[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:
@@ -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",
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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)",
|
||||
);
|
||||
});
|
||||
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -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
|
||||
|
||||
|
@@ -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,
|
||||
})
|
||||
|
||||
|
||||
|
||||
@@ -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):
|
||||
|
||||
Reference in New Issue
Block a user