[REF] various: cleanup alias usage and empty list help overrides

PURPOSE

Cleanup alias definitions and usage to have as few invalid or dummy
data as possible. Cleanup empty list helpers override.

SPECIFCIATIONS

hr_expense: cleanup alias management

  * globally avoid crashes if the alias data has been removed;
  * recreate Xml ID record if it has been removed as it is considered as
    being a master data;
  * avoid issues when trying to configure the expense alias in settings if
    alias has been manually removed. Setting a name now creates the alias
    and an XmlID if it has been removed;
  * rename a generic 'use_mail_gateway' field into 'expense_use_mail_gateway'
    in order to avoid conflicts with future changes in generic settings linked
    to email gateway and configuration
  * fix empty list helper: it is now translated and correctly encode parameters
    given to 'mailto';

hr_recruitment, maintenance: remove unused aliases

Those modules hold default aliases to respectively create applicants or
maintenance request. Issue with those generic aliases are

  * they are not bound to any context (container document). For example jobs
    is not linked to any job record. Applicants will not have any job_id set;
  * they are not displayed anywhere. Applicant kanban view displays a helper
    when having no content, with an email address to start populating the
    view. This emails is however based on job in context, aka alias record
    created through the alias mixin on the job.
  * maintenance does not even try to use aliases in any view or code and just
    defines a dummy alias;
  * as default data they can be wrong: taking ``jobs`` and ``helpdesk`` is
    not necessarily a good idea. Indeed it depends on mail server configuration
    (e.g. not always owning all possible emails of a domain when using its own
    address like gmail). This may also conflicts with existing email addresses
    or already-defined aliases without being really configurable;
  * they are not configurable. They are not displayed in any configuration flow
    (setting or container document). Only going into technical menus to find all
    aliases allows to find them;

mail: improve mail alias views to ease usage

mail, various: cleanup empty list help message overrides

Purpose is to cleanup code: stop using help parameter name (use help_message as
help is a keyword), try to call super(), ...

LINKS

Task-2710804 (Mail: Clean MailThread Posting API)
Prepares Task-36879 (Mail: Support MultiCompany Aliases)

closes odoo/odoo#105992

