Skip to content
Snippets Groups Projects
Commit 018992fa authored by OCA Git Bot's avatar OCA Git Bot
Browse files

Merge remote-tracking branch 'odoo/14.0' into 14.0

parents 7edf648c dc0ccc19
No related branches found
No related tags found
No related merge requests found
......@@ -41,7 +41,7 @@
<template id="external_layout_din5008">
<div>
<div t-attf-class="header din_page o_company_#{company.id}_layout">
<table class="company_header">
<table class="company_header" t-att-style="'height: %dmm;' % (din_header_spacing or 27)">
<tr>
<td><h3 class="mt0" t-field="company.report_header"/></td>
<td><img t-if="company.logo" t-att-src="image_data_uri(company.logo)" t-att-style="'max-height: %dmm;' % (din_header_spacing or 27)"/></td>
......
.din_page {
margin-left: -1rem;
font-size: 9pt;
&.header {
margin-left: 10px;
table {
width: 100%;
img, h3, td, tr {
......@@ -22,8 +22,7 @@
}
&.invoice_note {
padding-top: 10px;
margin-left: 10px;
padding-top: 20px;
tr {
td {
vertical-align: bottom;
......@@ -86,7 +85,7 @@
}
}
&.footer {
margin-left: 10px;
padding-left: 5mm;
padding-right: 10mm;
.page_number {
margin-top: 4.23mm;
......
......@@ -470,36 +470,13 @@ class MassMailing(models.Model):
self.ensure_one()
target = self.env[self.mailing_model_real]
# avoid loading a large number of records in memory
# + use a basic heuristic for extracting emails
query = """
SELECT lower(substring(t.%(mail_field)s, '([^ ,;<@]+@[^> ,;]+)'))
SELECT s.email
FROM mailing_trace s
JOIN %(target)s t ON (s.res_id = t.id)
WHERE substring(t.%(mail_field)s, '([^ ,;<@]+@[^> ,;]+)') IS NOT NULL
WHERE s.email IS NOT NULL
"""
# Apply same 'get email field' rule from mail_thread.message_get_default_recipients
if 'partner_id' in target._fields and target._fields['partner_id'].store:
mail_field = 'email'
query = """
SELECT lower(substring(p.%(mail_field)s, '([^ ,;<@]+@[^> ,;]+)'))
FROM mailing_trace s
JOIN %(target)s t ON (s.res_id = t.id)
JOIN res_partner p ON (t.partner_id = p.id)
WHERE substring(p.%(mail_field)s, '([^ ,;<@]+@[^> ,;]+)') IS NOT NULL
"""
elif issubclass(type(target), self.pool['mail.thread.blacklist']):
mail_field = 'email_normalized'
elif 'email_from' in target._fields and target._fields['email_from'].store:
mail_field = 'email_from'
elif 'partner_email' in target._fields and target._fields['partner_email'].store:
mail_field = 'partner_email'
elif 'email' in target._fields and target._fields['email'].store:
mail_field = 'email'
else:
raise UserError(_("Unsupported mass mailing model %s", self.mailing_model_id.name))
if self.unique_ab_testing:
query += """
AND s.campaign_id = %%(mailing_campaign_id)s;
......@@ -509,8 +486,8 @@ class MassMailing(models.Model):
AND s.mass_mailing_id = %%(mailing_id)s
AND s.model = %%(target_model)s;
"""
query = query % {'target': target._table, 'mail_field': mail_field}
params = {'mailing_id': self.id, 'mailing_campaign_id': self.campaign_id.id, 'target_model': self.mailing_model_real}
query = query % {'target': target._table}
params = {'mailing_campaign_id': self.campaign_id.id, 'mailing_id': self.id, 'target_model': self.mailing_model_real}
self._cr.execute(query, params)
seen_list = set(m[0] for m in self._cr.fetchall())
_logger.info(
......
......@@ -10,7 +10,7 @@
</group>
<field name="show_productions" invisible="1"/>
<field name="immediate_production_line_ids" nolabel="1" attrs="{'invisible': [('show_productions', '=', False)]}">>
<field name="immediate_production_line_ids" nolabel="1" attrs="{'invisible': [('show_productions', '=', False)]}">
<tree create="0" delete="0" editable="top">
<field name="production_id"/>
<field name="to_immediate" widget="boolean_toggle"/>
......
......@@ -784,7 +784,7 @@ class ProductTemplate(models.Model):
if 'uom_id' in vals:
new_uom = self.env['uom.uom'].browse(vals['uom_id'])
updated = self.filtered(lambda template: template.uom_id != new_uom)
done_moves = self.env['stock.move'].search([('product_id', 'in', updated.with_context(active_test=False).mapped('product_variant_ids').ids)], limit=1)
done_moves = self.env['stock.move'].sudo().search([('product_id', 'in', updated.with_context(active_test=False).mapped('product_variant_ids').ids)], limit=1)
if done_moves:
raise UserError(_("You cannot change the unit of measure as there are already stock moves for this product. If you want to change the unit of measure, you should rather archive this product and create a new one."))
if 'type' in vals and vals['type'] != 'product' and sum(self.mapped('nbr_reordering_rules')) != 0:
......
......@@ -108,6 +108,16 @@ class MailingOptOut(models.Model):
}
return default_recipients
class MailingTestPartner(models.Model):
_description = 'Mailing Model with partner_id'
_name = 'mailing.test.partner'
_inherit = ['mail.thread.blacklist']
_primary_email = 'email_from'
name = fields.Char()
email_from = fields.Char()
partner_id = fields.Many2one('res.partner', 'Customer')
class MailingPerformance(models.Model):
""" A very simple model only inheriting from mail.thread to test pure mass
......
......@@ -11,6 +11,8 @@ access_mailing_performance_all,access.mailing.performance.all,model_mailing_perf
access_mailing_performance_user,access.mailing.performance.user,model_mailing_performance,base.group_user,1,1,1,1
access_mailing_performance_blacklist_all,access.mailing.performance.blacklist.all,model_mailing_performance_blacklist,,0,0,0,0
access_mailing_performance_blacklist_user,access.mailing.performance.blacklist.user,model_mailing_performance_blacklist,base.group_user,1,1,1,1
access_mailing_test_partner_all,access.mailing.test.partner.all,model_mailing_test_partner,,0,0,0,0
access_mailing_test_partner_user,access.mailing.test.partner.user,model_mailing_test_partner,base.group_user,1,1,1,1
access_mailing_test_partner_unstored_all,access.mailing.test.partner.unstored.all,model_mailing_test_partner_unstored,,0,0,0,0
access_mailing_test_partner_unstored_user,access.mailing.test.partner.unstored.user,model_mailing_test_partner_unstored,base.group_user,1,1,1,1
access_mailing_test_utm_all,access.mailing.test.utm.all,model_mailing_test_utm,,0,0,0,0
......
......@@ -5,7 +5,7 @@ from odoo.addons.test_mass_mailing.data.mail_test_data import MAIL_TEMPLATE
from odoo.addons.test_mass_mailing.tests.common import TestMassMailCommon
from odoo.tests import tagged
from odoo.tests.common import users
from odoo.tools import mute_logger
from odoo.tools import email_normalize, mute_logger
@tagged('mass_mailing')
......@@ -412,6 +412,37 @@ class TestMassMailing(TestMassMailCommon):
)
self.assertEqual(mailing.ignored, 3)
@users('user_marketing')
def test_mailing_w_seenlist(self):
"""
Tests whether function `_get_seen_list` is correctly able to identify duplicate emails,
even through different batches.
Mails use different names to make sure they are recognized as duplicates even without being
normalized (e.g.: '"jc" <0@example.com>' and '"vd" <0@example.com>' are duplicates)
"""
BATCH_SIZE = 5
names = ['jc', 'vd']
emails = [f'test.{i}@example.com' for i in range(BATCH_SIZE)]
records = self.env['mailing.test.partner'].create([{
'name': f'test_duplicates {i}', 'email_from': f'"{names[i % 2]}" <{emails[i % BATCH_SIZE]}>'
} for i in range(20)])
mailing = self.env['mailing.mailing'].create({
'mailing_domain': [('name', 'ilike', 'test_duplicates %')],
'mailing_model_id': self.env.ref('test_mass_mailing.model_mailing_test_partner').id,
'name': 'test duplicates',
'subject': 'test duplicates',
})
with self.mock_mail_gateway():
for i in range(0, 20, BATCH_SIZE):
mailing.action_send_mail(records[i:i + BATCH_SIZE].mapped('id'))
self.assertEqual(len(self._mails), BATCH_SIZE)
self.assertEqual(mailing.ignored, 15)
mails_sent = [email_normalize(mail['email_to'][0]) for mail in self._mails]
for email in emails:
self.assertEqual(mails_sent.count(email), 1)
@users('user_marketing')
def test_mailing_w_seenlist_unstored_partner(self):
""" Test seen list when partners are not stored. """
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment