Merge PR #1529 into 16.0

Signed-off-by yajo
pull/1497/head
OCA-git-bot 2024-12-30 07:42:39 +00:00
commit 201781c262
10 changed files with 86 additions and 42 deletions

View File

@ -126,6 +126,10 @@ Contributors
* Nguyễn Minh Chiến <chien@trobz.com> * Nguyễn Minh Chiến <chien@trobz.com>
* `Moduon <https://www.moduon.team>`_:
* Jairo Llopis
Other credits Other credits
~~~~~~~~~~~~~ ~~~~~~~~~~~~~

View File

@ -17,3 +17,7 @@
* `Trobz <https://trobz.com>`_: * `Trobz <https://trobz.com>`_:
* Nguyễn Minh Chiến <chien@trobz.com> * Nguyễn Minh Chiến <chien@trobz.com>
* `Moduon <https://www.moduon.team>`_:
* Jairo Llopis

View File

@ -1,4 +1,3 @@
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en"> <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head> <head>
@ -9,10 +8,11 @@
/* /*
:Author: David Goodger (goodger@python.org) :Author: David Goodger (goodger@python.org)
:Id: $Id: html4css1.css 8954 2022-01-20 10:10:25Z milde $ :Id: $Id: html4css1.css 9511 2024-01-13 09:50:07Z milde $
:Copyright: This stylesheet has been placed in the public domain. :Copyright: This stylesheet has been placed in the public domain.
Default cascading style sheet for the HTML output of Docutils. Default cascading style sheet for the HTML output of Docutils.
Despite the name, some widely supported CSS2 features are used.
See https://docutils.sourceforge.io/docs/howto/html-stylesheets.html for how to See https://docutils.sourceforge.io/docs/howto/html-stylesheets.html for how to
customize this style sheet. customize this style sheet.
@ -275,7 +275,7 @@ pre.literal-block, pre.doctest-block, pre.math, pre.code {
margin-left: 2em ; margin-left: 2em ;
margin-right: 2em } margin-right: 2em }
pre.code .ln { color: grey; } /* line numbers */ pre.code .ln { color: gray; } /* line numbers */
pre.code, code { background-color: #eeeeee } pre.code, code { background-color: #eeeeee }
pre.code .comment, code .comment { color: #5C6576 } pre.code .comment, code .comment { color: #5C6576 }
pre.code .keyword, code .keyword { color: #3B0D06; font-weight: bold } pre.code .keyword, code .keyword { color: #3B0D06; font-weight: bold }
@ -301,7 +301,7 @@ span.option {
span.pre { span.pre {
white-space: pre } white-space: pre }
span.problematic { span.problematic, pre.problematic {
color: red } color: red }
span.section-subtitle { span.section-subtitle {
@ -479,6 +479,13 @@ If you spotted it first, help us to smash it by providing a detailed and welcome
</ul> </ul>
</blockquote> </blockquote>
</li> </li>
<li><p class="first"><a class="reference external" href="https://www.moduon.team">Moduon</a>:</p>
<blockquote>
<ul class="simple">
<li>Jairo Llopis</li>
</ul>
</blockquote>
</li>
</ul> </ul>
</div> </div>
<div class="section" id="other-credits"> <div class="section" id="other-credits">
@ -488,7 +495,9 @@ If you spotted it first, help us to smash it by providing a detailed and welcome
<div class="section" id="maintainers"> <div class="section" id="maintainers">
<h2><a class="toc-backref" href="#toc-entry-8">Maintainers</a></h2> <h2><a class="toc-backref" href="#toc-entry-8">Maintainers</a></h2>
<p>This module is maintained by the OCA.</p> <p>This module is maintained by the OCA.</p>
<a class="reference external image-reference" href="https://odoo-community.org"><img alt="Odoo Community Association" src="https://odoo-community.org/logo.png" /></a> <a class="reference external image-reference" href="https://odoo-community.org">
<img alt="Odoo Community Association" src="https://odoo-community.org/logo.png" />
</a>
<p>OCA, or the Odoo Community Association, is a nonprofit organization whose <p>OCA, or the Odoo Community Association, is a nonprofit organization whose
mission is to support the collaborative development of Odoo features and mission is to support the collaborative development of Odoo features and
promote its widespread use.</p> promote its widespread use.</p>

View File

@ -14,15 +14,16 @@ class DynamicListCase(common.TransactionCase):
def setUpClass(cls): def setUpClass(cls):
super().setUpClass() super().setUpClass()
cls.tag = cls.env["res.partner.category"].create({"name": "testing tag"}) cls.tag = cls.env["res.partner.category"].create({"name": "testing tag"})
cls.partners = cls.env["res.partner"] cls.partners = cls.env["res.partner"].create(
for number in range(5): [
cls.partners |= cls.partners.create(
{ {
"name": "partner %d" % number, "name": "partner %d" % number,
"category_id": [(4, cls.tag.id, False)], "category_id": [(4, cls.tag.id, False)],
"email": "%d@example.com" % number, "email": "%d@example.com" % number,
} }
) for number in range(5)
]
)
cls.list = cls.env["mailing.list"].create( cls.list = cls.env["mailing.list"].create(
{ {
"name": "test list", "name": "test list",
@ -180,3 +181,17 @@ class DynamicListCase(common.TransactionCase):
wizard.action_merge() wizard.action_merge()
self.assertTrue(partner_1.id in self.list.contact_ids.mapped("partner_id").ids) self.assertTrue(partner_1.id in self.list.contact_ids.mapped("partner_id").ids)
self.assertTrue(partner_1.id in list2.contact_ids.mapped("partner_id").ids) self.assertTrue(partner_1.id in list2.contact_ids.mapped("partner_id").ids)
def test_synced_contacts_can_be_bounced(self):
self.list.sync_method = "full"
self.list.action_sync()
contact = self.env["mailing.contact"].search(
[
("list_ids", "in", self.list.ids),
("partner_id", "=", self.partners[0].id),
]
)
# A bounce arrives through fetchmail
contact._message_receive_bounce(contact.email, contact.partner_id)
# The contact is marked as bounced
self.assertEqual(contact.message_bounce, 1)

View File

@ -98,6 +98,10 @@ Contributors
* Nguyễn Minh Chiến <chien@trobz.com> * Nguyễn Minh Chiến <chien@trobz.com>
* `Moduon <https://www.moduon.team>`_:
* Jairo Llopis
Other credits Other credits
~~~~~~~~~~~~~ ~~~~~~~~~~~~~

View File

@ -53,37 +53,30 @@ class MailingContact(models.Model):
) )
self.country_id = self.partner_id.country_id self.country_id = self.partner_id.country_id
@api.model def _overwrite_partner(self, vals, creating=False):
def _get_contact_vals(self, origin_vals): """Overwrite partner and update contact data if needed."""
record = self.new(origin_vals) self.ensure_one()
if not record.partner_id: if self.env.context.get("mass_mailing_partner_writing"):
record._set_partner() return
record._onchange_partner_mass_mailing_partner() _self = self.with_context(mass_mailing_partner_writing=True)
new_vals = record._convert_to_write(record._cache) prev_partner = _self.partner_id
new_vals.update( if "partner_id" not in vals:
subscription_list_ids=origin_vals.get("subscription_list_ids", []), _self._set_partner()
list_ids=origin_vals.get("list_ids", []), if creating or prev_partner != _self.partner_id:
) _self._onchange_partner_mass_mailing_partner()
if new_vals.get("partner_id") and "tag_ids" in new_vals:
# When there is a partner, tag_ids must get value from the compute function
# otherwise, its values will be different from partner
del new_vals["tag_ids"]
return new_vals
@api.model_create_multi @api.model_create_multi
def create(self, vals_list): def create(self, vals_list):
new_vals_list = [] result = super().create(vals_list)
for vals in vals_list: for contact, vals in zip(result, vals_list):
new_vals = self._get_contact_vals(vals) contact._overwrite_partner(vals, True)
new_vals_list.append(new_vals) return result
return super().create(new_vals_list)
def write(self, vals): def write(self, vals):
result = super().write(vals)
for contact in self: for contact in self:
origin_vals = contact.copy_data(vals)[0] contact._overwrite_partner(vals)
new_vals = self._get_contact_vals(origin_vals) return result
super(MailingContact, contact).write(new_vals)
return True
def _get_categories(self): def _get_categories(self):
ca_ids = ( ca_ids = (
@ -113,6 +106,8 @@ class MailingContact(models.Model):
email = self.email.strip() email = self.email.strip()
partner = m_partner.search([("email", "=ilike", email)], limit=1) partner = m_partner.search([("email", "=ilike", email)], limit=1)
if partner: if partner:
if partner == self.partner_id:
return
# Partner found # Partner found
self.partner_id = partner self.partner_id = partner
else: else:

View File

@ -16,3 +16,7 @@
* `Trobz <https://trobz.com>`_: * `Trobz <https://trobz.com>`_:
* Nguyễn Minh Chiến <chien@trobz.com> * Nguyễn Minh Chiến <chien@trobz.com>
* `Moduon <https://www.moduon.team>`_:
* Jairo Llopis

View File

@ -1,4 +1,3 @@
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en"> <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head> <head>
@ -9,10 +8,11 @@
/* /*
:Author: David Goodger (goodger@python.org) :Author: David Goodger (goodger@python.org)
:Id: $Id: html4css1.css 8954 2022-01-20 10:10:25Z milde $ :Id: $Id: html4css1.css 9511 2024-01-13 09:50:07Z milde $
:Copyright: This stylesheet has been placed in the public domain. :Copyright: This stylesheet has been placed in the public domain.
Default cascading style sheet for the HTML output of Docutils. Default cascading style sheet for the HTML output of Docutils.
Despite the name, some widely supported CSS2 features are used.
See https://docutils.sourceforge.io/docs/howto/html-stylesheets.html for how to See https://docutils.sourceforge.io/docs/howto/html-stylesheets.html for how to
customize this style sheet. customize this style sheet.
@ -275,7 +275,7 @@ pre.literal-block, pre.doctest-block, pre.math, pre.code {
margin-left: 2em ; margin-left: 2em ;
margin-right: 2em } margin-right: 2em }
pre.code .ln { color: grey; } /* line numbers */ pre.code .ln { color: gray; } /* line numbers */
pre.code, code { background-color: #eeeeee } pre.code, code { background-color: #eeeeee }
pre.code .comment, code .comment { color: #5C6576 } pre.code .comment, code .comment { color: #5C6576 }
pre.code .keyword, code .keyword { color: #3B0D06; font-weight: bold } pre.code .keyword, code .keyword { color: #3B0D06; font-weight: bold }
@ -301,7 +301,7 @@ span.option {
span.pre { span.pre {
white-space: pre } white-space: pre }
span.problematic { span.problematic, pre.problematic {
color: red } color: red }
span.section-subtitle { span.section-subtitle {
@ -447,6 +447,13 @@ If you spotted it first, help us to smash it by providing a detailed and welcome
</ul> </ul>
</blockquote> </blockquote>
</li> </li>
<li><p class="first"><a class="reference external" href="https://www.moduon.team">Moduon</a>:</p>
<blockquote>
<ul class="simple">
<li>Jairo Llopis</li>
</ul>
</blockquote>
</li>
</ul> </ul>
</div> </div>
<div class="section" id="other-credits"> <div class="section" id="other-credits">
@ -456,7 +463,9 @@ If you spotted it first, help us to smash it by providing a detailed and welcome
<div class="section" id="maintainers"> <div class="section" id="maintainers">
<h1>Maintainers</h1> <h1>Maintainers</h1>
<p>This module is maintained by the OCA.</p> <p>This module is maintained by the OCA.</p>
<a class="reference external image-reference" href="https://odoo-community.org"><img alt="Odoo Community Association" src="https://odoo-community.org/logo.png" /></a> <a class="reference external image-reference" href="https://odoo-community.org">
<img alt="Odoo Community Association" src="https://odoo-community.org/logo.png" />
</a>
<p>OCA, or the Odoo Community Association, is a nonprofit organization whose <p>OCA, or the Odoo Community Association, is a nonprofit organization whose
mission is to support the collaborative development of Odoo features and mission is to support the collaborative development of Odoo features and
promote its widespread use.</p> promote its widespread use.</p>

View File

@ -14,7 +14,7 @@ class PartnerMailListWizardCase(base.BaseCase):
wizard = self.env["partner.mail.list.wizard"].create( wizard = self.env["partner.mail.list.wizard"].create(
{"mail_list_id": self.mailing_list.id} {"mail_list_id": self.mailing_list.id}
) )
wizard.partner_ids = [self.partner.id] wizard.partner_ids = self.partner
wizard.add_to_mail_list() wizard.add_to_mail_list()
contacts = self.env["mailing.contact"].search( contacts = self.env["mailing.contact"].search(
[("partner_id", "=", self.partner.id)] [("partner_id", "=", self.partner.id)]

View File

@ -36,8 +36,8 @@ class PartnerMailListWizard(models.TransientModel):
contact_vals = { contact_vals = {
"partner_id": partner.id, "partner_id": partner.id,
"list_ids": [(4, self.mail_list_id.id)], "list_ids": [(4, self.mail_list_id.id)],
"title_id": partner.title or False, "title_id": partner.title.id or False,
"company_name": partner.company_id.name or False, "company_name": partner.company_id.name or False,
"country_id": partner.country_id or False, "country_id": partner.country_id.id or False,
} }
contact_obj.create(contact_vals) contact_obj.create(contact_vals)