102 lines
3.7 KiB
Python
102 lines
3.7 KiB
Python
# Copyright 2026 Criptomart
|
|
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl).
|
|
|
|
import logging
|
|
|
|
from markupsafe import Markup
|
|
|
|
from odoo import _, models
|
|
from odoo.exceptions import UserError
|
|
from odoo.tools import email_normalize
|
|
|
|
_logger = logging.getLogger(__name__)
|
|
|
|
|
|
class ResPartner(models.Model):
|
|
_inherit = "res.partner"
|
|
|
|
def write(self, vals):
|
|
res = super().write(vals)
|
|
if "email" in vals and not self.env.context.get("skip_portal_login_sync"):
|
|
self._sync_portal_user_login()
|
|
return res
|
|
|
|
def _get_portal_users_to_sync(self):
|
|
self.ensure_one()
|
|
group_portal = self.env.ref("base.group_portal")
|
|
return self.sudo().user_ids.filtered(lambda u: group_portal in u.groups_id)
|
|
|
|
def _sync_portal_user_login(self):
|
|
"""Set the partner email as login of its portal users and send them
|
|
a password reset email."""
|
|
Users = self.env["res.users"].sudo().with_context(active_test=False)
|
|
for partner in self:
|
|
users = partner._get_portal_users_to_sync()
|
|
if not users:
|
|
continue
|
|
new_login = email_normalize(partner.email)
|
|
if not new_login:
|
|
_logger.info(
|
|
"Portal login not synced for partner %s: invalid email %r",
|
|
partner.id,
|
|
partner.email,
|
|
)
|
|
continue
|
|
for user in users:
|
|
if email_normalize(user.login) == new_login:
|
|
continue
|
|
if Users.search_count(
|
|
[("login", "=", new_login), ("id", "!=", user.id)]
|
|
):
|
|
raise UserError(
|
|
_(
|
|
"Cannot change the email of %(partner)s: there is "
|
|
"already a user with login %(login)s.",
|
|
partner=partner.display_name,
|
|
login=new_login,
|
|
)
|
|
)
|
|
old_login = user.login
|
|
user.write({"login": new_login})
|
|
_logger.info(
|
|
"Portal user %s login changed from %s to %s",
|
|
user.id,
|
|
old_login,
|
|
new_login,
|
|
)
|
|
if self.env.context.get("portal_login_sync_no_mail"):
|
|
body = _(
|
|
"Portal user login changed from %(old)s to %(new)s.",
|
|
old=old_login,
|
|
new=new_login,
|
|
)
|
|
else:
|
|
body = partner._send_portal_login_reset_password(
|
|
user, old_login, new_login
|
|
)
|
|
partner.sudo().message_post(body=Markup("<p>%s</p>") % body)
|
|
|
|
def _send_portal_login_reset_password(self, user, old_login, new_login):
|
|
try:
|
|
with self.env.cr.savepoint():
|
|
user.action_reset_password()
|
|
except Exception as e:
|
|
# Do not block the email change if the reset email cannot be sent
|
|
_logger.warning(
|
|
"Password reset email for portal user %s could not be sent: %s",
|
|
user.id,
|
|
e,
|
|
)
|
|
return _(
|
|
"Portal user login changed from %(old)s to %(new)s, but the "
|
|
"password reset email could not be sent: %(error)s",
|
|
old=old_login,
|
|
new=new_login,
|
|
error=str(e),
|
|
)
|
|
return _(
|
|
"Portal user login changed from %(old)s to %(new)s and a password "
|
|
"reset email has been sent.",
|
|
old=old_login,
|
|
new=new_login,
|
|
)
|