Browse Source
Merge remote-tracking branch 'upstream/11.0' into 12.0-29b06ca8cdacccfe9e952dc3df57115085923760
pull/164/head
Merge remote-tracking branch 'upstream/11.0' into 12.0-29b06ca8cdacccfe9e952dc3df57115085923760
pull/164/head
rusllan
6 years ago
50 changed files with 1099 additions and 55 deletions
-
2mail_all/static/description/index.html
-
2mail_archives/static/description/index.html
-
2mail_check_immediately/static/description/index.html
-
2mail_move_message/__manifest__.py
-
6mail_move_message/data/mail_move_message_data.xml
-
5mail_move_message/doc/changelog.rst
-
48mail_move_message/mail_move_message_models.py
-
2mail_move_message/mail_move_message_views.xml
-
2mail_move_message/static/description/index.html
-
43mail_move_message/static/src/js/mail_move_message.js
-
3mail_move_message/tests/__init__.py
-
52mail_move_message/tests/test_mail_move.py
-
62mail_multi_website/README.rst
-
40mail_multi_website/__init__.py
-
51mail_multi_website/__manifest__.py
-
4mail_multi_website/doc/changelog.rst
-
73mail_multi_website/doc/index.rst
-
BINmail_multi_website/images/main.jpg
-
7mail_multi_website/models/__init__.py
-
20mail_multi_website/models/ir_property.py
-
16mail_multi_website/models/mail_message.py
-
151mail_multi_website/models/mail_template.py
-
26mail_multi_website/models/mail_thread.py
-
45mail_multi_website/models/res_users.py
-
10mail_multi_website/models/website.py
-
BINmail_multi_website/static/description/icon.png
-
97mail_multi_website/static/description/index.html
-
4mail_multi_website/tests/__init__.py
-
41mail_multi_website/tests/test_fetch.py
-
10mail_multi_website/tests/test_mail_model.py
-
114mail_multi_website/tests/test_render.py
-
62mail_multi_website/tests/test_send.py
-
14mail_multi_website/views/website_views.xml
-
2mail_multi_website/wizard/__init__.py
-
20mail_multi_website/wizard/mail_compose_message.py
-
30mail_private/README.rst
-
2mail_private/__openerp__.py
-
5mail_private/doc/changelog.rst
-
2mail_private/full_composer_wizard.xml
-
2mail_private/static/description/index.html
-
9mail_private/static/src/js/mail_private.js
-
6mail_private/template.xml
-
2mail_recovery/static/description/index.html
-
4mail_reply/doc/index.rst
-
2mail_reply/static/description/index.html
-
45mail_sent/static/description/index.html
-
2mail_to/static/description/index.html
-
1mail_to/tests/test_default.py
-
2mailgun/static/description/index.html
-
2res_partner_mails_count/static/description/index.html
@ -0,0 +1,3 @@ |
|||
# License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl.html). |
|||
from . import test_mail_move |
|||
|
@ -0,0 +1,52 @@ |
|||
# Copyright 2018 Kolushov Alexandr <https://it-projects.info/team/KolushovAlexandr> |
|||
# License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl.html). |
|||
|
|||
import odoo.tests |
|||
from odoo.api import Environment |
|||
|
|||
|
|||
@odoo.tests.common.at_install(True) |
|||
@odoo.tests.common.post_install(True) |
|||
class TestUi(odoo.tests.HttpCase): |
|||
|
|||
def test_create_new_partner_and_move_message(self): |
|||
env = Environment(self.registry.test_cr, self.uid, {}) |
|||
# needed because tests are run before the module is marked as |
|||
# installed. In js web will only load qweb coming from modules |
|||
# that are returned by the backend in module_boot. Without |
|||
# this you end up with js, css but no qweb. |
|||
env['ir.module.module'].search([('name', '=', 'mail_move_message')], limit=1).state = 'installed' |
|||
self.registry.cursor().release() |
|||
|
|||
# updating models, to be able relocate messages to a partner at_install |
|||
config_parameters = self.env["ir.config_parameter"].sudo() |
|||
config_parameters.set_param("mail_relocation_models", "crm.lead,project.task,res.partner") |
|||
|
|||
code = """ |
|||
var delayed_button_click = function(delay, button){ |
|||
setTimeout(function(){ |
|||
if (button.length) { |
|||
return button.click(); |
|||
} |
|||
return console.log('error', 'There is no element with the next selector: ' + button.selector); |
|||
}, delay); |
|||
}; |
|||
var delay = 1000; |
|||
var message = $('.o_thread_message_core:contains("virginie")'); |
|||
var relocate = message.find('.o_thread_icons .fa-exchange'); |
|||
delayed_button_click(delay, relocate); |
|||
// form is opened |
|||
|
|||
var create_partner_button = $('button[special="quick_create"]'); |
|||
delayed_button_click(delay, create_partner_button); |
|||
// partner creation wizard is opened |
|||
|
|||
var save_button = $('.modal-content .btn-primary:contains("Save")'); |
|||
delayed_button_click(delay, save_button); |
|||
|
|||
var move_button = $('.btn-sm.oe_highlight:contains("Move")'); |
|||
delayed_button_click(delay, move_button); |
|||
console.log('ok') |
|||
""" |
|||
|
|||
self.phantom_js('/web', code, login="admin", ready="$('.o_thread_icons').length") |
@ -0,0 +1,62 @@ |
|||
.. image:: https://img.shields.io/badge/license-LGPL--3-blue.png |
|||
:target: https://www.gnu.org/licenses/lgpl |
|||
:alt: License: LGPL-3 |
|||
|
|||
=========================================== |
|||
Email Addresses and Templates per Website |
|||
=========================================== |
|||
|
|||
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. |
|||
|
|||
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/11.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/11.0 |
|||
|
|||
HTML Description: https://apps.odoo.com/apps/modules/11.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/11.0/mail_multi_website.atom>`_, `by Email <https://blogtrottr.com/?subscribe=https://github.com/it-projects-llc/mail-addons/commits/11.0/mail_multi_website.atom>`_ |
|||
|
|||
Tested on Odoo 11.0 4d0a1330e05bd688265bea14df4ad12838f9f2d7 |
@ -0,0 +1,40 @@ |
|||
# Copyright 2018 Ivan Yelizariev <https://it-projects.info/team/yelizariev> |
|||
# License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl.html). |
|||
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_multi_website 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_multi_website', 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 partner to user |
|||
cr.execute("SELECT partner_id,email_multi_website FROM res_users") |
|||
for partner_id, default_email in cr.fetchall(): |
|||
env['res.partner'].browse(partner_id).email = default_email |
@ -0,0 +1,51 @@ |
|||
# Copyright 2018 Ivan Yelizariev <https://it-projects.info/team/yelizariev> |
|||
# License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl.html). |
|||
{ |
|||
"name": """Email Addresses and Templates per Website""", |
|||
"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": "11.0.1.0.0", |
|||
"application": False, |
|||
|
|||
"author": "IT-Projects LLC, Ivan Yelizariev", |
|||
"support": "apps@it-projects.info", |
|||
"website": "https://it-projects.info/team/yelizariev", |
|||
"license": "LGPL-3", |
|||
"price": 230.00, |
|||
"currency": "EUR", |
|||
|
|||
"depends": [ |
|||
"ir_config_parameter_multi_company", |
|||
"web_website", |
|||
"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", |
|||
# ] |
|||
} |
@ -0,0 +1,4 @@ |
|||
`1.0.0` |
|||
------- |
|||
|
|||
- **Init version** |
@ -0,0 +1,73 @@ |
|||
=========================================== |
|||
Email Addresses and Templates per Website |
|||
=========================================== |
|||
|
|||
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 |
|||
-------------------------- |
|||
|
|||
If each domain has different Outgoing Mail Server you need following adjustments |
|||
|
|||
* Got 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. |
After Width: 750 | Height: 371 | Size: 285 KiB |
@ -0,0 +1,7 @@ |
|||
# License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl.html). |
|||
from . import res_users |
|||
from . import ir_property |
|||
from . import mail_template |
|||
from . import mail_thread |
|||
from . import mail_message |
|||
from . import website |
@ -0,0 +1,20 @@ |
|||
# Copyright 2018 Ivan Yelizariev <https://it-projects.info/team/yelizariev> |
|||
# License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl.html). |
|||
from odoo import models, api |
|||
|
|||
|
|||
class IrProperty(models.Model): |
|||
_inherit = 'ir.property' |
|||
|
|||
@api.multi |
|||
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 |
@ -0,0 +1,16 @@ |
|||
# Copyright 2018 Ivan Yelizariev <https://it-projects.info/team/yelizariev> |
|||
# License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl.html). |
|||
from odoo import models, fields |
|||
|
|||
|
|||
class Message(models.Model): |
|||
_inherit = 'mail.message' |
|||
|
|||
def _default_mail_server_id(self): |
|||
website = self.env.context.get('website_id') |
|||
if not website: |
|||
return |
|||
website = self.env['website'].sudo().browse(website) |
|||
return website.mail_server_id.id |
|||
|
|||
mail_server_id = fields.Many2one(default=_default_mail_server_id) |
@ -0,0 +1,151 @@ |
|||
# Copyright 2018 Ivan Yelizariev <https://it-projects.info/team/yelizariev> |
|||
# License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl.html). |
|||
import logging |
|||
from odoo import models, fields, api, tools, _ |
|||
from odoo.exceptions import UserError |
|||
from odoo.tools import pycompat |
|||
from odoo.addons.mail.models.mail_template import format_date, format_tz, format_amount |
|||
|
|||
_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) |
|||
|
|||
@api.multi |
|||
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, pycompat.integer_types): |
|||
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, pycompat.integer_types): |
|||
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, format=False, context=self._context: format_date(self.env, date, format), |
|||
'format_tz': lambda dt, tz=False, format=False, context=self._context: format_tz(self.env, dt, tz, format), |
|||
'format_amount': lambda amount, currency, context=self._context: format_amount(self.env, amount, currency), |
|||
'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) |
|||
|
|||
if self.env.context.get('website_id'): |
|||
website = self.env['website'].browse(self.env.context.get('website_id')) |
|||
else: |
|||
website = self.env.user.backend_website_id |
|||
|
|||
for res_id, record in res_to_rec.items(): |
|||
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 website |
|||
record_website = self.env['website'] # empty value |
|||
|
|||
record_context = dict(force_company=record_company.id, website_id=record_website.id) |
|||
variables['object'] = record.with_context(**record_context) |
|||
variables['website'] = record_website |
|||
|
|||
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"" |
|||
|
|||
if post_process: |
|||
render_result = self.with_context(**record_context).render_post_process(render_result) |
|||
|
|||
results[res_id] = render_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 |
|||
|
|||
@api.multi |
|||
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() |
@ -0,0 +1,26 @@ |
|||
# Copyright 2018 Ivan Yelizariev <https://it-projects.info/team/yelizariev> |
|||
# License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl.html). |
|||
from odoo import models, api, 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) |
|||
]) |
|||
if website: |
|||
self = self.with_context(website_id=website[0].id) |
|||
|
|||
return super(MailThread, self).message_route_process( |
|||
message, message_dict, routes |
|||
) |
@ -0,0 +1,45 @@ |
|||
# Copyright 2018 Ivan Yelizariev <https://it-projects.info/team/yelizariev> |
|||
# License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl.html). |
|||
import logging |
|||
from odoo import models, fields, api |
|||
|
|||
|
|||
_logger = logging.getLogger(__name__) |
|||
FIELD_NAME = 'email_multi_website' |
|||
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(related='email_multi_website', inherited=False) |
|||
email_multi_website = fields.Char(company_dependent=True, website_dependent=True) |
|||
|
|||
@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 |
|||
|
|||
@api.multi |
|||
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', 'email'] + 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() |
@ -0,0 +1,10 @@ |
|||
# Copyright 2017 Ivan Yelizariev <https://it-projects.info/team/yelizariev> |
|||
# License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl.html). |
|||
|
|||
from odoo import models, fields |
|||
|
|||
|
|||
class Website(models.Model): |
|||
_inherit = "website" |
|||
|
|||
mail_server_id = fields.Many2one('ir.mail_server', 'Outgoing Mails', help='Default outgoing mail server') |
After Width: 100 | Height: 100 | Size: 2.1 KiB |
@ -0,0 +1,97 @@ |
|||
<section class="oe_container"> |
|||
<div class="oe_row oe_spaced"> |
|||
<div class="oe_span12"> |
|||
<h2 class="oe_slogan" style="color:#875A7B;">Email Addresses and Templates per Website |
|||
</h2> |
|||
<h3 class="oe_slogan">Use single Backend to manage several Websites</h3> |
|||
</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="oe_container"> |
|||
<div class="oe_row oe_spaced"> |
|||
<div class="oe_span8"> |
|||
<h2>Need our service?</h2> |
|||
<p class="oe_mt32">Contact us by <a href="mailto:apps@it-projects.info">email</a> or fill out <a href="https://www.it-projects.info/page/website.contactus " target="_blank">request form</a></p> |
|||
<ul> |
|||
<li><a href="mailto:apps@it-projects.info">apps@it-projects.info <i class="fa fa-envelope-o"></i></a></li> |
|||
<li><a href="https://www.it-projects.info/page/website.contactus " target="_blank">https://www.it-projects.info/page/website.contactus <i class="fa fa-list-alt"></i></a></li> |
|||
<li><a href="https://m.me/itprojectsllc" target="_blank">https://m.me/itprojectsllc <i class="fa fa-facebook-square"></i></a></li> |
|||
<li>skype@it-projects.info <i class="fa fa-skype"></i></li> |
|||
</ul> |
|||
</div> |
|||
<div class="oe_span4"> |
|||
<div class="stamp" style="width:200px;"> |
|||
<div style="margin-top: 15px; |
|||
position: relative; |
|||
font-family:'Vollkorn', serif; |
|||
font-size: 16px; |
|||
line-height: 25px; |
|||
text-transform: uppercase; |
|||
font-weight: bold; |
|||
color: #75526b; |
|||
border: 3px dashed #75526b; |
|||
float: left; |
|||
padding: 4px 12px; |
|||
-webkit-transform: rotate(1deg); |
|||
-o-transform: rotate(1deg); |
|||
-moz-transform: rotate(1deg); |
|||
-ms-transform: rotate(1deg);"> |
|||
Tested on Odoo<br/>11.0 community |
|||
</div> |
|||
<!--<div style="margin-top: 15px; |
|||
position: relative; |
|||
font-family:'Vollkorn', serif; |
|||
font-size: 16px; |
|||
line-height: 25px; |
|||
text-transform: uppercase; |
|||
font-weight: bold; |
|||
color: #75526b; |
|||
border: 3px dashed #75526b; |
|||
float: left; |
|||
padding: 4px 12px; |
|||
-webkit-transform: rotate(1deg); |
|||
-o-transform: rotate(1deg); |
|||
-moz-transform: rotate(1deg); |
|||
-ms-transform: rotate(1deg);"> |
|||
Tested on Odoo<br/>11.0 enterprise |
|||
</div>--> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
</section> |
@ -0,0 +1,4 @@ |
|||
# License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl.html). |
|||
from . import test_send |
|||
from . import test_render |
|||
from . import test_fetch |
@ -0,0 +1,41 @@ |
|||
# Copyright 2018 Ivan Yelizariev <https://it-projects.info/team/yelizariev> |
|||
# License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl.html). |
|||
from odoo.addons.mail.tests.common import TestMail |
|||
from odoo.tools import mute_logger |
|||
from odoo.addons.mail.tests.test_mail_gateway import MAIL_TEMPLATE |
|||
|
|||
|
|||
class TestFetch(TestMail): |
|||
at_install = True |
|||
post_install = True |
|||
|
|||
def setUp(self): |
|||
super(TestFetch, self).setUp() |
|||
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') |
|||
# groups@.. will cause the creation of new mail.test |
|||
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, subject='My Frogs', to='groups@example.com, other@gmail.com') |
|||
|
|||
# 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') |
@ -0,0 +1,10 @@ |
|||
# Copyright 2018 Ivan Yelizariev <https://it-projects.info/team/yelizariev> |
|||
# License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl.html). |
|||
from odoo import models, fields |
|||
|
|||
|
|||
class MailTest(models.Model): |
|||
_inherit = 'mail.test' |
|||
|
|||
company_id = fields.Many2one('res.company', default=lambda self: self.env['res.company']._company_default_get()) |
|||
website_id = fields.Many2one('website', default=lambda self: self.env['website'].browse(self.env.context.get('website_id'))) |
@ -0,0 +1,114 @@ |
|||
# Copyright 2018 Ivan Yelizariev <https://it-projects.info/team/yelizariev> |
|||
# License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl.html). |
|||
import base64 |
|||
|
|||
from odoo.addons.mail.tests.common 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 |
|||
|
|||
# copy-paste from mail.tests.test_mail_template |
|||
self._attachments = [{ |
|||
'name': '_Test_First', |
|||
'datas_fname': |
|||
'first.txt', |
|||
'datas': base64.b64encode(b'My first attachment'), |
|||
'res_model': 'res.partner', |
|||
'res_id': self.user_admin.partner_id.id |
|||
}, { |
|||
'name': '_Test_Second', |
|||
'datas_fname': 'second.txt', |
|||
'datas': base64.b64encode(b'My second attachment'), |
|||
'res_model': 'res.partner', |
|||
'res_id': self.user_admin.partner_id.id |
|||
}] |
|||
|
|||
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': '%s, %s' % (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 |
|||
|
|||
# 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, website_id=self.website.id).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) |
|||
self.assertEqual(mail.email_cc, self.email_template.email_cc) |
|||
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(website_id=self.website.id).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) |
@ -0,0 +1,62 @@ |
|||
# Copyright 2018 Ivan Yelizariev <https://it-projects.info/team/yelizariev> |
|||
# License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl.html). |
|||
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.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') |
@ -0,0 +1,14 @@ |
|||
<?xml version="1.0" encoding="utf-8"?> |
|||
<!-- Copyright 2018 Ivan Yelizariev <https://it-projects.info/team/yelizariev> |
|||
License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl.html). --> |
|||
<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> |
@ -0,0 +1,2 @@ |
|||
# License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl.html). |
|||
from . import mail_compose_message |
@ -0,0 +1,20 @@ |
|||
# Copyright 2018 Ivan Yelizariev <https://it-projects.info/team/yelizariev> |
|||
# License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl.html). |
|||
from odoo import models, api |
|||
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) |
Write
Preview
Loading…
Cancel
Save
Reference in new issue