Browse Source

✡️ make module mail_multi_website free again

13.0-mail_multi_website-publish
Ivan Yelizariev 2 years ago
parent
commit
829df3905d
No known key found for this signature in database GPG Key ID: 5C35763D5E7BFD67
  1. 14
      mail_multi_website/ ⇐ ⇐ ⇐/README.rst
  2. 67
      mail_multi_website/README.rst
  3. 43
      mail_multi_website/__init__.py
  4. 45
      mail_multi_website/__manifest__.py
  5. 13
      mail_multi_website/doc/changelog.rst
  6. 73
      mail_multi_website/doc/index.rst
  7. 36
      mail_multi_website/doc/src/index.html
  8. 1
      mail_multi_website/doc/src/info.yaml
  9. 123
      mail_multi_website/i18n/mail_multi_website.pot
  10. BIN
      mail_multi_website/images/main.jpg
  11. 7
      mail_multi_website/models/__init__.py
  12. 20
      mail_multi_website/models/ir_property.py
  13. 13
      mail_multi_website/models/mail_message.py
  14. 185
      mail_multi_website/models/mail_template.py
  15. 34
      mail_multi_website/models/mail_thread.py
  16. 50
      mail_multi_website/models/res_users.py
  17. 12
      mail_multi_website/models/website.py
  18. BIN
      mail_multi_website/static/description/icon.png
  19. 134
      mail_multi_website/static/description/index.html
  20. 4
      mail_multi_website/tests/__init__.py
  21. 63
      mail_multi_website/tests/test_fetch.py
  22. 11
      mail_multi_website/tests/test_mail_model.py
  23. 145
      mail_multi_website/tests/test_render.py
  24. 72
      mail_multi_website/tests/test_send.py
  25. 14
      mail_multi_website/views/website_views.xml
  26. 2
      mail_multi_website/wizard/__init__.py
  27. 22
      mail_multi_website/wizard/mail_compose_message.py

14
mail_multi_website/ ⇐ ⇐ ⇐/README.rst

@ -1,14 +0,0 @@
=====================
Multi-Brand Mailing
=====================
Mail-related stuff for multi-website support
Module is available at Odoo Apps Store:
https://www.odoo.com/apps/modules/13.0/mail_multi_website/
We do love FOSS, but sometimes we need to eat ¯\\_(ツ)_/¯
Please consider buying the module and get karma and support in return
`IT Projects Labs Team <https://itpp.dev/>`__

67
mail_multi_website/README.rst

@ -0,0 +1,67 @@
.. image:: https://img.shields.io/badge/license-MIT-blue.svg
:target: https://opensource.org/licenses/MIT
:alt: License: MIT
=====================
Multi-Brand Mailing
=====================
Mail-related stuff for multi-website support
* Makes following field in ``res.users`` website-dependent:
* ``email``
* ``signature``
* Makes following fields in ``mail.template`` website-dependent:
* ``body_html``
* ``mail_server_id``
* ``report_template``
* Overrides ``mail.template``'s ``render_template`` method to add ``website``
variable. It may cause incompatibility with other modules that redefine that
method too.
Roadmap
=======
* ``body_html`` becomes untranslatable after module installation
Credits
=======
Contributors
------------
* `Ivan Yelizariev <https://it-projects.info/team/yelizariev>`__
Sponsors
--------
* `e-thos SSII <http://www.e-thos.fr/>`__
Maintainers
-----------
* `IT-Projects LLC <https://it-projects.info>`__
To get a guaranteed support
you are kindly requested to purchase the module
at `odoo apps store <https://apps.odoo.com/apps/modules/13.0/mail_multi_website/>`__.
Thank you for understanding!
`IT-Projects Team <https://www.it-projects.info/team>`__
Further information
===================
Demo: http://runbot.it-projects.info/demo/mail-addons/13.0
HTML Description: https://apps.odoo.com/apps/modules/13.0/mail_multi_website/
Usage instructions: `<doc/index.rst>`_
Changelog: `<doc/changelog.rst>`_
Notifications on updates: `via Atom <https://github.com/it-projects-llc/mail-addons/commits/13.0/mail_multi_website.atom>`_, `by Email <https://blogtrottr.com/?subscribe=https://github.com/it-projects-llc/mail-addons/commits/13.0/mail_multi_website.atom>`_
Tested on Odoo 13.0 ca67c83e8d36ececaf97a7579c3ff2529b3e227c

43
mail_multi_website/__init__.py

@ -0,0 +1,43 @@
# Copyright 2018 Ivan Yelizariev <https://it-projects.info/team/yelizariev>
# License MIT (https://opensource.org/licenses/MIT).
from . import models
from . import wizard
from .tests import test_mail_model
def post_init_hook(cr, registry):
from odoo import api, SUPERUSER_ID
env = api.Environment(cr, SUPERUSER_ID, {})
env.cr.execute("ALTER TABLE res_users ADD COLUMN email VARCHAR")
# fill new email column with values from partner
for user in env["res.users"].with_context(active_test=False).search([]):
email = user.partner_id.email
if email:
user._force_default("email", email)
def uninstall_hook(cr, registry):
from odoo import api, SUPERUSER_ID
env = api.Environment(cr, SUPERUSER_ID, {})
# remove properties
field_ids = [
env.ref("base.field_res_users__email").id,
env.ref("base.field_res_users__signature").id,
env.ref("mail.field_mail_template__body_html").id,
env.ref("mail.field_mail_template__mail_server_id").id,
env.ref("mail.field_mail_template__report_template").id,
]
env["ir.property"].search([("fields_id", "in", field_ids)]).unlink()
# copy emails from user to partner
cr.execute("SELECT partner_id,email FROM res_users")
for partner_id, default_email in cr.fetchall():
env["res.partner"].browse(partner_id).email = default_email
# email field is computed (related) and not needed if mail_multi_website is not installed
env.cr.execute("ALTER TABLE res_users DROP COLUMN email")

45
mail_multi_website/__manifest__.py

@ -0,0 +1,45 @@
# Copyright 2018,2020 Ivan Yelizariev <https://it-projects.info/team/yelizariev>
# Copyright 2018 Kolushov Alexandr <https://it-projects.info/team/KolushovAlexandr>
# License MIT (https://opensource.org/licenses/MIT).
# License OPL-1 (https://www.odoo.com/documentation/user/13.0/legal/licenses/licenses.html#odoo-apps) for derivative work.
{
"name": """Multi-Brand Mailing""",
"summary": """Use single Backend to manage several Websites""",
"category": "Discuss",
# "live_test_url": "http://apps.it-projects.info/shop/product/website-multi-company?version=11.0",
"images": ["images/main.jpg"],
"version": "13.0.2.0.0",
"application": False,
"author": "IT-Projects LLC, Ivan Yelizariev",
"support": "apps@itpp.dev",
"website": "https://twitter.com/OdooFree",
"license": "OPL-1",
"price": 115.00,
"currency": "EUR",
"depends": [
"ir_config_parameter_multi_company",
"web_website",
"mail",
"test_mail",
],
"external_dependencies": {"python": [], "bin": []},
"data": ["views/website_views.xml"],
"demo": [],
"qweb": [],
"post_load": None,
"pre_init_hook": None,
"post_init_hook": "post_init_hook",
"uninstall_hook": "uninstall_hook",
"auto_install": False,
"installable": True,
# "demo_title": "Email Addresses per Website",
# "demo_addons": [
# ],
# "demo_addons_hidden": [
# ],
# "demo_url": "DEMO-URL",
# "demo_summary": "Use single Backend to manage several Websites",
# "demo_images": [
# "images/MAIN_IMAGE",
# ]
}

13
mail_multi_website/doc/changelog.rst

@ -0,0 +1,13 @@
`2.0.0`
-------
- **Improvement:** adapt module to latest version of ``web_website`` module
`1.0.1`
-------
- **Fix:** Issue with module uninstallation
`1.0.0`
-------
- **Init version**

73
mail_multi_website/doc/index.rst

@ -0,0 +1,73 @@
=====================
Multi-Brand Mailing
=====================
Installation
============
* `Install <https://odoo-development.readthedocs.io/en/latest/odoo/usage/install-module.html>`__ this module in a usual way
Configuration
=============
Access to websites
------------------
* Go to menu ``[[ Settings ]] >> Users & Companies >> Users``
* Select a user
* Grant access ``[x] Multi Websites for Backend``
* Configure **Allowed Websites**
User's email per website
------------------------
* Refresh page if you just granted your user access to websites
* Use top right-hand corner button with current website name to switch between websites
* Use top right-hand corner button with user name and avatar to open
Preference popup. When you edit **Email** field, it will be saved as a value
for current website.
Email template per website
--------------------------
* Refresh page if you just granted your user access to websites
* `Activate Developer Mode <https://odoo-development.readthedocs.io/en/latest/odoo/usage/debug-mode.html>`__
* Use top right-hand corner button with current website name to switch between websites
* Go to menu ``[[ Settings ]] >> Technical >> Email >> Templates``
* When you edit template, following fields will be saved as a value for current website:
* **Body**
* **Outgoing Mail Server**
* **Optional report to print and attach**
* Additional variable ``website`` is available to configure rest fields (**Subject**, **From**, etc.)
Note. If related record (e.g. ``sale.order``) has field ``company_id`` or ``website_id`` those values will be used instead of currently selected in Website / Company Switchers
Alias domain per website
------------------------
Configure ``mail.catchall.domain`` per website. See Documentation of the module `Context-dependent values in System Parameters <https://apps.odoo.com/apps/modules/10.0/ir_config_parameter_multi_company>`__.
Outgoing mails servers per website
----------------------------------
If each domain has different Outgoing Mail Server you need following adjustments
* Go to menu ``[[ Website ]] >> Configuration >> Websites``
* In each Website specify field **Outgoing Mails**
Properties
----------
To review properties by website use menu ``[[ Settings ]] >> Technical >> Parameters >> Company Properties``. See **How it works** in Documentation of module `Website Switcher in Backend <https://apps.odoo.com/apps/modules/10.0/web_website>`__.
Usage
=====
When you work from backend, Email for current website is used.
When a user do something on website (e.g. purchase products) and some mail is sent, then email address for that website will be used (mostly Administrator's email address).
When email is sent, template's value like body, subject, etc. for current values are used.

36
mail_multi_website/doc/src/index.html

@ -0,0 +1,36 @@
<section class="oe_container">
<div class="oe_row oe_spaced">
<div class="oe_span12">
<div class="alert alert-info oe_mt32" style="padding:0.3em 0.6em; font-size: 150%;">
<i class="fa fa-hand-o-right"></i><b> Key features: </b>
<ul class="list-unstyled">
<li>
<i class="fa fa-check-square-o text-primary"></i>
Separate Mail Templates per Website
</li>
<li>
<i class="fa fa-check-square-o text-primary"></i>
<em>From</em> address in email has address for current Website
</li>
<li>
<i class="fa fa-check-square-o text-primary"></i>
<em>Reply-To</em> address in email has domain of current Website
</li>
<li>
<i class="fa fa-check-square-o text-primary"></i>
User's signature per Website
</li>
</ul>
</div>
</div>
</div>
</section>

1
mail_multi_website/doc/src/info.yaml

@ -0,0 +1 @@
slogan: Use single Backend to manage several Websites

123
mail_multi_website/i18n/mail_multi_website.pot

@ -0,0 +1,123 @@
# Translation of Odoo Server.
# This file contains the translation of the following modules:
# * mail_multi_website
#
msgid ""
msgstr ""
"Project-Id-Version: Odoo Server 12.0\n"
"Report-Msgid-Bugs-To: \n"
"Last-Translator: <>\n"
"Language-Team: \n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: \n"
"Plural-Forms: \n"
#. module: mail_multi_website
#: model:ir.model.fields,field_description:mail_multi_website.field_email_template_preview__body_html
#: model:ir.model.fields,field_description:mail_multi_website.field_mail_template__body_html
msgid "Body"
msgstr ""
#. module: mail_multi_website
#: model:ir.model.fields,field_description:mail_multi_website.field_mail_test_simple__company_id
msgid "Company"
msgstr ""
#. module: mail_multi_website
#: model:ir.model,name:mail_multi_website.model_ir_property
msgid "Company Property"
msgstr ""
#. module: mail_multi_website
#: model:ir.model.fields,help:mail_multi_website.field_website__mail_server_id
msgid "Default outgoing mail server"
msgstr ""
#. module: mail_multi_website
#: model:ir.model.fields,field_description:mail_multi_website.field_res_users__email_multi_website
msgid "Email Multi Website"
msgstr ""
#. module: mail_multi_website
#: model:ir.model,name:mail_multi_website.model_mail_template
msgid "Email Templates"
msgstr ""
#. module: mail_multi_website
#: model:ir.model,name:mail_multi_website.model_mail_thread
msgid "Email Thread"
msgstr ""
#. module: mail_multi_website
#: model:ir.model,name:mail_multi_website.model_mail_compose_message
msgid "Email composition wizard"
msgstr ""
#. module: mail_multi_website
#: code:addons/mail_multi_website/models/mail_template.py:112
#, python-format
msgid "Failed to render template %r using values %r"
msgstr ""
#. module: mail_multi_website
#: model:ir.model,name:mail_multi_website.model_mail_message
msgid "Message"
msgstr ""
#. module: mail_multi_website
#: model:ir.model.fields,field_description:mail_multi_website.field_res_users__email
msgid "Multi Website Email"
msgstr ""
#. module: mail_multi_website
#: model:ir.model.fields,help:mail_multi_website.field_email_template_preview__mail_server_id
#: model:ir.model.fields,help:mail_multi_website.field_mail_template__mail_server_id
msgid "Optional preferred server for outgoing mails. If not set, the highest priority one will be used."
msgstr ""
#. module: mail_multi_website
#: model:ir.model.fields,field_description:mail_multi_website.field_email_template_preview__report_template
#: model:ir.model.fields,field_description:mail_multi_website.field_mail_template__report_template
msgid "Optional report to print and attach (Multi-Website)"
msgstr ""
#. module: mail_multi_website
#: model:ir.model.fields,field_description:mail_multi_website.field_email_template_preview__mail_server_id
#: model:ir.model.fields,field_description:mail_multi_website.field_mail_template__mail_server_id
msgid "Outgoing Mail Server (Multi-Website)"
msgstr ""
#. module: mail_multi_website
#: model:ir.model.fields,field_description:mail_multi_website.field_website__mail_server_id
msgid "Outgoing Mails"
msgstr ""
#. module: mail_multi_website
#: model:ir.model.fields,field_description:mail_multi_website.field_mail_compose_message__mail_server_id
#: model:ir.model.fields,field_description:mail_multi_website.field_mail_mail__mail_server_id
#: model:ir.model.fields,field_description:mail_multi_website.field_mail_message__mail_server_id
msgid "Outgoing mail server"
msgstr ""
#. module: mail_multi_website
#: model:ir.model.fields,field_description:mail_multi_website.field_res_users__signature
msgid "Signature"
msgstr ""
#. module: mail_multi_website
#: model:ir.model,name:mail_multi_website.model_mail_test_simple
msgid "Simple Chatter Model"
msgstr ""
#. module: mail_multi_website
#: model:ir.model,name:mail_multi_website.model_res_users
msgid "Users"
msgstr ""
#. module: mail_multi_website
#: model:ir.model,name:mail_multi_website.model_website
#: model:ir.model.fields,field_description:mail_multi_website.field_mail_test_simple__website_id
msgid "Website"
msgstr ""

BIN
mail_multi_website/images/main.jpg

After

Width: 750  |  Height: 371  |  Size: 285 KiB

7
mail_multi_website/models/__init__.py

@ -0,0 +1,7 @@
# License MIT (https://opensource.org/licenses/MIT).
from . import res_users
from . import ir_property
from . import mail_template
from . import mail_thread
from . import mail_message
from . import website

20
mail_multi_website/models/ir_property.py

@ -0,0 +1,20 @@
# Copyright 2018 Ivan Yelizariev <https://it-projects.info/team/yelizariev>
# Copyright 2018 Kolushov Alexandr <https://it-projects.info/team/KolushovAlexandr>
# License MIT (https://opensource.org/licenses/MIT).
from odoo import models
class IrProperty(models.Model):
_inherit = "ir.property"
def write(self, vals):
res = super(IrProperty, self).write(vals)
field_object_list = [
self.env.ref("base.field_res_users__email"),
self.env.ref("mail.field_mail_template__body_html"),
self.env.ref("mail.field_mail_template__mail_server_id"),
self.env.ref("mail.field_mail_template__report_template"),
]
for fobj in field_object_list:
self._update_db_value_website_dependent(fobj)
return res

13
mail_multi_website/models/mail_message.py

@ -0,0 +1,13 @@
# Copyright 2018,2020 Ivan Yelizariev <https://it-projects.info/team/yelizariev>
# License MIT (https://opensource.org/licenses/MIT).
# License OPL-1 (https://www.odoo.com/documentation/user/13.0/legal/licenses/licenses.html#odoo-apps) for derivative work.
from odoo import fields, models
class Message(models.Model):
_inherit = "mail.message"
def _default_mail_server_id(self):
return self.env.website.mail_server_id.id
mail_server_id = fields.Many2one(default=_default_mail_server_id)

185
mail_multi_website/models/mail_template.py

@ -0,0 +1,185 @@
# Copyright 2018,2020 Ivan Yelizariev <https://it-projects.info/team/yelizariev>
# License MIT (https://opensource.org/licenses/MIT).
# License OPL-1 (https://www.odoo.com/documentation/user/13.0/legal/licenses/licenses.html#odoo-apps) for derivative work.
import logging
from odoo import _, api, fields, models, tools
from odoo.exceptions import UserError
from odoo.addons.mail.models.mail_template import format_date, format_datetime
_logger = logging.getLogger(__name__)
FIELDS = ["body_html", "mail_server_id", "report_template"]
try:
from odoo.addons.mail.models.mail_template import (
mako_safe_template_env,
mako_template_env,
)
except ImportError:
_logger.warning("jinja2 not available, templating features will not work!")
class MailTemplate(models.Model):
_inherit = ["mail.template", "website_dependent.mixin"]
_name = "mail.template"
body_html = fields.Html(company_dependent=True, website_dependent=True)
mail_server_id = fields.Many2one(
string="Outgoing Mail Server (Multi-Website)",
company_dependent=True,
website_dependent=True,
)
report_template = fields.Many2one(
string="Optional report to print and attach (Multi-Website)",
company_dependent=True,
website_dependent=True,
)
def generate_email(self, res_ids, fields=None):
"""Remove mail_server_id when not set to recompute in _default_mail_server_id in mail.message"""
multi_mode = True
if isinstance(res_ids, int):
multi_mode = False
res = super(MailTemplate, self).generate_email(res_ids, fields=fields)
if not multi_mode:
list_of_dict = {0: res}
else:
list_of_dict = res
for _unused, data in list_of_dict.items():
if "mail_server_id" in data and not data.get("mail_server_id"):
del data["mail_server_id"]
return res
@api.model
def _render_template(self, template_txt, model, res_ids, post_process=False):
"""Override to add website to context"""
multi_mode = True
if isinstance(res_ids, int):
multi_mode = False
res_ids = [res_ids]
results = dict.fromkeys(res_ids, u"")
# try to load the template
try:
mako_env = (
mako_safe_template_env
if self.env.context.get("safe")
else mako_template_env
)
template = mako_env.from_string(tools.ustr(template_txt))
except Exception:
_logger.info("Failed to load template %r", template_txt, exc_info=True)
return multi_mode and results or results[res_ids[0]]
# prepare template variables
records = self.env[model].browse(
it for it in res_ids if it
) # filter to avoid browsing [None]
res_to_rec = dict.fromkeys(res_ids, None)
for record in records:
res_to_rec[record.id] = record
variables = {
"format_date": lambda date, date_format=False, lang_code=False: format_date(
self.env, date, date_format, lang_code
),
"format_datetime": lambda dt, tz=False, dt_format=False, lang_code=False: format_datetime(
self.env, dt, tz, dt_format, lang_code
),
"format_amount": lambda amount, currency, lang_code=False: tools.format_amount(
self.env, amount, currency, lang_code
),
"format_duration": lambda value: tools.format_duration(value),
"user": self.env.user,
"ctx": self._context, # context kw would clash with mako internals
}
# [NEW] Check website and company context
company = self.env["res.company"] # empty value
company_id = self.env.context.get("force_company")
if company_id:
company = self.env["res.company"].sudo().browse(company_id)
website = self.env.website
# [/NEW]
for res_id, record in res_to_rec.items():
# [NEW] Check website and company context
record_company = company
if not record_company:
if hasattr(record, "company_id") and record.company_id:
record_company = record.company_id
record_website = website
if hasattr(record, "website_id") and record.website_id:
record_website = record.website_id
if (
record_company
and record_website
and record_website.company_id != company
):
# company and website are incompatible, so keep only company
record_website = self.env["website"] # empty value
record_context = dict(
force_company=record_company.id, website_id=record_website.id
)
variables["website"] = record_website
# [/NEW]
variables["object"] = record
try:
render_result = template.render(variables)
except Exception:
_logger.info(
"Failed to render template %r using values %r"
% (template, variables),
exc_info=True,
)
raise UserError(
_("Failed to render template %r using values %r")
% (template, variables)
)
if render_result == u"False":
render_result = u""
results[res_id] = render_result
if post_process:
for res_id, result in results.items():
results[res_id] = self.with_context(
**record_context
).render_post_process(result)
return multi_mode and results or results[res_ids[0]]
@api.model
def create(self, vals):
res = super(MailTemplate, self).create(vals)
# make value company independent
for f in FIELDS:
res._force_default(f, vals.get(f))
return res
def write(self, vals):
res = super(MailTemplate, self).write(vals)
# TODO: will it work with OCA's partner_firstname module?
if "name" in vals:
fields_to_update = FIELDS
else:
fields_to_update = [f for f in FIELDS if f in vals]
for f in fields_to_update:
self._update_properties_label(f)
return res
def _auto_init(self):
for f in FIELDS:
self._auto_init_website_dependent(f)
return super(MailTemplate, self)._auto_init()

34
mail_multi_website/models/mail_thread.py

@ -0,0 +1,34 @@
# Copyright 2018,2020 Ivan Yelizariev <https://it-projects.info/team/yelizariev>
# License MIT (https://opensource.org/licenses/MIT).
# License OPL-1 (https://www.odoo.com/documentation/user/13.0/legal/licenses/licenses.html#odoo-apps) for derivative work.
from odoo import api, models, tools
class MailThread(models.AbstractModel):
_inherit = "mail.thread"
@api.model
def _message_route_process(self, message, message_dict, routes):
rcpt_tos = ",".join(
[
tools.decode_message_header(message, "Delivered-To"),
tools.decode_message_header(message, "To"),
tools.decode_message_header(message, "Cc"),
tools.decode_message_header(message, "Resent-To"),
tools.decode_message_header(message, "Resent-Cc"),
]
)
rcpt_tos_websiteparts = [
e.split("@")[1].lower() for e in tools.email_split(rcpt_tos)
]
website = (
self.env["website"].sudo().search([("domain", "in", rcpt_tos_websiteparts)])
)
company = website.mapped("company_id")
new_self = self.with_context(
allowed_website_ids=website.ids, allowed_company_ids=company.ids
)
return super(MailThread, new_self)._message_route_process(
message, message_dict, routes
)

50
mail_multi_website/models/res_users.py

@ -0,0 +1,50 @@
# Copyright 2018 Ivan Yelizariev <https://it-projects.info/team/yelizariev>
# License MIT (https://opensource.org/licenses/MIT).
import logging
from odoo import api, fields, models
_logger = logging.getLogger(__name__)
FIELD_NAME = "email"
FIELDS = ["signature"]
ALL_FIELDS = [FIELD_NAME] + FIELDS
class User(models.Model):
_inherit = ["res.users", "website_dependent.mixin"]
_name = "res.users"
signature = fields.Html(company_dependent=True, website_dependent=True)
# extra field to detach email field from res.partner
email = fields.Char(
string="Multi Website Email",
company_dependent=True,
website_dependent=True,
inherited=False,
related=None,
readonly=False,
)
@api.model
def create(self, vals):
res = super(User, self).create(vals)
# make value company independent
res._force_default(FIELD_NAME, vals.get("email"))
for f in FIELDS:
res._force_default(f, vals.get(f))
return res
def write(self, vals):
res = super(User, self).write(vals)
# TODO: will it work with OCA's partner_firstname module?
if any(k in vals for k in ["name"] + FIELDS):
for f in ALL_FIELDS:
self._update_properties_label(f)
return res
def _auto_init(self):
for f in FIELDS:
self._auto_init_website_dependent(f)
return super(User, self)._auto_init()

12
mail_multi_website/models/website.py

@ -0,0 +1,12 @@
# Copyright 2017 Ivan Yelizariev <https://it-projects.info/team/yelizariev>
# License MIT (https://opensource.org/licenses/MIT).
from odoo import fields, models
class Website(models.Model):
_inherit = "website"
mail_server_id = fields.Many2one(
"ir.mail_server", "Outgoing Mails", help="Default outgoing mail server"
)

BIN
mail_multi_website/static/description/icon.png

After

Width: 100  |  Height: 100  |  Size: 2.1 KiB

134
mail_multi_website/static/description/index.html

@ -0,0 +1,134 @@
<section class="container">
<div class="row">
<div class="col-md-offset-1 col-md-8 mb64 mt64">
<div class="">
<h2 class="display-3">Multi-Brand Mailing</h2>
<h4 class="text-default">Use single Backend to manage several Websites</h4>
<p class="text-default mt16">Version: v<b>13.0</b>.2.0.0</p>
</div>
</div>
<div class="col-md-3 text-right">
<p>
<img src="https://itpp.dev/images/favicon.png"/>
<br/>Tested and maintained by
<br/><b>IT Projects Labs</b>
<br/>Assitance: <a href="mailto:apps@itpp.dev">apps@itpp.dev</a>
</p>
</div>
</div>
</section>
<section class="oe_container">
<div class="oe_row oe_spaced">
<div class="oe_span12">
<div class="alert alert-info oe_mt32" style="padding:0.3em 0.6em; font-size: 150%;">
<i class="fa fa-hand-o-right"></i><b> Key features: </b>
<ul class="list-unstyled">
<li>
<i class="fa fa-check-square-o text-primary"></i>
Separate Mail Templates per Website
</li>
<li>
<i class="fa fa-check-square-o text-primary"></i>
<em>From</em> address in email has address for current Website
</li>
<li>
<i class="fa fa-check-square-o text-primary"></i>
<em>Reply-To</em> address in email has domain of current Website
</li>
<li>
<i class="fa fa-check-square-o text-primary"></i>
User's signature per Website
</li>
</ul>
</div>
</div>
</div>
</section>
<section class="container text-center">
<div class="mt-4 mb-3">
<h2>Let our expertise work for you!</h2>
<h4 class="d-none d-md-block">(Doors and windows below are clickable)</h4>
<div class="mb32 d-md-none">
<ul class="list-unstyled">
<li><a target="_blank" href="https://apps.odoo.com/apps/browse?repo_maintainer_id=59928">All modules</a></li>
<li><a target="_blank" href="https://apps.odoo.com/apps/browse?price=Free&order=Downloads&repo_maintainer_id=59928">Free Modules</a></li>
<li><a target="_blank" href="https://apps.odoo.com/apps/modules/category/Point%20of%20Sale/browse?repo_maintainer_id=59928">All POS modules</a></li>
<li><a target="_blank" href="https://apps.odoo.com/apps/modules/category/Discuss/browse?repo_maintainer_id=59928">All Mail modules</a></li>
<li><a target="_blank" href="https://apps.odoo.com/apps/modules/category/Website/browse?repo_maintainer_id=59928">All Website modules</a></li>
<li><a target="_blank" href="https://apps.odoo.com/apps/modules/category/eCommerce/browse?repo_maintainer_id=59928">All eCommerce modules</a></li>
<li><a target="_blank" href="https://apps.odoo.com/apps/modules/browse?search=sync+studio&repo_maintainer_id=59928">Sync Studio</a></li>
<li><a target="_blank" href="https://apps.odoo.com/apps/modules/14.0/openapi/">REST API</a></li>
<li><a target="_blank" href="https://apps.odoo.com/apps/modules/14.0/base_automation_webhook/">Webhooks</a></li>
<li><a target="_blank" href="https://apps.odoo.com/apps/modules/14.0/pos_product_available/">POS: show product qty</a></li>
<li><a target="_blank" href="https://apps.odoo.com/apps/modules/14.0/web_login_background/">Web Login Background</a></li>
</ul>
</div>
<div class="mb64 d-none d-xl-block">
<img class="img img-responsive" src="https://itpp.dev/images/apps/;-)/itpp-labs-1100.jpg" usemap="#itpp-xl" />
<map name="itpp-xl">
<area alt="Free Modules" target="_blank" href="https://apps.odoo.com/apps/browse?price=Free&order=Downloads&repo_maintainer_id=59928" shape="rect" class="" coords="900,220,1080,625" />
<area alt="Sync Studio" target="_blank" href="https://apps.odoo.com/apps/modules/browse?search=sync+studio&repo_maintainer_id=59928" shape="rect" class="" coords="552,186,721,274" />
<area alt="REST API" target="_blank" href="https://apps.odoo.com/apps/modules/14.0/openapi/" shape="rect" class="" coords="646,279,720,365" />
<area alt="Webhooks" target="_blank" href="https://apps.odoo.com/apps/modules/14.0/base_automation_webhook/" shape="rect" class="" coords="646,370,720,458" />
<area alt="POS: show product qty" target="_blank" href="https://apps.odoo.com/apps/modules/14.0/pos_product_available/" shape="rect" class="" coords="82,373,251,459" />
<area alt="All modules" target="_blank" href="https://apps.odoo.com/apps/browse?repo_maintainer_id=59928" shape="rect" class="" coords="326,267,381,456" />
<area alt="All POS modules" target="_blank" href="https://apps.odoo.com/apps/modules/category/Point%20of%20Sale/browse?repo_maintainer_id=59928" shape="rect" class="" coords="82,191,154,276" />
<area alt="All Mail modules" target="_blank" href="https://apps.odoo.com/apps/modules/category/Discuss/browse?repo_maintainer_id=59928" shape="rect" class="" coords="82,282,155,368" />
<area alt="All Website modules" target="_blank" href="https://apps.odoo.com/apps/modules/category/Website/browse?repo_maintainer_id=59928" shape="rect" class="" coords="176,282,250,368" />
<area alt="All eCommerce modules" target="_blank" href="https://apps.odoo.com/apps/modules/category/eCommerce/browse?repo_maintainer_id=59928" shape="rect" class="" coords="175,189,250,275" />
<area alt="Ivan Yelizariev" target="_blank" href="https://apps.odoo.com/apps/modules/browse?search=Ivan+Yelizariev&repo_maintainer_id=59928" shape="rect" class="" coords="554,280,625,456" />
<area alt="Web Login Background" target="_blank" href="https://apps.odoo.com/apps/modules/14.0/web_login_background/" shape="rect" class="" coords="420,267,477,456" />
</map>
</div>
<div class="mb64 d-none d-lg-block d-xl-none">
<img class="img img-responsive" src="https://itpp.dev/images/apps/;-)/itpp-labs-930.jpg" usemap="#itpp-lg" />
<map name="itpp-lg">
<area alt="Free Modules" target="_blank" href="https://apps.odoo.com/apps/browse?price=Free&order=Downloads&repo_maintainer_id=59928" shape="rect" class="" coords="760,186,913,528" />
<area alt="Sync Studio" target="_blank" href="https://apps.odoo.com/apps/modules/browse?search=sync+studio&repo_maintainer_id=59928" shape="rect" class="" coords="466,157,609,231" />
<area alt="REST API" target="_blank" href="https://apps.odoo.com/apps/modules/14.0/openapi/" shape="rect" class="" coords="546,235,608,308" />
<area alt="Webhooks" target="_blank" href="https://apps.odoo.com/apps/modules/14.0/base_automation_webhook/" shape="rect" class="" coords="546,312,608,387" />
<area alt="POS: show product qty" target="_blank" href="https://apps.odoo.com/apps/modules/14.0/pos_product_available/" shape="rect" class="" coords="69,315,212,388" />
<area alt="All modules" target="_blank" href="https://apps.odoo.com/apps/browse?repo_maintainer_id=59928" shape="rect" class="" coords="275,225,322,385" />
<area alt="All POS modules" target="_blank" href="https://apps.odoo.com/apps/modules/category/Point%20of%20Sale/browse?repo_maintainer_id=59928" shape="rect" class="" coords="69,161,130,233" />
<area alt="All Mail modules" target="_blank" href="https://apps.odoo.com/apps/modules/category/Discuss/browse?repo_maintainer_id=59928" shape="rect" class="" coords="69,238,131,311" />
<area alt="All Website modules" target="_blank" href="https://apps.odoo.com/apps/modules/category/Website/browse?repo_maintainer_id=59928" shape="rect" class="" coords="148,238,211,311" />
<area alt="All eCommerce modules" target="_blank" href="https://apps.odoo.com/apps/modules/category/eCommerce/browse?repo_maintainer_id=59928" shape="rect" class="" coords="147,159,211,232" />
<area alt="Ivan Yelizariev" target="_blank" href="https://apps.odoo.com/apps/modules/browse?search=Ivan+Yelizariev&repo_maintainer_id=59928" shape="rect" class="" coords="468,236,528,385" />
<area alt="Web Login Background" target="_blank" href="https://apps.odoo.com/apps/modules/14.0/web_login_background/" shape="rect" class="" coords="355,225,403,385" />
</map>
</div>
<div class="mb64 d-lg-none">
<img class="img img-responsive" src="https://itpp.dev/images/apps/;-)/itpp-labs-690.jpg" usemap="#itpp-md" />
<map name="itpp-md">
<area alt="Free Modules" target="_blank" href="https://apps.odoo.com/apps/browse?price=Free&order=Downloads&repo_maintainer_id=59928" shape="rect" class="" coords="564,138,677,392" />
<area alt="Sync Studio" target="_blank" href="https://apps.odoo.com/apps/modules/browse?search=sync+studio&repo_maintainer_id=59928" shape="rect" class="" coords="346,116,452,171" />
<area alt="REST API" target="_blank" href="https://apps.odoo.com/apps/modules/14.0/openapi/" shape="rect" class="" coords="405,175,451,228" />
<area alt="Webhooks" target="_blank" href="https://apps.odoo.com/apps/modules/14.0/base_automation_webhook/" shape="rect" class="" coords="405,232,451,287" />
<area alt="POS: show product qty" target="_blank" href="https://apps.odoo.com/apps/modules/14.0/pos_product_available/" shape="rect" class="" coords="51,233,157,287" />
<area alt="All modules" target="_blank" href="https://apps.odoo.com/apps/browse?repo_maintainer_id=59928" shape="rect" class="" coords="204,167,238,286" />
<area alt="All POS modules" target="_blank" href="https://apps.odoo.com/apps/modules/category/Point%20of%20Sale/browse?repo_maintainer_id=59928" shape="rect" class="" coords="51,119,96,173" />
<area alt="All Mail modules" target="_blank" href="https://apps.odoo.com/apps/modules/category/Discuss/browse?repo_maintainer_id=59928" shape="rect" class="" coords="51,176,97,230" />
<area alt="All Website modules" target="_blank" href="https://apps.odoo.com/apps/modules/category/Website/browse?repo_maintainer_id=59928" shape="rect" class="" coords="110,176,156,230" />
<area alt="All eCommerce modules" target="_blank" href="https://apps.odoo.com/apps/modules/category/eCommerce/browse?repo_maintainer_id=59928" shape="rect" class="" coords="109,118,156,172" />
<area alt="Ivan Yelizariev" target="_blank" href="https://apps.odoo.com/apps/modules/browse?search=Ivan+Yelizariev&repo_maintainer_id=59928" shape="rect" class="" coords="347,175,392,286" />
<area alt="Web Login Background" target="_blank" href="https://apps.odoo.com/apps/modules/14.0/web_login_background/" shape="rect" class="" coords="263,167,299,286" />
</map>
</div>
</div>
</section>

4
mail_multi_website/tests/__init__.py

@ -0,0 +1,4 @@
# License MIT (https://opensource.org/licenses/MIT).
from . import test_send
from . import test_render
from . import test_fetch

63
mail_multi_website/tests/test_fetch.py

@ -0,0 +1,63 @@
# Copyright 2018,2020 Ivan Yelizariev <https://it-projects.info/team/yelizariev>
# Copyright 2018 Kolushov Alexandr <https://it-projects.info/team/KolushovAlexandr>
# License MIT (https://opensource.org/licenses/MIT).
# License OPL-1 (https://www.odoo.com/documentation/user/13.0/legal/licenses/licenses.html#odoo-apps) for derivative work.
from odoo.tools import mute_logger
from odoo.addons.test_mail.data.test_mail_data import MAIL_TEMPLATE
from odoo.addons.test_mail.tests.test_mail_mail import TestMail
# TODO: Shall we use TestMailgateway class instead?
class TestFetch(TestMail):
at_install = True
post_install = True
def setUp(self):
super(TestFetch, self).setUp()
self.email_from = '"Sylvie Lelitre" <test.sylvie.lelitre@agrolait.com>'
self.website = self.env["website"].create(
{"name": "Test Website", "domain": "example.com"}
)
self.company = self.env["res.company"].create({"name": "New Test Website"})
self.website.company_id = self.company
# copy-paste from mail.tests.test_mail_gateway
mail_test_model = self.env["ir.model"]._get("mail.test.simple")
# groups@.. will cause the creation of new mail.test.simple
self.alias = self.env["mail.alias"].create(
{
"alias_name": "groups",
"alias_user_id": False,
"alias_model_id": mail_test_model.id,
"alias_contact": "everyone",
}
)
@mute_logger("odoo.addons.mail.models.mail_thread", "odoo.models")
def test_fetch_multi_website(self):
""" Incoming email on an alias creating a new record + message_new + message details """
new_groups = self.format_and_process(
MAIL_TEMPLATE,
self.email_from,
"groups@example.com",
subject="My Frogs",
target_model="mail.test.simple",
)
# Test: one group created by mailgateway administrator
self.assertEqual(
len(new_groups),
1,
"message_process: a new mail.test should have been created",
)
self.assertEqual(
new_groups.website_id,
self.website,
"New record is created with wrong website",
)
self.assertEqual(
new_groups.company_id,
self.company,
"New record is created with wrong company",
)

11
mail_multi_website/tests/test_mail_model.py

@ -0,0 +1,11 @@
# Copyright 2018,2020 Ivan Yelizariev <https://it-projects.info/team/yelizariev>
# License MIT (https://opensource.org/licenses/MIT).
# License OPL-1 (https://www.odoo.com/documentation/user/13.0/legal/licenses/licenses.html#odoo-apps) for derivative work.
from odoo import fields, models
class MailTest(models.Model):
_inherit = "mail.test.simple"
company_id = fields.Many2one("res.company", default=lambda self: self.env.company)
website_id = fields.Many2one("website", default=lambda self: self.env.website)

145
mail_multi_website/tests/test_render.py

@ -0,0 +1,145 @@
# Copyright 2018,2020 Ivan Yelizariev <https://it-projects.info/team/yelizariev>
# Copyright 2018 Kolushov Alexandr <https://it-projects.info/team/KolushovAlexandr>
# License MIT (https://opensource.org/licenses/MIT).
# License OPL-1 (https://www.odoo.com/documentation/user/13.0/legal/licenses/licenses.html#odoo-apps) for derivative work.
import base64
from odoo.addons.test_mail.tests.test_mail_mail import TestMail
class TestRender(TestMail):
at_install = True
post_install = True
def setUp(self):
super(TestRender, self).setUp()
self.original_email = self.env.user.email
self.original_company = self.env.user.company_id
self.email = "superadmin@second-website.example"
self.assertNotEqual(self.original_email, self.email)
self.website = self.env.ref("website.website2")
self.company = self.env["res.company"].create({"name": "New Test Website"})
self.website.company_id = self.company
self.mail_server_id = self.env["ir.mail_server"].create(
{"name": "mail server", "smtp_host": "mail.example.com"}
)
self.website.mail_server_id = self.mail_server_id
user_admin = self.env.ref("base.user_admin")
# copy-paste from mail.tests.test_mail_template
self._attachments = [
{
"name": "first.txt",
"datas": base64.b64encode(b"My first attachment"),
"res_model": "res.partner",
"res_id": user_admin.partner_id.id,
},
{
"name": "second.txt",
"datas": base64.b64encode(b"My second attachment"),
"res_model": "res.partner",
"res_id": user_admin.partner_id.id,
},
]
self.partner_1 = self.env["res.partner"].create({"name": "partner_1"})
self.partner_2 = self.env["res.partner"].create({"name": "partner_2"})
self.email_1 = "test1@example.com"
self.email_2 = "test2@example.com"
self.email_3 = self.partner_1.email
self.email_template = self.env["mail.template"].create(
{
"model_id": self.env["ir.model"]._get("mail.test").id,
"name": "Pigs Template",
"subject": "${website.name}",
"body_html": "${object.description}",
"user_signature": False,
"attachment_ids": [
(0, 0, self._attachments[0]),
(0, 0, self._attachments[1]),
],
"partner_to": "%s,%s"
% (self.partner_2.id, self.user_employee.partner_id.id),
"email_to": "{}, {}".format(self.email_1, self.email_2),
"email_cc": "%s" % self.email_3,
}
)
def switch_user_website(self):
# add website to allowed
self.env.user.write(
dict(
backend_website_ids=[(4, self.website.id)],
backend_website_id=self.website.id,
company_id=self.company.id,
company_ids=[(4, self.company.id)],
)
)
def test_website_in_render_variables(self):
"""Mail values are per website"""
self.env.user.backend_website_id = None
TestModel = self.env["mail.test"].with_context(
{"mail_create_nolog": True, "mail_create_nosubscribe": True}
)
self.test_pigs = TestModel.create(
{
"name": "Pigs",
"description": "Fans of Pigs, unite !",
"alias_name": "pigs",
"alias_contact": "followers",
}
)
# sending without website
mail_id = self.email_template.send_mail(self.test_pigs.id)
mail = self.env["mail.mail"].browse(mail_id)
self.assertEqual(mail.subject, "")
self.assertFalse(mail.mail_server_id)
# sending from frontend
self.test_pigs.company_id = None
mail_id = self.email_template.with_context(
wdb=True, allowed_website_ids=self.website.ids
).send_mail(self.test_pigs.id)
mail = self.env["mail.mail"].browse(mail_id)
self.assertEqual(mail.subject, self.website.name)
self.assertEqual(mail.mail_server_id, self.mail_server_id)
# copy-pasted tests
self.assertEqual(mail.email_to, self.email_template.email_to)
# for some reason self.email_template.email_cc might return u'False'
self.assertEqual(
mail.email_cc or "False", self.email_template.email_cc or "False"
)
self.assertEqual(
mail.recipient_ids, self.partner_2 | self.user_employee.partner_id
)
# sending from frontend
self.switch_user_website()
mail_id = self.email_template.send_mail(self.test_pigs.id)
mail = self.env["mail.mail"].browse(mail_id)
self.assertEqual(mail.subject, self.website.name)
def _test_message_post_with_template(self):
# It's deactivated, because workaround is based on checking host value in get_current_website()
"""Simulate sending email on eCommerce checkout"""
self.switch_user_website()
self.env.user.email = self.email
self.env.user.invalidate_cache()
self.env.user.invalidate_cache()
self.assertEqual(self.env.user.email, self.email)
# switch admin user back
self.env.user.company_id = self.original_company
self.env.user.invalidate_cache()
self.assertEqual(self.env.user.email, self.original_email)
self.test_pigs.with_context(
allowed_website_ids=self.website.ids
).message_post_with_template(self.email_template.id)
message = self.env["mail.message"].search([], order="id desc", limit=1)
self.assertIn("<%s>" % self.email, message.email_from)

72
mail_multi_website/tests/test_send.py

@ -0,0 +1,72 @@
# Copyright 2018 Ivan Yelizariev <https://it-projects.info/team/yelizariev>
# License MIT (https://opensource.org/licenses/MIT).
from odoo.tests.common import TransactionCase
class TestSendMail(TransactionCase):
at_install = True
post_install = True
def setUp(self):
super(TestSendMail, self).setUp()
self.website = self.env.ref("website.website2")
self.company = self.env["res.company"].create({"name": "New Test Website"})
self.original_email = self.env.user.email
self.original_company = self.env.user.company_id
self.email = "superadmin@second-website.example"
# Check that current email is set and differs
self.assertTrue(self.email)
self.assertNotEqual(self.original_email, self.email)
self.website.company_id = self.company
def switch_user_website(self):
# add website to allowed
self.env.user.write(
dict(
backend_website_ids=[(4, self.website.id)],
backend_website_id=self.website.id,
company_id=self.company.id,
company_ids=[(4, self.company.id)],
)
)
def test_multi_email(self):
"""User has email addresses per website"""
self.switch_user_website()
# update user's email
self.env.user.email = self.email
# Check that writing works
self.env.user.flush()
self.env.user.invalidate_cache()
self.assertEqual(
self.env.user.email,
self.email,
"Write methods doesn't work (Field is not in registry?)",
)
# changing company will automatically update website value to empty value
self.env.user.company_id = self.original_company
self.env.user.invalidate_cache()
self.assertEqual(
self.env.user.email,
self.original_email,
"Multi-email doesn't work on switching websites",
)
def test_multi_email_partner(self):
"""Partner doesn't have email addresses per website"""
original_email = "original@email1"
new_email = "new@email2"
partner = self.env["res.partner"].create(
{"name": "test", "email": original_email}
)
self.switch_user_website()
# update partner's email
partner.email = new_email
self.assertEqual(partner.email, new_email)
# changing company will automatically update website value to empty value
self.env.user.company_id = self.original_company
self.env.user.invalidate_cache()
self.assertEqual(
partner.email, new_email, "Partner's email must not be Multi-website"
)

14
mail_multi_website/views/website_views.xml

@ -0,0 +1,14 @@
<?xml version="1.0" encoding="utf-8" ?>
<!-- Copyright 2018 Ivan Yelizariev <https://it-projects.info/team/yelizariev>
License MIT (https://opensource.org/licenses/MIT). -->
<odoo>
<record id="view_website_multi_mail_form" model="ir.ui.view">
<field name="model">website</field>
<field name="inherit_id" ref="website.view_website_form" />
<field name="arch" type="xml">
<xpath expr="//field[@name='default_lang_id']" position="after">
<field name="mail_server_id" />
</xpath>
</field>
</record>
</odoo>

2
mail_multi_website/wizard/__init__.py

@ -0,0 +1,2 @@
# License MIT (https://opensource.org/licenses/MIT).
from . import mail_compose_message

22
mail_multi_website/wizard/mail_compose_message.py

@ -0,0 +1,22 @@
# Copyright 2018 Ivan Yelizariev <https://it-projects.info/team/yelizariev>
# License MIT (https://opensource.org/licenses/MIT).
from odoo import api, models
from odoo.http import request
class MailComposer(models.TransientModel):
_inherit = "mail.compose.message"
@api.model
def create(self, vals):
"""Workaround for https://github.com/odoo/odoo/pull/26589"""
if "website_id" not in self.env.context:
website = (
request and hasattr(request, "website") and request.website or None
)
if not website:
website = self.env["website"].get_current_website()
if website:
self = self.with_context(website_id=website.id)
return super(MailComposer, self).create(vals)
Loading…
Cancel
Save