Related: odoo/upgrade#4046
Related: odoo/enterprise#34089
Signed-off-by: Thibault Delavallee (tde) <tde@openerp.com>
This commit is contained in:
Odoo's Mergebot
2022-11-18 13:59:54 +01:00
committed by GitHub
16 changed files with 100 additions and 80 deletions
+6 -4
View File
@@ -1234,13 +1234,13 @@ class Lead(models.Model):
}
@api.model
def get_empty_list_help(self, help):
def get_empty_list_help(self, help_message):
""" This method returns the action helpers for the leads. If help is already provided
on the action, the same is returned. Otherwise, we build the help message which
contains the alias responsible for creating the lead (if available) and return it.
"""
if not is_html_empty(help):
return help
if not is_html_empty(help_message):
return help_message
help_title, sub_title = "", ""
if self._context.get('default_type') == 'lead':
@@ -1258,7 +1258,9 @@ class Lead(models.Model):
email = '%s@%s' % (alias_record.alias_name, alias_record.alias_domain)
email_link = "<b><a href='mailto:%s'>%s</a></b>" % (email, email)
sub_title = _('Use the top left <i>Create</i> button, or send an email to %s to test the email gateway.') % (email_link)
return '<p class="o_view_nocontent_smiling_face">%s</p><p class="oe_view_nocontent_alias">%s</p>' % (help_title, sub_title)
return super().get_empty_list_help(
f'<p class="o_view_nocontent_smiling_face">{help_title}</p><p class="oe_view_nocontent_alias">{sub_title}</p>'
)
# ------------------------------------------------------------
# BUSINESS
@@ -6,6 +6,7 @@ import logging
from odoo import api, fields, models, _
from odoo.addons.iap.tools import iap_tools
from odoo.exceptions import UserError
from odoo.tools import is_html_empty
_logger = logging.getLogger(__name__)
@@ -185,10 +186,15 @@ class CRMLeadMiningRequest(models.Model):
self.company_size_max = self.company_size_min
@api.model
def get_empty_list_help(self, help_string):
def get_empty_list_help(self, help_message):
if not is_html_empty(help_message):
return help_message
help_title = _('Create a Lead Mining Request')
sub_title = _('Generate new leads based on their country, industry, size, etc.')
return '<p class="o_view_nocontent_smiling_face">%s</p><p class="oe_view_nocontent_alias">%s</p>' % (help_title, sub_title)
return super().get_empty_list_help(
f'<p class="o_view_nocontent_smiling_face">{help_title}</p><p class="oe_view_nocontent_alias">{sub_title}</p>'
)
def _prepare_iap_payload(self):
"""
+1
View File
@@ -1,4 +1,5 @@
# -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.
from . import hr_employee
from . import account_move
+15 -7
View File
@@ -3,6 +3,8 @@
import re
from markupsafe import Markup
import werkzeug
from odoo import api, fields, Command, models, _
from odoo.tools import float_round
from odoo.exceptions import UserError, ValidationError
@@ -403,17 +405,23 @@ class HrExpense(models.Model):
@api.model
def get_empty_list_help(self, help_message):
return super(HrExpense, self).get_empty_list_help(help_message or '' + self._get_empty_list_mail_alias())
return super().get_empty_list_help((help_message or '') + self._get_empty_list_mail_alias())
@api.model
def _get_empty_list_mail_alias(self):
use_mailgateway = self.env['ir.config_parameter'].sudo().get_param('hr_expense.use_mailgateway')
alias_record = use_mailgateway and self.env.ref('hr_expense.mail_alias_expense') or False
if alias_record and alias_record.alias_domain and alias_record.alias_name:
return Markup("""
<p>
Or send your receipts at <a href="mailto:%(email)s?subject=Lunch%%20with%%20customer%%3A%%20%%2412.32">%(email)s</a>.
</p>""") % {'email': '%s@%s' % (alias_record.alias_name, alias_record.alias_domain)}
expense_alias = self.env.ref('hr_expense.mail_alias_expense') if use_mailgateway else False
if expense_alias and expense_alias.alias_domain and expense_alias.alias_name:
alias_email = f'{expense_alias.alias_name}@{expense_alias.alias_domain}'
# encode, but force %20 encoding for space instead of a + (URL / mailto difference)
params = werkzeug.urls.url_encode({'subject': _("Lunch with customer $12.32")}).replace('+', '%20')
return Markup(
"""<p>%(send_string)s <a href="mailto:%(alias_email)s?%(params)s">%(alias_email)s</a></p>"""
) % {
'alias_email': alias_email,
'params': params,
'send_string': _("Or send your receipts at"),
}
return ""
# ----------------------------------------
+26 -12
View File
@@ -6,14 +6,13 @@ from odoo import api, fields, models
class ResConfigSettings(models.TransientModel):
_inherit = 'res.config.settings'
expense_alias_prefix = fields.Char(
hr_expense_alias_prefix = fields.Char(
'Default Alias Name for Expenses',
compute='_compute_expense_alias_prefix',
compute='_compute_hr_expense_alias_prefix',
store=True,
readonly=False)
use_mailgateway = fields.Boolean(string='Let your employees record expenses by email',
config_parameter='hr_expense.use_mailgateway')
hr_expense_use_mailgateway = fields.Boolean(string='Let your employees record expenses by email',
config_parameter='hr_expense.use_mailgateway')
module_hr_payroll_expense = fields.Boolean(string='Reimburse Expenses in Payslip')
module_hr_expense_extract = fields.Boolean(string='Send bills to OCR to generate expenses')
expense_journal_id = fields.Many2one('account.journal', related='company_id.expense_journal_id', readonly=False)
@@ -22,17 +21,32 @@ class ResConfigSettings(models.TransientModel):
@api.model
def get_values(self):
res = super(ResConfigSettings, self).get_values()
expense_alias = self.env.ref('hr_expense.mail_alias_expense', raise_if_not_found=False)
res.update(
expense_alias_prefix=self.env.ref('hr_expense.mail_alias_expense').alias_name,
hr_expense_alias_prefix=expense_alias.alias_name if expense_alias else False,
)
return res
def set_values(self):
super().set_values()
alias = self.env.ref('hr_expense.mail_alias_expense', raise_if_not_found=False)
if alias and alias.alias_name != self.expense_alias_prefix:
alias.alias_name = self.expense_alias_prefix
expense_alias = self.env.ref('hr_expense.mail_alias_expense', raise_if_not_found=False)
if not expense_alias and self.hr_expense_alias_prefix:
# create data again
alias = self.env['mail.alias'].sudo().create({
'alias_contact': 'employees',
'alias_model_id': self.env['ir.model']._get_id('hr.expense'),
'alias_name': self.hr_expense_alias_prefix,
})
self.env['ir.model.data'].sudo().create({
'name': 'mail_alias_expense',
'module': 'hr_expense',
'model': 'mail.alias',
'noupdate': True,
'res_id': alias.id,
})
elif expense_alias and expense_alias.alias_name != self.hr_expense_alias_prefix:
expense_alias.alias_name = self.hr_expense_alias_prefix
@api.depends('use_mailgateway')
def _compute_expense_alias_prefix(self):
self.filtered(lambda w: not w.use_mailgateway).update({'expense_alias_prefix': False})
@api.depends('hr_expense_use_mailgateway')
def _compute_hr_expense_alias_prefix(self):
self.filtered(lambda w: not w.hr_expense_use_mailgateway).hr_expense_alias_prefix = False
@@ -15,22 +15,22 @@
id="create_expense_setting"
title="Send an email to this email alias with the receipt in attachment to create an expense in one click. If the first word of the mail subject contains the category's internal reference or the category name, the corresponding category will automatically be set. Type the expense amount in the mail subject to set it on the expense too.">
<div class="o_setting_left_pane">
<field name="use_mailgateway"/>
<field name="hr_expense_use_mailgateway"/>
</div>
<div class="o_setting_right_pane">
<label string="Incoming Emails" for="use_mailgateway"/>
<label string="Incoming Emails" for="hr_expense_use_mailgateway"/>
<div class="text-muted">
Create expenses from incoming emails
</div>
<div class="content-group" attrs="{'invisible': ['|', ('use_mailgateway', '=', False), ('alias_domain', 'in', ['localhost', '', False])]}">
<div class="content-group" attrs="{'invisible': ['|', ('hr_expense_use_mailgateway', '=', False), ('alias_domain', 'in', ['localhost', '', False])]}">
<div class="mt16">
<label for="expense_alias_prefix" string="Alias" class="o_light_label"/>
<field name="expense_alias_prefix" class="oe_inline"/>
<label for="hr_expense_alias_prefix" string="Alias" class="o_light_label"/>
<field name="hr_expense_alias_prefix" class="oe_inline"/>
<span>@</span>
<field name="alias_domain" class="oe_inline" readonly="1" force_save="1"/>
<field name="alias_domain" class="oe_inline" readonly="1"/>
</div>
</div>
<div class="content-group" attrs="{'invisible': ['|', ('use_mailgateway', '=', False), ('alias_domain', 'not in', ['localhost', '', False])]}">
<div class="content-group" attrs="{'invisible': ['|', ('hr_expense_use_mailgateway', '=', False), ('alias_domain', 'not in', ['localhost', '', False])]}">
<div class="mt16">
<button type="action" name="base_setup.action_general_configuration" icon="fa-arrow-right" string="Setup your domain alias" class="btn-link"/>
</div>
-1
View File
@@ -20,7 +20,6 @@
'security/hr_recruitment_security.xml',
'security/ir.model.access.csv',
'data/digest_data.xml',
'data/mail_alias_data.xml',
'data/mail_message_subtype_data.xml',
'data/mail_template_data.xml',
'data/mail_templates.xml',
@@ -1,11 +0,0 @@
<?xml version="1.0"?>
<odoo>
<data noupdate="1">
<record id="mail_alias_jobs" model="mail.alias">
<field name="alias_name">jobs</field>
<field name="alias_model_id" ref="model_hr_applicant"/>
<field name="alias_user_id" ref="base.user_admin"/>
<field name="alias_parent_model_id" ref="model_hr_job"/>
</record>
</data>
</odoo>
@@ -434,7 +434,7 @@ class Applicant(models.Model):
self._update_employee_from_applicant()
return res
def get_empty_list_help(self, help):
def get_empty_list_help(self, help_message):
if 'active_id' in self.env.context and self.env.context.get('active_model') == 'hr.job':
alias_id = self.env['hr.job'].browse(self.env.context['active_id']).alias_id
else:
@@ -453,9 +453,9 @@ class Applicant(models.Model):
email = alias_id.display_name
email_link = "<a href='mailto:%s'>%s</a>" % (email, email)
nocontent_values['email_link'] = email_link
nocontent_body += """<p class="o_copy_paste_email">%(email_link)s</p>"""
nocontent_body += """<p class="o_copy_paste_email oe_view_nocontent_alias">%(email_link)s</p>"""
return nocontent_body % nocontent_values
return super().get_empty_list_help(nocontent_body % nocontent_values)
@api.model
def get_view(self, view_id=None, view_type='form', **options):
+11 -11
View File
@@ -338,14 +338,14 @@ class MailThread(models.AbstractModel):
return super(MailThread, self.with_context(mail_notrack=True)).copy_data(default=default)
@api.model
def get_empty_list_help(self, help):
def get_empty_list_help(self, help_message):
""" Override of BaseModel.get_empty_list_help() to generate an help message
that adds alias information. """
model = self._context.get('empty_list_help_model')
res_id = self._context.get('empty_list_help_id')
catchall_domain = self.env['ir.config_parameter'].sudo().get_param("mail.catchall.domain")
document_name = self._context.get('empty_list_help_document_name', _('document'))
nothing_here = not help
nothing_here = is_html_empty(help_message)
alias = None
if catchall_domain and model and res_id: # specific res_id -> find its alias (i.e. section_id specified)
@@ -369,28 +369,28 @@ class MailThread(models.AbstractModel):
if alias:
email_link = "<a href='mailto:%(email)s'>%(email)s</a>" % {'email': alias.display_name}
if nothing_here:
return "<p class='o_view_nocontent_smiling_face'>%(dyn_help)s</p>" % {
return super().get_empty_list_help("<p class='o_view_nocontent_smiling_face'>%(dyn_help)s</p>" % {
'dyn_help': _("Add a new %(document)s or send an email to %(email_link)s",
document=document_name,
email_link=email_link,
)
}
})
# do not add alias two times if it was added previously
if "oe_view_nocontent_alias" not in help:
return "%(static_help)s<p class='oe_view_nocontent_alias'>%(dyn_help)s</p>" % {
'static_help': help,
if "oe_view_nocontent_alias" not in help_message:
return super().get_empty_list_help("%(static_help)s<p class='oe_view_nocontent_alias'>%(dyn_help)s</p>" % {
'static_help': help_message,
'dyn_help': _("Create new %(document)s by sending an email to %(email_link)s",
document=document_name,
email_link=email_link,
)
}
})
if nothing_here:
return "<p class='o_view_nocontent_smiling_face'>%(dyn_help)s</p>" % {
return super().get_empty_list_help("<p class='o_view_nocontent_smiling_face'>%(dyn_help)s</p>" % {
'dyn_help': _("Create new %(document)s", document=document_name),
}
})
return help
return super().get_empty_list_help(help_message)
# ------------------------------------------------------
# MODELS / CRUD HELPERS
+17 -4
View File
@@ -11,7 +11,7 @@
<sheet>
<div class="oe_button_box" name="button_box">
<button name="open_document" string="Open Document"
type="object" class="oe_link"
type="object" class="oe_link" icon="fa-sitemap"
attrs="{'invisible': ['|', ('alias_model_id', '=', False), ('alias_force_thread_id', '=', 0)]}"/>
<button name="open_parent_document" string="Open Parent Document"
type="object" class="oe_link" icon="fa-sitemap"
@@ -42,9 +42,18 @@
<tree string="Alias">
<field name="alias_name"/>
<field name="alias_model_id"/>
<field name="alias_force_thread_id" optional="hide"/>
<field name="alias_user_id"/>
<field name="alias_defaults"/>
<field name="alias_parent_model_id"/>
<field name="alias_parent_thread_id" optional="hide"/>
<field name="alias_defaults" optional="hide"/>
<field name="alias_contact"/>
<button name="open_document" type="object"
string="Open Document" icon="fa-sitemap"
attrs="{'invisible': ['|', ('alias_model_id', '=', False), ('alias_force_thread_id', '=', 0)]}"/>
<button name="open_parent_document" type="object"
string="Open Owner" icon="fa-sitemap"
attrs="{'invisible': ['|', ('alias_parent_model_id', '=', False), ('alias_parent_thread_id', '=', 0)]}"/>
</tree>
</field>
</record>
@@ -63,8 +72,12 @@
<separator/>
<filter string="Active" name="active" domain="[('alias_name', '!=', False)]"/>
<group expand="0" string="Group By">
<filter string="User" name="User" context="{'group_by':'alias_user_id'}"/>
<filter string="Model" name="Model" context="{'group_by':'alias_model_id'}"/>
<filter string="Owner" name="groupby_user_id"
context="{'group_by': 'alias_user_id'}"/>
<filter string="Document Model" name="groupby_alias_model_id"
context="{'group_by': 'alias_model_id'}"/>
<filter string="Container Model" name="groupby_alias_model_id"
context="{'group_by': 'alias_parent_model_id'}"/>
</group>
</search>
</field>
-1
View File
@@ -14,7 +14,6 @@
'security/maintenance.xml',
'security/ir.model.access.csv',
'data/maintenance_data.xml',
'data/mail_alias_data.xml',
'data/mail_activity_type_data.xml',
'data/mail_message_subtype_data.xml',
'views/maintenance_views.xml',
@@ -1,11 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<data noupdate="1">
<!-- email alias for maintenance requests -->
<record id="mail_alias_equipment" model="mail.alias">
<field name="alias_name">helpdesk</field>
<field name="alias_model_id" ref="model_maintenance_request"/>
<field name="alias_user_id" ref="base.user_admin"/>
</record>
</data>
</odoo>
+2 -2
View File
@@ -1901,11 +1901,11 @@ class MrpProduction(models.Model):
return action
@api.model
def get_empty_list_help(self, help):
def get_empty_list_help(self, help_message):
self = self.with_context(
empty_list_help_document_name=_("manufacturing order"),
)
return super(MrpProduction, self).get_empty_list_help(help)
return super(MrpProduction, self).get_empty_list_help(help_message)
def _log_downside_manufactured_quantity(self, moves_modification, cancel=False):
+2 -2
View File
@@ -644,11 +644,11 @@ class ProductProduct(models.Model):
return prices
@api.model
def get_empty_list_help(self, help):
def get_empty_list_help(self, help_message):
self = self.with_context(
empty_list_help_document_name=_("product"),
)
return super(ProductProduct, self).get_empty_list_help(help)
return super(ProductProduct, self).get_empty_list_help(help_message)
def get_product_multiline_description_sale(self):
""" Compute a multiline description of this product, in the context of sales
+2 -2
View File
@@ -1283,11 +1283,11 @@ class ProductTemplate(models.Model):
return {}
@api.model
def get_empty_list_help(self, help):
def get_empty_list_help(self, help_message):
self = self.with_context(
empty_list_help_document_name=_("product"),
)
return super(ProductTemplate, self).get_empty_list_help(help)
return super(ProductTemplate, self).get_empty_list_help(help_message)
@api.model
def get_import_templates(self):