mirror of
https://github.com/bringout/oca-ocb-core.git
synced 2026-04-23 05:52:05 +02:00
19.0 vanilla
This commit is contained in:
parent
d1963a3c3a
commit
2d3ee4855a
7430 changed files with 2687981 additions and 2965473 deletions
|
|
@ -7,6 +7,7 @@ import werkzeug
|
|||
|
||||
from odoo import api, fields, models, tools, _
|
||||
from odoo.exceptions import UserError
|
||||
from odoo.tools.mail import email_split_and_format, email_normalize
|
||||
|
||||
_logger = logging.getLogger(__name__)
|
||||
|
||||
|
|
@ -15,7 +16,7 @@ emails_split = re.compile(r"[;,\n\r]+")
|
|||
|
||||
class SurveyInvite(models.TransientModel):
|
||||
_name = 'survey.invite'
|
||||
_inherit = 'mail.composer.mixin'
|
||||
_inherit = ['mail.composer.mixin']
|
||||
_description = 'Survey Invitation Wizard'
|
||||
|
||||
@api.model
|
||||
|
|
@ -25,10 +26,8 @@ class SurveyInvite(models.TransientModel):
|
|||
# composer content
|
||||
attachment_ids = fields.Many2many(
|
||||
'ir.attachment', 'survey_mail_compose_message_ir_attachments_rel', 'wizard_id', 'attachment_id',
|
||||
string='Attachments', compute='_compute_attachment_ids', store=True, readonly=False)
|
||||
string='Attachments', compute='_compute_attachment_ids', store=True, readonly=False, bypass_search_access=True)
|
||||
# origin
|
||||
email_from = fields.Char(
|
||||
'From', compute='_compute_email_from', readonly=False, store=True)
|
||||
author_id = fields.Many2one(
|
||||
'res.partner', 'Author', index=True,
|
||||
ondelete='set null', default=_get_default_author)
|
||||
|
|
@ -43,15 +42,14 @@ class SurveyInvite(models.TransientModel):
|
|||
)
|
||||
existing_partner_ids = fields.Many2many(
|
||||
'res.partner', compute='_compute_existing_partner_ids', readonly=True, store=False)
|
||||
emails = fields.Text(string='Additional emails', help="This list of emails of recipients will not be converted in contacts.\
|
||||
Emails must be separated by commas, semicolons or newline.")
|
||||
emails = fields.Text(string='Additional emails')
|
||||
existing_emails = fields.Text(
|
||||
'Existing emails', compute='_compute_existing_emails',
|
||||
readonly=True, store=False)
|
||||
existing_mode = fields.Selection([
|
||||
('new', 'New invite'), ('resend', 'Resend invite')],
|
||||
string='Handle existing', default='resend', required=True)
|
||||
existing_text = fields.Text('Resend Comment', compute='_compute_existing_text', readonly=True, store=False)
|
||||
existing_text = fields.Text('Resend Comment', compute='_compute_existing_text')
|
||||
# technical info
|
||||
mail_server_id = fields.Many2one('ir.mail_server', 'Outgoing mail server')
|
||||
# survey
|
||||
|
|
@ -61,45 +59,51 @@ class SurveyInvite(models.TransientModel):
|
|||
survey_users_login_required = fields.Boolean(related="survey_id.users_login_required", readonly=True)
|
||||
survey_users_can_signup = fields.Boolean(related='survey_id.users_can_signup')
|
||||
deadline = fields.Datetime(string="Answer deadline")
|
||||
send_email = fields.Boolean(compute="_compute_send_email",
|
||||
inverse="_inverse_send_email")
|
||||
|
||||
@api.depends('survey_access_mode')
|
||||
def _compute_send_email(self):
|
||||
for record in self:
|
||||
record.send_email = record.survey_access_mode == 'token'
|
||||
|
||||
def _inverse_send_email(self):
|
||||
pass
|
||||
|
||||
@api.depends('partner_ids', 'survey_id')
|
||||
def _compute_existing_partner_ids(self):
|
||||
self.existing_partner_ids = list(set(self.survey_id.user_input_ids.partner_id.ids) & set(self.partner_ids.ids))
|
||||
|
||||
@api.depends('template_id.email_from')
|
||||
def _compute_email_from(self):
|
||||
if self.template_id.email_from:
|
||||
self.email_from = self.template_id.email_from
|
||||
else:
|
||||
self.email_from = self.env.user.email_formatted
|
||||
for wizard in self:
|
||||
wizard.existing_partner_ids = list(set(wizard.survey_id.user_input_ids.partner_id.ids) & set(wizard.partner_ids.ids))
|
||||
|
||||
@api.depends('emails', 'survey_id')
|
||||
def _compute_existing_emails(self):
|
||||
emails = list(set(emails_split.split(self.emails or "")))
|
||||
existing_emails = self.survey_id.mapped('user_input_ids.email')
|
||||
self.existing_emails = '\n'.join(email for email in emails if email in existing_emails)
|
||||
for wizard in self:
|
||||
emails = list(set(emails_split.split(wizard.emails or "")))
|
||||
existing_emails = wizard.survey_id.mapped('user_input_ids.email')
|
||||
wizard.existing_emails = '\n'.join(email for email in emails if email in existing_emails)
|
||||
|
||||
@api.depends('existing_partner_ids', 'existing_emails')
|
||||
def _compute_existing_text(self):
|
||||
existing_text = False
|
||||
if self.existing_partner_ids:
|
||||
existing_text = '%s: %s.' % (
|
||||
_('The following customers have already received an invite'),
|
||||
', '.join(self.mapped('existing_partner_ids.name'))
|
||||
)
|
||||
if self.existing_emails:
|
||||
existing_text = '%s\n' % existing_text if existing_text else ''
|
||||
existing_text += '%s: %s.' % (
|
||||
_('The following emails have already received an invite'),
|
||||
self.existing_emails
|
||||
)
|
||||
for wizard in self:
|
||||
existing_text = False
|
||||
if wizard.existing_partner_ids:
|
||||
existing_text = '%s: %s.' % (
|
||||
_('The following customers have already received an invite'),
|
||||
', '.join(wizard.mapped('existing_partner_ids.name'))
|
||||
)
|
||||
if wizard.existing_emails:
|
||||
existing_text = '%s\n' % existing_text if existing_text else ''
|
||||
existing_text += '%s: %s.' % (
|
||||
_('The following emails have already received an invite'),
|
||||
wizard.existing_emails
|
||||
)
|
||||
|
||||
self.existing_text = existing_text
|
||||
wizard.existing_text = existing_text
|
||||
|
||||
@api.depends('survey_id.access_token')
|
||||
def _compute_survey_start_url(self):
|
||||
for invite in self:
|
||||
invite.survey_start_url = werkzeug.urls.url_join(invite.survey_id.get_base_url(), invite.survey_id.get_start_url()) if invite.survey_id else False
|
||||
invite.survey_start_url = tools.urls.urljoin(invite.survey_id.get_base_url(), invite.survey_id.get_start_url()) if invite.survey_id else False
|
||||
|
||||
# Overrides of mail.composer.mixin
|
||||
@api.depends('survey_id') # fake trigger otherwise not computed in new mode
|
||||
|
|
@ -115,13 +119,13 @@ class SurveyInvite(models.TransientModel):
|
|||
valid, error = [], []
|
||||
emails = list(set(emails_split.split(self.emails or "")))
|
||||
for email in emails:
|
||||
email_check = tools.email_split_and_format(email)
|
||||
email_check = email_split_and_format(email)
|
||||
if not email_check:
|
||||
error.append(email)
|
||||
else:
|
||||
valid.extend(email_check)
|
||||
if error:
|
||||
raise UserError(_("Some emails you just entered are incorrect: %s") % (', '.join(error)))
|
||||
raise UserError(_("Some emails you just entered are incorrect: %s", ', '.join(error)))
|
||||
self.emails = '\n'.join(valid)
|
||||
|
||||
@api.onchange('partner_ids')
|
||||
|
|
@ -152,10 +156,10 @@ class SurveyInvite(models.TransientModel):
|
|||
@api.depends('template_id', 'partner_ids')
|
||||
def _compute_subject(self):
|
||||
for invite in self:
|
||||
langs = set(invite.partner_ids.mapped('lang')) - {False}
|
||||
if len(langs) == 1:
|
||||
invite = invite.with_context(lang=langs.pop())
|
||||
super(SurveyInvite, invite)._compute_subject()
|
||||
if invite.template_id and invite.template_id.subject:
|
||||
invite.subject = invite.template_id.subject
|
||||
else:
|
||||
invite.subject = _("Participate to %(survey_name)s", survey_name=invite.survey_id.display_name)
|
||||
|
||||
@api.depends('template_id', 'partner_ids')
|
||||
def _compute_body(self):
|
||||
|
|
@ -182,13 +186,23 @@ class SurveyInvite(models.TransientModel):
|
|||
# ------------------------------------------------------
|
||||
|
||||
def _prepare_answers(self, partners, emails):
|
||||
answers = self.env['survey.user_input']
|
||||
existing_answers = self.env['survey.user_input'].search([
|
||||
'&', ('survey_id', '=', self.survey_id.id),
|
||||
'|',
|
||||
('partner_id', 'in', partners.ids),
|
||||
('email', 'in', emails)
|
||||
])
|
||||
partners_done, emails_done, answers = self._get_done_partners_emails(existing_answers)
|
||||
|
||||
for new_partner in partners - partners_done:
|
||||
answers |= self.survey_id._create_answer(partner=new_partner, check_attempts=False, **self._get_answers_values())
|
||||
for new_email in [email for email in emails if email not in emails_done]:
|
||||
answers |= self.survey_id._create_answer(email=new_email, check_attempts=False, **self._get_answers_values())
|
||||
|
||||
return answers
|
||||
|
||||
def _get_done_partners_emails(self, existing_answers):
|
||||
answers = self.env['survey.user_input']
|
||||
partners_done = self.env['res.partner']
|
||||
emails_done = []
|
||||
if existing_answers:
|
||||
|
|
@ -207,13 +221,7 @@ class SurveyInvite(models.TransientModel):
|
|||
answers |= next(existing_answer for existing_answer in
|
||||
existing_answers.sorted(lambda answer: answer.create_date, reverse=True)
|
||||
if existing_answer.email == email_done)
|
||||
|
||||
for new_partner in partners - partners_done:
|
||||
answers |= self.survey_id._create_answer(partner=new_partner, check_attempts=False, **self._get_answers_values())
|
||||
for new_email in [email for email in emails if email not in emails_done]:
|
||||
answers |= self.survey_id._create_answer(email=new_email, check_attempts=False, **self._get_answers_values())
|
||||
|
||||
return answers
|
||||
return (partners_done, emails_done, answers)
|
||||
|
||||
def _get_answers_values(self):
|
||||
return {
|
||||
|
|
@ -222,21 +230,21 @@ class SurveyInvite(models.TransientModel):
|
|||
|
||||
def _send_mail(self, answer):
|
||||
""" Create mail specific for recipient containing notably its access token """
|
||||
email_from = self._render_field('email_from', answer.ids)[answer.id]
|
||||
email_from = self.template_id._render_field('email_from', answer.ids)[answer.id] if self.template_id.email_from else self.author_id.email_formatted
|
||||
if not email_from:
|
||||
raise UserError(_("Unable to post message, please configure the sender's email address."))
|
||||
subject = self._render_field('subject', answer.ids)[answer.id]
|
||||
body = self._render_field('body', answer.ids, post_process=True)[answer.id]
|
||||
body = self._render_field('body', answer.ids)[answer.id]
|
||||
# post the message
|
||||
mail_values = {
|
||||
'email_from': email_from,
|
||||
'attachment_ids': [(4, att.id) for att in self.attachment_ids],
|
||||
'auto_delete': True,
|
||||
'author_id': self.author_id.id,
|
||||
'body_html': body,
|
||||
'email_from': email_from,
|
||||
'model': None,
|
||||
'res_id': None,
|
||||
'subject': subject,
|
||||
'body_html': body,
|
||||
'attachment_ids': [(4, att.id) for att in self.attachment_ids],
|
||||
'auto_delete': True,
|
||||
}
|
||||
if answer.partner_id:
|
||||
mail_values['recipient_ids'] = [(4, answer.partner_id.id)]
|
||||
|
|
@ -246,17 +254,10 @@ class SurveyInvite(models.TransientModel):
|
|||
# optional support of default_email_layout_xmlid in context
|
||||
email_layout_xmlid = self.env.context.get('default_email_layout_xmlid', self.env.context.get('notif_layout'))
|
||||
if email_layout_xmlid:
|
||||
template_ctx = {
|
||||
'message': self.env['mail.message'].sudo().new(dict(body=mail_values['body_html'], record_name=self.survey_id.title)),
|
||||
'model_description': self.env['ir.model']._get('survey.survey').display_name,
|
||||
'company': self.env.company,
|
||||
}
|
||||
body = self.env['ir.qweb']._render(email_layout_xmlid, template_ctx, minimal_qcontext=True, raise_if_not_found=False)
|
||||
if body:
|
||||
mail_values['body_html'] = self.env['mail.render.mixin']._replace_local_links(body)
|
||||
else:
|
||||
_logger.warning('QWeb template %s not found or is empty when sending survey mails. Sending without layout', email_layout_xmlid)
|
||||
|
||||
mail_values['body_html'] = self._render_encapsulate(
|
||||
email_layout_xmlid, mail_values['body_html'],
|
||||
context_record=self.survey_id,
|
||||
)
|
||||
return self.env['mail.mail'].sudo().create(mail_values)
|
||||
|
||||
def action_invite(self):
|
||||
|
|
@ -273,14 +274,14 @@ class SurveyInvite(models.TransientModel):
|
|||
valid_emails = []
|
||||
for email in emails_split.split(self.emails or ''):
|
||||
partner = False
|
||||
email_normalized = tools.email_normalize(email)
|
||||
email_normalized = email_normalize(email)
|
||||
if email_normalized:
|
||||
limit = None if self.survey_users_login_required else 1
|
||||
partner = Partner.search([('email_normalized', '=', email_normalized)], limit=limit)
|
||||
if partner:
|
||||
valid_partners |= partner
|
||||
else:
|
||||
email_formatted = tools.email_split_and_format(email)
|
||||
email_formatted = email_split_and_format(email)
|
||||
if email_formatted:
|
||||
valid_emails.extend(email_formatted)
|
||||
|
||||
|
|
|
|||
|
|
@ -8,45 +8,55 @@
|
|||
<form string="Compose Email" class="o_mail_composer_form">
|
||||
<group col="1">
|
||||
<group col="2">
|
||||
<field name="author_id" invisible="1"/>
|
||||
<field name="survey_access_mode" invisible="1"/>
|
||||
<field name="survey_users_login_required" invisible="1"/>
|
||||
<field name="survey_users_can_signup" invisible="1"/>
|
||||
<field name="survey_id" readonly="context.get('default_survey_id')"/>
|
||||
<field name="survey_id" invisible="1"/>
|
||||
<field name="existing_mode" widget="radio" invisible="1" />
|
||||
<field name="lang" invisible="1"/>
|
||||
<field name="render_model" invisible="1"/>
|
||||
<field name="survey_start_url" label="Public share URL" readonly="1" widget="CopyClipboardChar"
|
||||
attrs="{'invisible':[('survey_access_mode', '!=', 'public')]}"
|
||||
class="mb16"/>
|
||||
<label class="o_survey_label_survey_start_url" for="survey_start_url" string="Survey Link"
|
||||
invisible="survey_access_mode != 'public'"/>
|
||||
<field name="survey_start_url" nolabel="1" widget="CopyClipboardChar"
|
||||
readonly="1"
|
||||
invisible="survey_access_mode != 'public'"/>
|
||||
<field string="Send by Email" name="send_email" widget="boolean_toggle" options="{'autosave': False}"
|
||||
invisible="survey_access_mode != 'public'"/>
|
||||
<field name="partner_ids"
|
||||
widget="many2many_tags_email"
|
||||
placeholder="Add existing contacts..."
|
||||
context="{'force_email':True, 'show_email':True, 'no_create_edit': True}"/>
|
||||
placeholder="Add existing contacts..." options="{'no_quick_create': True}"
|
||||
context="{'show_email': True, 'form_view_ref': 'base.view_partner_simple_form'}"
|
||||
required="True"
|
||||
invisible="not send_email"/>
|
||||
<field name="emails"
|
||||
attrs="{
|
||||
'invisible': [('survey_users_login_required', '=', True)],
|
||||
}"
|
||||
placeholder="Add a list of email recipients (separated by commas, semicolons or line breaks). They will not be converted into contacts."/>
|
||||
invisible="survey_users_login_required or not send_email"
|
||||
placeholder="e.g. 'Rick Sanchez' <rick_sanchez@example.com>, hictor_vugo@example.com"/>
|
||||
</group>
|
||||
<field name="existing_partner_ids" invisible="1"/>
|
||||
<field name="existing_emails" invisible="1"/>
|
||||
<div col="2" class="alert alert-warning" role="alert"
|
||||
attrs="{'invisible': ['|', ('survey_access_mode', '=', 'public'), ('existing_text', '=', False)]}">
|
||||
invisible="survey_access_mode == 'public' or not existing_text">
|
||||
<field name="existing_text"/>
|
||||
<group col="2">
|
||||
<label for="existing_mode" string="Handle existing"/>
|
||||
<div>
|
||||
<field name="existing_mode" nolabel="1"/>
|
||||
<p attrs="{'invisible': [('existing_mode', '!=', 'resend')]}">Customers will receive the same token.</p>
|
||||
<p attrs="{'invisible': [('existing_mode', '!=', 'new')]}">Customers will receive a new token and be able to completely retake the survey.</p>
|
||||
<p invisible="existing_mode != 'resend'">Customers will receive the same token.</p>
|
||||
<p invisible="existing_mode != 'new'">Customers will receive a new token and be able to completely retake the survey.</p>
|
||||
</div>
|
||||
</group>
|
||||
<field name="existing_partner_ids" invisible="1"/>
|
||||
<field name="existing_emails" invisible="1"/>
|
||||
</div>
|
||||
<group col="2">
|
||||
<field name="subject" placeholder="Subject..."/>
|
||||
<field name="subject" invisible="not send_email" placeholder="Subject..."/>
|
||||
</group>
|
||||
<field name="can_edit_body" invisible="1"/>
|
||||
<field name="body" class="oe-bordered-editor" options="{'style-inline': true, 'height': 380}" attrs="{'readonly': [('can_edit_body', '=', False)]}" force_save="1"/>
|
||||
<group>
|
||||
<field name="body" class="oe-bordered-editor border border-1 m-3 p-0 flex-fill"
|
||||
widget="html_mail"
|
||||
options="{'height': 380}"
|
||||
invisible="not send_email"
|
||||
readonly="not can_edit_body" force_save="1"/>
|
||||
<group invisible="not send_email">
|
||||
<group>
|
||||
<field name="attachment_ids" widget="many2many_binary"/>
|
||||
</group>
|
||||
|
|
@ -57,11 +67,12 @@
|
|||
</group>
|
||||
</group>
|
||||
<footer>
|
||||
<button string="Send" name="action_invite" type="object" class="btn-primary" data-hotkey="q"/>
|
||||
<button string="Cancel" class="btn-secondary" special="cancel" data-hotkey="z"/>
|
||||
<button string="Send" invisible="not send_email" name="action_invite" type="object" class="btn-primary" data-hotkey="q"/>
|
||||
<button string="Close" class="btn-secondary" special="cancel" data-hotkey="x"/>
|
||||
</footer>
|
||||
</form>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
</data>
|
||||
</odoo>
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue