From 04a6b74d096ba63c9b046faec7849547c586596f Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Thibault=20Delavall=C3=A9e?=
Date: Fri, 9 Dec 2022 15:40:34 +0000
Subject: [PATCH 01/45] [FIX] mail, various: update query counters
Update counters according to latest runbot counters. It allows to better spot
side effects of upcoming changes.
Task-2710804 (Mail: Clean MailThread Posting API)
Part-of: odoo/odoo#99482
---
addons/crm/tests/test_crm_lead_convert_mass.py | 6 +++---
addons/crm/tests/test_performances.py | 2 +-
addons/google_calendar/tests/test_sync_odoo2google.py | 8 ++++----
addons/hr_holidays/tests/test_company_leave.py | 2 +-
.../hr_work_entry_holidays/tests/test_performance.py | 10 +++++-----
addons/sale_stock/tests/test_create_perf.py | 8 ++++----
addons/test_mass_mailing/tests/test_performance.py | 8 ++++----
odoo/addons/base/tests/test_ir_actions.py | 2 +-
odoo/addons/base/tests/test_res_users.py | 10 +++++-----
odoo/addons/test_new_api/tests/test_new_fields.py | 4 ++--
10 files changed, 30 insertions(+), 30 deletions(-)
diff --git a/addons/crm/tests/test_crm_lead_convert_mass.py b/addons/crm/tests/test_crm_lead_convert_mass.py
index a39dec8e285..09c365cf8e3 100644
--- a/addons/crm/tests/test_crm_lead_convert_mass.py
+++ b/addons/crm/tests/test_crm_lead_convert_mass.py
@@ -24,7 +24,7 @@ class TestLeadConvertMass(crm_common.TestLeadConvertMassCommon):
with self.assertQueryCount(user_sales_manager=0):
test_leads = self.env['crm.lead'].browse(test_leads.ids)
- with self.assertQueryCount(user_sales_manager=543): # crm 537 / com 543 / ent 537
+ with self.assertQueryCount(user_sales_manager=543): # crm 537 / com 541 / ent 536
test_leads._handle_salesmen_assignment(user_ids=user_ids, team_id=False)
self.assertEqual(test_leads.team_id, self.sales_team_convert | self.sales_team_1)
@@ -42,7 +42,7 @@ class TestLeadConvertMass(crm_common.TestLeadConvertMassCommon):
with self.assertQueryCount(user_sales_manager=0):
test_leads = self.env['crm.lead'].browse(test_leads.ids)
- with self.assertQueryCount(user_sales_manager=524): # crm 521 / com 524
+ with self.assertQueryCount(user_sales_manager=524): # crm 521 / com 516 / ent 516
test_leads._handle_salesmen_assignment(user_ids=user_ids, team_id=team_id)
self.assertEqual(test_leads.team_id, self.sales_team_convert)
@@ -167,7 +167,7 @@ class TestLeadConvertMass(crm_common.TestLeadConvertMassCommon):
user_ids = self.assign_users.ids
# randomness: at least 1 query
- with self.assertQueryCount(user_sales_manager=1704): # crm 1410 / com 1697
+ with self.assertQueryCount(user_sales_manager=1704): # crm 1410 / com 1677 / ent 1685
mass_convert = self.env['crm.lead2opportunity.partner.mass'].with_context({
'active_model': 'crm.lead',
'active_ids': test_leads.ids,
diff --git a/addons/crm/tests/test_performances.py b/addons/crm/tests/test_performances.py
index 067f7b483b7..7f2500f4d9b 100644
--- a/addons/crm/tests/test_performances.py
+++ b/addons/crm/tests/test_performances.py
@@ -178,7 +178,7 @@ class TestLeadAssignPerf(TestLeadAssignCommon):
# randomness
with self.with_user('user_sales_manager'):
- with self.assertQueryCount(user_sales_manager=6280): # crm 6226 / com 6276 / ent 6278
+ with self.assertQueryCount(user_sales_manager=6280): # crm 6226 / com 6212 / ent 6214
self.env['crm.team'].browse(sales_teams.ids)._action_assign_leads(work_days=30)
# teams assign
diff --git a/addons/google_calendar/tests/test_sync_odoo2google.py b/addons/google_calendar/tests/test_sync_odoo2google.py
index f14de26f1f3..f4a144cbd21 100644
--- a/addons/google_calendar/tests/test_sync_odoo2google.py
+++ b/addons/google_calendar/tests/test_sync_odoo2google.py
@@ -71,7 +71,7 @@ class TestSyncOdoo2Google(TestSyncGoogle):
})
partner_model = self.env.ref('base.model_res_partner')
partner = self.env['res.partner'].search([], limit=1)
- with self.assertQueryCount(__system__=616):
+ with self.assertQueryCount(__system__=615):
events = self.env['calendar.event'].create([{
'name': "Event %s" % (i),
'start': datetime(2020, 1, 15, 8, 0),
@@ -86,7 +86,7 @@ class TestSyncOdoo2Google(TestSyncGoogle):
events._sync_odoo2google(self.google_service)
- with self.assertQueryCount(__system__=130):
+ with self.assertQueryCount(__system__=126):
events.unlink()
@@ -103,7 +103,7 @@ class TestSyncOdoo2Google(TestSyncGoogle):
})
partner_model = self.env.ref('base.model_res_partner')
partner = self.env['res.partner'].search([], limit=1)
- with self.assertQueryCount(__system__=72):
+ with self.assertQueryCount(__system__=56):
event = self.env['calendar.event'].create({
'name': "Event",
'start': datetime(2020, 1, 15, 8, 0),
@@ -120,7 +120,7 @@ class TestSyncOdoo2Google(TestSyncGoogle):
'res_id': partner.id,
})
- with self.assertQueryCount(__system__=35):
+ with self.assertQueryCount(__system__=31):
event.unlink()
def test_event_without_user(self):
diff --git a/addons/hr_holidays/tests/test_company_leave.py b/addons/hr_holidays/tests/test_company_leave.py
index 4f1b7dce92b..78aa100f6e0 100644
--- a/addons/hr_holidays/tests/test_company_leave.py
+++ b/addons/hr_holidays/tests/test_company_leave.py
@@ -323,7 +323,7 @@ class TestCompanyLeave(TransactionCase):
})
company_leave._compute_date_from_to()
- with self.assertQueryCount(__system__=774, admin=867): # 770 community
+ with self.assertQueryCount(__system__=605, admin=867): # 770 community
# Original query count: 1987
# Without tracking/activity context keys: 5154
company_leave.action_validate()
diff --git a/addons/hr_work_entry_holidays/tests/test_performance.py b/addons/hr_work_entry_holidays/tests/test_performance.py
index 869afade403..996b7b2e336 100644
--- a/addons/hr_work_entry_holidays/tests/test_performance.py
+++ b/addons/hr_work_entry_holidays/tests/test_performance.py
@@ -32,7 +32,7 @@ class TestWorkEntryHolidaysPerformance(TestWorkEntryHolidaysBase):
self.richard_emp.generate_work_entries(date(2018, 1, 1), date(2018, 1, 2))
leave = self.create_leave(datetime(2018, 1, 1, 7, 0), datetime(2018, 1, 1, 18, 0))
- with self.assertQueryCount(__system__=93, admin=94):
+ with self.assertQueryCount(__system__=79, admin=81):
leave.action_validate()
leave.action_refuse()
@@ -41,14 +41,14 @@ class TestWorkEntryHolidaysPerformance(TestWorkEntryHolidaysBase):
def test_performance_leave_write(self):
leave = self.create_leave(datetime(2018, 1, 1, 7, 0), datetime(2018, 1, 1, 18, 0))
- with self.assertQueryCount(__system__=21, admin=30):
+ with self.assertQueryCount(__system__=19, admin=27):
leave.date_to = datetime(2018, 1, 1, 19, 0)
leave.action_refuse()
@users('__system__', 'admin')
@warmup
def test_performance_leave_create(self):
- with self.assertQueryCount(__system__=31, admin=32): # 25/26 com
+ with self.assertQueryCount(__system__=29, admin=30):
leave = self.create_leave(datetime(2018, 1, 1, 7, 0), datetime(2018, 1, 1, 18, 0))
leave.action_refuse()
@@ -57,7 +57,7 @@ class TestWorkEntryHolidaysPerformance(TestWorkEntryHolidaysBase):
def test_performance_leave_confirm(self):
leave = self.create_leave(datetime(2018, 1, 1, 7, 0), datetime(2018, 1, 1, 18, 0))
leave.action_draft()
- with self.assertQueryCount(__system__=28, admin=29):
+ with self.assertQueryCount(__system__=25, admin=26):
leave.action_confirm()
leave.state = 'refuse'
@@ -112,7 +112,7 @@ class TestWorkEntryHolidaysPerformancesBigData(TestWorkEntryHolidaysBase):
def test_work_entries_generation_perf(self):
# Test Case 7: Try to generate work entries for
# a hundred employees over a month
- with self.assertQueryCount(__system__=2607, admin=2807):
+ with self.assertQueryCount(__system__=500, admin=2807):
work_entries = self.contracts._generate_work_entries(date(2020, 7, 1), date(2020, 8, 31))
# Original work entries to generate when we don't adapt date_generated_from and
diff --git a/addons/sale_stock/tests/test_create_perf.py b/addons/sale_stock/tests/test_create_perf.py
index ca9adce165f..7010c50d3ac 100644
--- a/addons/sale_stock/tests/test_create_perf.py
+++ b/addons/sale_stock/tests/test_create_perf.py
@@ -38,7 +38,7 @@ class TestPERF(common.TransactionCase):
@users('admin')
@warmup
def test_empty_sale_order_creation_perf(self):
- with self.assertQueryCount(admin=34):
+ with self.assertQueryCount(admin=33):
self.env['sale.order'].create({
'partner_id': self.partners[0].id,
'user_id': self.salesmans[0].id,
@@ -52,7 +52,7 @@ class TestPERF(common.TransactionCase):
# + 1 warehouse fetch
# + 1 query to get analytic default account
# + 1 followers queries ?
- with self.assertQueryCount(admin=39):
+ with self.assertQueryCount(admin=37):
self.env['sale.order'].create([{
'partner_id': self.partners[0].id,
'user_id': self.salesmans[0].id,
@@ -63,7 +63,7 @@ class TestPERF(common.TransactionCase):
def test_dummy_sales_orders_batch_creation_perf(self):
""" Dummy SOlines (notes/sections) should not add any custom queries other than their insert"""
# + 2 SOL (batched) insert
- with self.assertQueryCount(admin=41):
+ with self.assertQueryCount(admin=39):
self.env['sale.order'].create([{
'partner_id': self.partners[0].id,
'user_id': self.salesmans[0].id,
@@ -80,7 +80,7 @@ class TestPERF(common.TransactionCase):
# + 2 SQL insert
# + 2 queries to get analytic default tags
# + 9 follower queries ?
- with self.assertQueryCount(admin=52):
+ with self.assertQueryCount(admin=49):
self.env['sale.order'].create([{
'partner_id': self.partners[0].id,
'user_id': self.salesmans[0].id,
diff --git a/addons/test_mass_mailing/tests/test_performance.py b/addons/test_mass_mailing/tests/test_performance.py
index 6c9fbf5e992..4e48a20cac8 100644
--- a/addons/test_mass_mailing/tests/test_performance.py
+++ b/addons/test_mass_mailing/tests/test_performance.py
@@ -47,14 +47,14 @@ class TestMassMailPerformance(TestMassMailPerformanceBase):
})
# runbot needs +2 compared to local
- with self.assertQueryCount(__system__=426, marketing=427): # tm 423/424
+ with self.assertQueryCount(__system__=425, marketing=426): # tm 423/424
mailing.action_send_mail()
self.assertEqual(mailing.sent, 50)
self.assertEqual(mailing.delivered, 50)
# runbot needs +3 compared to local
- with self.assertQueryCount(__system__=69, marketing=67): # tm 66/66
+ with self.assertQueryCount(__system__=68, marketing=67): # tm 66/66
self.env['mail.mail'].sudo().search([('to_delete', '=', True)]).unlink()
mails = self.env['mail.mail'].sudo().search([('mailing_id', '=', mailing.id)])
@@ -94,14 +94,14 @@ class TestMassMailBlPerformance(TestMassMailPerformanceBase):
})
# runbot needs +2 compared to local
- with self.assertQueryCount(__system__=488, marketing=489): # tm 485/486
+ with self.assertQueryCount(__system__=487, marketing=488): # tm 485/486
mailing.action_send_mail()
self.assertEqual(mailing.sent, 50)
self.assertEqual(mailing.delivered, 50)
# runbot needs +3 compared to local
- with self.assertQueryCount(__system__=69, marketing=67): # tm 66/66
+ with self.assertQueryCount(__system__=68, marketing=67): # tm 66/66
self.env['mail.mail'].sudo().search([('to_delete', '=', True)]).unlink()
cancelled_mail_count = self.env['mail.mail'].sudo().search([('mailing_id', '=', mailing.id)])
diff --git a/odoo/addons/base/tests/test_ir_actions.py b/odoo/addons/base/tests/test_ir_actions.py
index a6f5b81999e..616bcfee551 100644
--- a/odoo/addons/base/tests/test_ir_actions.py
+++ b/odoo/addons/base/tests/test_ir_actions.py
@@ -536,7 +536,7 @@ class TestCustomFields(common.TransactionCase):
# create a non-computed field, and assert how many queries it takes
model_id = self.env['ir.model']._get_id('res.partner')
- query_count = 41
+ query_count = 40
with self.assertQueryCount(query_count):
self.env.registry.clear_caches()
self.env['ir.model.fields'].create({
diff --git a/odoo/addons/base/tests/test_res_users.py b/odoo/addons/base/tests/test_res_users.py
index 5eacb4791c7..4b6fa13b4c9 100644
--- a/odoo/addons/base/tests/test_res_users.py
+++ b/odoo/addons/base/tests/test_res_users.py
@@ -405,7 +405,7 @@ class TestUsersGroupWarning(TransactionCase):
# 97 requests if only base is installed
# 412 runbot community
# 549 runbot enterprise
- with self.assertQueryCount(__system__=549), \
+ with self.assertQueryCount(__system__=436), \
Form(self.test_group_user.with_context(show_user_group_warning=True), view='base.view_users_form') as UserForm:
UserForm._values[self.sales_categ_field] = False
UserForm._perform_onchange([self.sales_categ_field])
@@ -427,7 +427,7 @@ class TestUsersGroupWarning(TransactionCase):
# 97 requests if only base is installed
# 412 runbot community
# 549 runbot enterprise
- with self.assertQueryCount(__system__=549), \
+ with self.assertQueryCount(__system__=436), \
Form(self.test_group_user.with_context(show_user_group_warning=True), view='base.view_users_form') as UserForm:
UserForm._values[self.sales_categ_field] = self.group_sales_user.id
UserForm._perform_onchange([self.sales_categ_field])
@@ -451,7 +451,7 @@ class TestUsersGroupWarning(TransactionCase):
# 101 requests if only base is installed
# 416 runbot community
# 553 runbot enterprise
- with self.assertQueryCount(__system__=553), \
+ with self.assertQueryCount(__system__=438), \
Form(self.test_group_user.with_context(show_user_group_warning=True), view='base.view_users_form') as UserForm:
UserForm._values[self.sales_categ_field] = self.group_sales_user.id
UserForm._values[self.project_categ_field] = self.group_project_user.id
@@ -479,7 +479,7 @@ class TestUsersGroupWarning(TransactionCase):
# 98 requests if only base is installed
# 413 runbot community
# 550 runbot enterprise
- with self.assertQueryCount(__system__=550), \
+ with self.assertQueryCount(__system__=437), \
Form(self.test_group_user.with_context(show_user_group_warning=True), view='base.view_users_form') as UserForm:
UserForm._values[self.timesheets_categ_field] = self.group_timesheets_user_own_timesheet.id
UserForm._perform_onchange([self.timesheets_categ_field])
@@ -500,7 +500,7 @@ class TestUsersGroupWarning(TransactionCase):
# 83 requests if only base is installed
# 397 runbot community
# 534 runbot enterprise
- with self.assertQueryCount(__system__=534), \
+ with self.assertQueryCount(__system__=420), \
Form(self.test_group_user.with_context(show_user_group_warning=True), view='base.view_users_form') as UserForm:
UserForm._values[self.field_service_categ_field] = self.group_field_service_user.id
UserForm._perform_onchange([self.field_service_categ_field])
diff --git a/odoo/addons/test_new_api/tests/test_new_fields.py b/odoo/addons/test_new_api/tests/test_new_fields.py
index 9af27961535..94c6269d160 100644
--- a/odoo/addons/test_new_api/tests/test_new_fields.py
+++ b/odoo/addons/test_new_api/tests/test_new_fields.py
@@ -3411,7 +3411,7 @@ class TestSelectionUpdates(common.TransactionCase):
self.env[self.MODEL_BASE].create({})
with self.assertQueryCount(1):
record = self.env[self.MODEL_BASE].create({'my_selection': 'foo'})
- with self.assertQueryCount(3): # SELECT, SELECT (related field), UPDATE
+ with self.assertQueryCount(1): # SELECT, SELECT (related field), UPDATE
record.my_selection = 'bar'
def test_selection_related_readonly(self):
@@ -3425,7 +3425,7 @@ class TestSelectionUpdates(common.TransactionCase):
related_record = self.env[self.MODEL_BASE].create({'my_selection': 'foo'})
with self.assertQueryCount(2): # defaults (related field), INSERT
record = self.env[self.MODEL_RELATED_UPDATE].create({'selection_id': related_record.id})
- with self.assertQueryCount(3):
+ with self.assertQueryCount(2):
record.related_selection = 'bar'
From 11906b776e1fc459d1b5eb9e4dc036e7627665d8 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Thibault=20Delavall=C3=A9e?=
Date: Tue, 13 Dec 2022 14:46:28 +0000
Subject: [PATCH 02/45] [FIX] mail: remove microseconds when parsing vague
datetime
Mail holds an helper function to convert datetime from a char input into a
datetime value. It is used notably when having to store a datetime value
(e.g. on a mail_mail) from a string generated by templates with expression
like ``{{ datetime.datetime.now() + datetime.timedelta(days=2)}}``.
In this commit we explicitly remove microseconds, as otherwise we end up with
something that the web client cannot parse, not speaking of even going into
server side storage with this value not matching the expected format.
Task-2710804 (Mail: Clean MailThread Posting API)
Part-of: odoo/odoo#99482
---
addons/mail/models/mail_mail.py | 1 +
1 file changed, 1 insertion(+)
diff --git a/addons/mail/models/mail_mail.py b/addons/mail/models/mail_mail.py
index 02f8edbb129..533821fffc8 100644
--- a/addons/mail/models/mail_mail.py
+++ b/addons/mail/models/mail_mail.py
@@ -309,6 +309,7 @@ class MailMail(models.Model):
except (ValueError, TypeError):
parsed_datetime = False
if parsed_datetime:
+ parsed_datetime = parsed_datetime.replace(microsecond=0)
if not parsed_datetime.tzinfo:
parsed_datetime = pytz.utc.localize(parsed_datetime)
else:
From 44a316275db8490d7ef2976c56d458453fbb94e4 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Thibault=20Delavall=C3=A9e?=
Date: Tue, 13 Dec 2022 14:48:58 +0000
Subject: [PATCH 03/45] [FIX] mail: avoid cache miss when opening the template
previewer
Sometimes the previewer crashes in rendering with cache-based records, hence
trying to check directly the id of the related reference record.
Task-2710804 (Mail: Clean MailThread Posting API)
Part-of: odoo/odoo#99482
---
addons/mail/wizard/mail_template_preview.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/addons/mail/wizard/mail_template_preview.py b/addons/mail/wizard/mail_template_preview.py
index 24ecbac2533..79644ce3e8f 100644
--- a/addons/mail/wizard/mail_template_preview.py
+++ b/addons/mail/wizard/mail_template_preview.py
@@ -72,7 +72,7 @@ class MailTemplatePreview(models.TransientModel):
copy_depends_values = {'lang': self.lang}
mail_template = self.mail_template_id.with_context(lang=self.lang)
try:
- if not self.resource_ref:
+ if not self.resource_ref.id:
self._set_mail_attributes()
else:
copy_depends_values['resource_ref'] = '%s,%s' % (self.resource_ref._name, self.resource_ref.id)
From 7b96e7cb22a873ddf3d5779b7c3febf5e974e74f Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Thibault=20Delavall=C3=A9e?=
Date: Tue, 13 Dec 2022 13:50:13 +0000
Subject: [PATCH 04/45] [FIX] mail: correctly display errors when previewing
templates
In this commit we correctly set 'error_msg' field as computed. As it was not
defined as computed, it was not really updated and therefore not displayed
in the preview form view. It is now the case.
ValueError are now also catched, for example when having badly configured
'partner_ids' field we may face this kind of error, which is now logged
in the preview wizard.
Task-2710804 (Mail: Clean MailThread Posting API)
Part-of: odoo/odoo#99482
---
addons/mail/wizard/mail_template_preview.py | 4 ++--
addons/mail/wizard/mail_template_preview_views.xml | 2 +-
2 files changed, 3 insertions(+), 3 deletions(-)
diff --git a/addons/mail/wizard/mail_template_preview.py b/addons/mail/wizard/mail_template_preview.py
index 79644ce3e8f..5916cabdc69 100644
--- a/addons/mail/wizard/mail_template_preview.py
+++ b/addons/mail/wizard/mail_template_preview.py
@@ -43,7 +43,7 @@ class MailTemplatePreview(models.TransientModel):
resource_ref = fields.Reference(string='Record', selection='_selection_target_model')
lang = fields.Selection(_selection_languages, string='Template Preview Language')
no_record = fields.Boolean('No Record', compute='_compute_no_record')
- error_msg = fields.Char('Error Message', readonly=True)
+ error_msg = fields.Char('Error Message', compute='_compute_mail_template_fields')
# Fields same than the mail.template model, computed with resource_ref and lang
subject = fields.Char('Subject', compute='_compute_mail_template_fields')
email_from = fields.Char('From', compute='_compute_mail_template_fields', help="Sender address")
@@ -82,7 +82,7 @@ class MailTemplatePreview(models.TransientModel):
)
self._set_mail_attributes(values=mail_values)
self.error_msg = False
- except UserError as user_error:
+ except (ValueError, UserError) as user_error:
self._set_mail_attributes()
self.error_msg = user_error.args[0]
finally:
diff --git a/addons/mail/wizard/mail_template_preview_views.xml b/addons/mail/wizard/mail_template_preview_views.xml
index 228c97956f5..90865d69061 100644
--- a/addons/mail/wizard/mail_template_preview_views.xml
+++ b/addons/mail/wizard/mail_template_preview_views.xml
@@ -8,7 +8,7 @@
-
- {{ (object.name or '').replace('/','-') }}
+ {{ object.partner_id.lang }}
@@ -129,8 +127,7 @@
-
- Credit_note_{{ (object.name or '').replace('/','_') }}{{ object.state == 'draft' and '_draft' or '' }}
+ {{ object.partner_id.lang }}
diff --git a/addons/event/data/mail_template_data.xml b/addons/event/data/mail_template_data.xml
index 1d5de71bdec..03d541a588d 100644
--- a/addons/event/data/mail_template_data.xml
+++ b/addons/event/data/mail_template_data.xml
@@ -22,8 +22,7 @@
-- Mitchell Admin
-
- Foldable Badge - {{ (object.event_id.name or 'Event').replace('/','_') }}
+ {{ object.partner_id.lang }}
@@ -254,8 +253,7 @@
-
- Full Page Ticket - {{ (object.event_id.name or 'Event').replace('/','') }}
+ {{ object.partner_id.lang }}
diff --git a/addons/loyalty/data/mail_template_data.xml b/addons/loyalty/data/mail_template_data.xml
index 4c4a8597811..bba70470e01 100644
--- a/addons/loyalty/data/mail_template_data.xml
+++ b/addons/loyalty/data/mail_template_data.xml
@@ -34,8 +34,7 @@
-
- Your Gift Card
+
@@ -96,8 +95,7 @@
-
- Your Coupon Code
+
diff --git a/addons/mail/models/mail_template.py b/addons/mail/models/mail_template.py
index 25c734bbac0..bccd11d813c 100644
--- a/addons/mail/models/mail_template.py
+++ b/addons/mail/models/mail_template.py
@@ -7,6 +7,7 @@ import logging
from odoo import _, api, fields, models, tools, Command
from odoo.exceptions import UserError
from odoo.tools import is_html_empty
+from odoo.tools.safe_eval import safe_eval, time
_logger = logging.getLogger(__name__)
@@ -63,10 +64,12 @@ class MailTemplate(models.Model):
'attachment_id', 'Attachments',
help="You may attach files to this template, to be added to all "
"emails created from this template")
- report_name = fields.Char('Report Filename', translate=True, prefetch=True,
- help="Name to use for the generated report file (may contain placeholders)\n"
- "The extension can be omitted and will then come from the report type.")
- report_template = fields.Many2one('ir.actions.report', 'Optional report to print and attach')
+ report_template_ids = fields.Many2many(
+ 'ir.actions.report', relation='mail_template_ir_actions_report_rel',
+ column1='mail_template_id',
+ column2='ir_actions_report_id',
+ string='Reports to print and attach',
+ domain="[('model', '=', model)]")
# options
mail_server_id = fields.Many2one('ir.mail_server', 'Outgoing Mail Server', readonly=False,
help="Optional preferred server for outgoing mails. If not set, the highest "
@@ -198,14 +201,14 @@ class MailTemplate(models.Model):
def _generate_template_attachments(self, res_ids, render_fields,
render_results=None):
""" Render attachments of template 'self', returning values for records
- given by 'res_ids'. Note that ``report_template`` returns values for
+ given by 'res_ids'. Note that ``report_template_ids`` returns values for
'attachments', as we have a list of tuple (report_name, base64 value)
for those reports. It is considered as being the job of callers to
transform those attachments into valid ``ir.attachment`` records.
:param list res_ids: list of record IDs on which template is rendered;
:param list render_fields: list of fields to render on template which
- are specific to attachments, e.g. attachment_ids or report_template;
+ are specific to attachments, e.g. attachment_ids or report_template_ids;
:param dict render_results: res_ids-based dictionary of render values.
For each res_id, a dict of values based on render_fields is given
@@ -215,6 +218,11 @@ class MailTemplate(models.Model):
if render_results is None:
render_results = {}
+ # generating reports is done on a per-record basis, better ensure cache
+ # is filled up to avoid rendering and browsing in a loop
+ if res_ids and 'report_template_ids' in render_fields and self.report_template_ids:
+ self.env[self.model].browse(res_ids)
+
for res_id in res_ids:
values = render_results.setdefault(res_id, {})
@@ -223,27 +231,33 @@ class MailTemplate(models.Model):
values['attachment_ids'] = self.attachment_ids.ids
# generate attachments (reports)
- if 'report_template' in render_fields and self.report_template:
- report = self.report_template
-
- if report.report_type in ['qweb-html', 'qweb-pdf']:
- report_content, report_format = self.env['ir.actions.report']._render_qweb_pdf(report, [res_id])
- else:
- render_res = self.env['ir.actions.report']._render(report, [res_id])
- if not render_res:
- raise UserError(_('Unsupported report type %s found.', report.report_type))
- report_content, report_format = render_res
- report_content = base64.b64encode(report_content)
-
- report_name = self._render_field('report_name', [res_id])[res_id]
- if not report_name:
- report_name = 'report.' + report.report_name
- ext = "." + report_format
- if not report_name.endswith(ext):
- report_name += ext
-
- values['attachments'] = [(report_name, report_content)]
- elif 'report_template' in render_fields:
+ if 'report_template_ids' in render_fields and self.report_template_ids:
+ for report in self.report_template_ids:
+ # generate content
+ if report.report_type in ['qweb-html', 'qweb-pdf']:
+ report_content, report_format = self.env['ir.actions.report']._render_qweb_pdf(report, [res_id])
+ else:
+ render_res = self.env['ir.actions.report']._render(report, [res_id])
+ if not render_res:
+ raise UserError(_('Unsupported report type %s found.', report.report_type))
+ report_content, report_format = render_res
+ report_content = base64.b64encode(report_content)
+ # generate name
+ if report.print_report_name:
+ report_name = safe_eval(
+ report.print_report_name,
+ {
+ 'object': self.env[self.model].browse(res_id),
+ 'time': time,
+ }
+ )
+ else:
+ report_name = _('Report')
+ extension = "." + report_format
+ if not report_name.endswith(extension):
+ report_name += extension
+ values.setdefault('attachments', []).append((report_name, report_content))
+ elif 'report_template_ids' in render_fields:
values['attachments'] = []
# hook for attachments-specific computation, used currently only for accounting
@@ -436,7 +450,7 @@ class MailTemplate(models.Model):
'email_cc', # recipients
'email_to', # recipients
'partner_to', # recipients
- 'report_template', # attachments
+ 'report_template_ids', # attachments
'scheduled_date', # specific
# not rendered (static)
'auto_delete',
@@ -482,7 +496,7 @@ class MailTemplate(models.Model):
)
# generate attachments if requested
- if render_fields_set & {'attachment_ids', 'report_template'}:
+ if render_fields_set & {'attachment_ids', 'report_template_ids'}:
template._generate_template_attachments(
template_res_ids,
render_fields_set,
@@ -533,7 +547,7 @@ class MailTemplate(models.Model):
'model',
'partner_to',
'reply_to',
- 'report_template',
+ 'report_template_ids',
'res_id',
'scheduled_date',
'subject',
diff --git a/addons/mail/views/mail_template_views.xml b/addons/mail/views/mail_template_views.xml
index 021e0dde091..0be8580fb0d 100644
--- a/addons/mail/views/mail_template_views.xml
+++ b/addons/mail/views/mail_template_views.xml
@@ -79,8 +79,9 @@
-
-
+
@@ -102,7 +103,6 @@
-
@@ -112,7 +112,7 @@
mail.template
-
+
diff --git a/addons/mail/wizard/mail_compose_message.py b/addons/mail/wizard/mail_compose_message.py
index b92fdb65867..3914e6be9d2 100644
--- a/addons/mail/wizard/mail_compose_message.py
+++ b/addons/mail/wizard/mail_compose_message.py
@@ -284,7 +284,7 @@ class MailComposer(models.TransientModel):
'mail_server_id',
'partner_ids',
'reply_to',
- 'report_template',
+ 'report_template_ids',
'scheduled_date',
'subject',
)
@@ -709,7 +709,7 @@ class MailComposer(models.TransientModel):
'email_cc',
'mail_server_id',
'partner_ids',
- 'report_template',
+ 'report_template_ids',
'scheduled_date',
)
)
@@ -906,7 +906,7 @@ class MailComposer(models.TransientModel):
# some fields behave / are named differently on template model
mapping = {
- 'attachments': 'report_template',
+ 'attachments': 'report_template_ids',
'body': 'body_html',
'partner_ids': 'partner_to',
}
diff --git a/addons/mail/wizard/mail_template_preview.py b/addons/mail/wizard/mail_template_preview.py
index 14367e1e250..6eb21551de0 100644
--- a/addons/mail/wizard/mail_template_preview.py
+++ b/addons/mail/wizard/mail_template_preview.py
@@ -15,7 +15,7 @@ class MailTemplatePreview(models.TransientModel):
'email_from',
'email_to',
'partner_to',
- 'report_template',
+ 'report_template_ids',
'reply_to',
'scheduled_date',
]
@@ -94,9 +94,9 @@ class MailTemplatePreview(models.TransientModel):
def _set_mail_attributes(self, values=None):
for field in self._MAIL_TEMPLATE_FIELDS:
- if field in ('partner_to', 'report_template'):
+ if field in ('partner_to', 'report_template_ids'):
# partner_to is used to generate partner_ids, handled here below
- # report_template generates attachments, no usage here
+ # report_template_ids generates attachments, no usage here
continue
field_value = values.get(field, False) if values else self.mail_template_id[field]
self[field] = field_value
diff --git a/addons/purchase/data/mail_template_data.xml b/addons/purchase/data/mail_template_data.xml
index 0b348044df9..3dffc957249 100644
--- a/addons/purchase/data/mail_template_data.xml
+++ b/addons/purchase/data/mail_template_data.xml
@@ -30,8 +30,7 @@
-
- RFQ_{{ (object.name or '').replace('/','_') }}
+ {{ object.partner_id.lang }}
@@ -69,8 +68,7 @@