Exemple #1
0
    def generate_recipients(self, results, res_ids):
        """Generates the recipients of the template. Default values can ben generated
        instead of the template values if requested by template or context.
        Emails (email_to, email_cc) can be transformed into partners if requested
        in the context. """
        self.ensure_one()

        if self.use_default_to or self._context.get('tpl_force_default_to'):
            default_recipients = self.env['mail.thread'].message_get_default_recipients(res_model=self.model, res_ids=res_ids)
            for res_id, recipients in default_recipients.items():
                results[res_id].pop('partner_to', None)
                results[res_id].update(recipients)

        records_company = None
        if self._context.get('tpl_partners_only') and self.model and results and 'company_id' in self.env[self.model]._fields:
            records = self.env[self.model].browse(results.keys()).read(['company_id'])
            records_company = {rec['id']: (rec['company_id'][0] if rec['company_id'] else None) for rec in records}

        for res_id, values in results.items():
            partner_ids = values.get('partner_ids', list())
            if self._context.get('tpl_partners_only'):
                mails = tools.email_split(values.pop('email_to', '')) + tools.email_split(values.pop('email_cc', ''))
                Partner = self.env['res.partner']
                if records_company:
                    Partner = Partner.with_context(default_company_id=records_company[res_id])
                for mail in mails:
                    partner_id = Partner.find_or_create(mail)
                    partner_ids.append(partner_id)
            partner_to = values.pop('partner_to', '')
            if partner_to:
                # placeholders could generate '', 3, 2 due to some empty field values
                tpl_partner_ids = [int(pid) for pid in partner_to.split(',') if pid]
                partner_ids += self.env['res.partner'].sudo().browse(tpl_partner_ids).exists().ids
            results[res_id]['partner_ids'] = partner_ids
        return results
Exemple #2
0
 def message_new(self, msg, custom_values=None):
     """ Overrides mail_thread message_new that is called by the mailgateway
         through message_process.
         This override updates the document according to the email.
     """
     if custom_values is None:
         custom_values = {}
     email = tools.email_split(msg.get('from')) and tools.email_split(msg.get('from'))[0] or False
     user = self.env['res.users'].search([('login', '=', email)], limit=1)
     if user:
         employee = self.env['hr.employee'].search([('user_id', '=', user.id)], limit=1)
         if employee:
             custom_values['employee_id'] = employee and employee[0].id
     return super(MaintenanceRequest, self).message_new(msg, custom_values=custom_values)
Exemple #3
0
 def send_mail_test(self):
     self.ensure_one()
     mails = self.env['mail.mail']
     mailing = self.mass_mailing_id
     test_emails = tools.email_split(self.email_to)
     mass_mail_layout = self.env.ref('mass_mailing.mass_mailing_mail_layout')
     for test_mail in test_emails:
         # Convert links in absolute URLs before the application of the shortener
         body = self.env['mail.thread']._replace_local_links(mailing.body_html)
         body = tools.html_sanitize(body, sanitize_attributes=True, sanitize_style=True)
         mail_values = {
             'email_from': mailing.email_from,
             'reply_to': mailing.reply_to,
             'email_to': test_mail,
             'subject': mailing.name,
             'body_html': mass_mail_layout.render({'body': body}, engine='ir.qweb', minimal_qcontext=True),
             'notification': True,
             'mailing_id': mailing.id,
             'attachment_ids': [(4, attachment.id) for attachment in mailing.attachment_ids],
             'auto_delete': True,
             'mail_server_id': mailing.mail_server_id.id,
         }
         mail = self.env['mail.mail'].create(mail_values)
         mails |= mail
     mails.send()
     return True
Exemple #4
0
    def message_route(self,
                      message,
                      message_dict,
                      model=None,
                      thread_id=None,
                      custom_values=None):
        """ Override to udpate mass mailing statistics based on bounce emails """
        bounce_alias = self.env['ir.config_parameter'].sudo().get_param(
            "mail.bounce.alias")
        email_to = decode_message_header(message, 'To')
        email_to_localparts = [
            e.split('@', 1)[0].lower()
            for e in (tools.email_split(email_to) or [''])
        ]

        if bounce_alias and any(
                email.startswith(bounce_alias)
                for email in email_to_localparts):
            bounce_re = re.compile(
                "%s\+(\d+)-?([\w.]+)?-?(\d+)?" % re.escape(bounce_alias),
                re.UNICODE)
            bounce_match = bounce_re.search(email_to)
            if bounce_match:
                bounced_mail_id = bounce_match.group(1)
                self.env['mail.mail.statistics'].set_bounced(
                    mail_mail_ids=[bounced_mail_id])

        return super(MailThread,
                     self).message_route(message, message_dict, model,
                                         thread_id, custom_values)
Exemple #5
0
 def _sanitize_email(self, email):
     """ Sanitize and standardize blacklist entries: all emails should be
     only real email extracted from strings (A <a@a> -> a@a)  and should be
     lower case. """
     emails = tools.email_split(email)
     if not emails or len(emails) != 1:
         return False
     return emails[0].lower()
Exemple #6
0
 def _send_prepare_values(self, partner=None):
     # TDE: temporary addition (mail was parameter) due to semi-new-API
     res = super(MailMail, self)._send_prepare_values(partner)
     base_url = self.env['ir.config_parameter'].sudo().get_param('web.base.url').rstrip('/')
     if self.mailing_id and res.get('body') and res.get('email_to'):
         emails = tools.email_split(res.get('email_to')[0])
         email_to = emails and emails[0] or False
         unsubscribe_url = self._get_unsubscribe_url(email_to)
         link_to_replace = base_url + '/unsubscribe_from_list'
         if link_to_replace in res['body']:
             res['body'] = res['body'].replace(link_to_replace, unsubscribe_url if unsubscribe_url else '#')
     return res
Exemple #7
0
 def _parse_partner_name(self, text, context=None):
     """ Supported syntax:
         - 'Raoul <*****@*****.**>': will find name and email address
         - otherwise: default, everything is set as the name """
     emails = tools.email_split(text.replace(' ', ','))
     if emails:
         email = emails[0]
         name = text[:text.index(email)].replace('"',
                                                 '').replace('<',
                                                             '').strip()
     else:
         name, email = text, ''
     return name, email
Exemple #8
0
 def _alias_check_contact_on_record(self, record, message, message_dict, alias):
     if alias.alias_contact == 'employees':
         email_from = tools.decode_message_header(message, 'From')
         email_address = tools.email_split(email_from)[0]
         employee = self.env['hr.employee'].search([('work_email', 'ilike', email_address)], limit=1)
         if not employee:
             employee = self.env['hr.employee'].search([('user_id.email', 'ilike', email_address)], limit=1)
         if not employee:
             return {
                 'error_message': 'restricted to employees',
                 'error_template': self.env.ref('hr.mail_template_data_unknown_employee_email_address').body_html,
             }
         return True
     return super(MailAlias, self)._alias_check_contact_on_record(record, message, message_dict, alias)
Exemple #9
0
    def find_or_create(self, email):
        """ Find a partner with the given ``email`` or use :py:method:`~.name_create`
            to create one

            :param str email: email-like string, which should contain at least one email,
                e.g. ``"Raoul Grosbedon <*****@*****.**>"``"""
        assert email, 'an email is required for find_or_create to work'
        emails = tools.email_split(email)
        name_emails = tools.email_split_and_format(email)
        if emails:
            email = emails[0]
            name_email = name_emails[0]
        else:
            name_email = email
        partners = self.search([('email', '=ilike', email)], limit=1)
        return partners.id or self.name_create(name_email)[0]
Exemple #10
0
    def message_new(self, msg_dict, custom_values=None):
        if custom_values is None:
            custom_values = {}

        email_address = email_split(msg_dict.get('email_from', False))[0]

        employee = self.env['hr.employee'].search([
            '|', ('work_email', 'ilike', email_address),
            ('user_id.email', 'ilike', email_address)
        ],
                                                  limit=1)
        # The expenses alias is the same for all companies, we need to set the proper context
        company = employee.company_id or self.env.user.company_id
        self = self.with_context(force_company=company.id)

        expense_description = msg_dict.get('subject', '')

        # Match the first occurence of '[]' in the string and extract the content inside it
        # Example: '[foo] bar (baz)' becomes 'foo'. This is potentially the product code
        # of the product to encode on the expense. If not, take the default product instead
        # which is 'Fixed Cost'
        default_product = self.env.ref('hr_expense.product_product_fixed_cost')
        pattern = '\[([^)]*)\]'
        product_code = re.search(pattern, expense_description)
        if product_code is None:
            product = default_product
        else:
            expense_description = expense_description.replace(
                product_code.group(), '')
            products = self.env['product.product'].search([
                ('default_code', 'ilike', product_code.group(1))
            ]) or default_product
            product = products.filtered(lambda p: p.default_code ==
                                        product_code.group(1)) or products[0]
        account = product.product_tmpl_id._get_product_accounts()['expense']

        pattern = '[-+]?(\d+(\.\d*)?|\.\d+)([eE][-+]?\d+)?'
        # Match the last occurence of a float in the string
        # Example: '[foo] 50.3 bar 34.5' becomes '34.5'. This is potentially the price
        # to encode on the expense. If not, take 1.0 instead
        expense_price = re.findall(pattern, expense_description)
        # TODO: International formatting
        if not expense_price:
            price = 1.0
        else:
            price = expense_price[-1][0]
            expense_description = expense_description.replace(price, '')
            try:
                price = float(price)
            except ValueError:
                price = 1.0

        custom_values.update({
            'name':
            expense_description.strip(),
            'employee_id':
            employee.id,
            'product_id':
            product.id,
            'product_uom_id':
            product.uom_id.id,
            'tax_ids':
            [(4, tax.id, False) for tax in product.supplier_taxes_id],
            'quantity':
            1,
            'unit_amount':
            price,
            'company_id':
            employee.company_id.id,
            'currency_id':
            employee.company_id.currency_id.id,
        })
        if account:
            custom_values['account_id'] = account.id
        return super(HrExpense, self).message_new(msg_dict, custom_values)
    def get_mail_values(self, res_ids):
        """ Override method that generated the mail content by creating the
        mail.mail.statistics values in the o2m of mail_mail, when doing pure
        email mass mailing. """
        self.ensure_one()
        res = super(MailComposeMessage, self).get_mail_values(res_ids)
        # use only for allowed models in mass mailing
        if self.composition_mode == 'mass_mail' and \
                (self.mass_mailing_name or self.mass_mailing_id) and \
                self.env['ir.model'].sudo().search([('model', '=', self.model), ('is_mail_thread', '=', True)], limit=1):
            mass_mailing = self.mass_mailing_id
            if not mass_mailing:
                reply_to_mode = 'email' if self.no_auto_thread else 'thread'
                reply_to = self.reply_to if self.no_auto_thread else False
                mass_mailing = self.env['mail.mass_mailing'].create({
                    'mass_mailing_campaign_id':
                    self.mass_mailing_campaign_id.id,
                    'name':
                    self.mass_mailing_name,
                    'template_id':
                    self.template_id.id,
                    'state':
                    'done',
                    'reply_to_mode':
                    reply_to_mode,
                    'reply_to':
                    reply_to,
                    'sent_date':
                    fields.Datetime.now(),
                    'body_html':
                    self.body,
                    'mailing_model_id':
                    self.env['ir.model']._get(self.model).id,
                    'mailing_domain':
                    self.active_domain,
                })

            # Preprocess res.partners to batch-fetch from db
            # if recipient_ids is present, it means they are partners
            # (the only object to fill get_default_recipient this way)
            recipient_partners_ids = []
            read_partners = {}
            for res_id in res_ids:
                mail_values = res[res_id]
                if mail_values.get('recipient_ids'):
                    # recipient_ids is a list of x2m command tuples at this point
                    recipient_partners_ids.append(
                        mail_values.get('recipient_ids')[0][1])
            read_partners = self.env['res.partner'].browse(
                recipient_partners_ids)

            partners_email = {p.id: p.email for p in read_partners}

            opt_out_list = self._context.get('mass_mailing_opt_out_list')
            seen_list = self._context.get('mass_mailing_seen_list')
            mass_mail_layout = self.env.ref(
                'mass_mailing.mass_mailing_mail_layout',
                raise_if_not_found=False)
            for res_id in res_ids:
                mail_values = res[res_id]
                if mail_values.get('email_to'):
                    recips = tools.email_split(mail_values['email_to'])
                else:
                    partner_id = (mail_values.get('recipient_ids')
                                  or [(False, '')])[0][1]
                    recips = tools.email_split(partners_email.get(partner_id))
                mail_to = recips[0].lower() if recips else False
                if (opt_out_list and mail_to in opt_out_list) or (seen_list and mail_to in seen_list) \
                        or (not mail_to or not email_re.findall(mail_to)):
                    # prevent sending to blocked addresses that were included by mistake
                    mail_values['state'] = 'cancel'
                elif seen_list is not None:
                    seen_list.add(mail_to)
                stat_vals = {
                    'model': self.model,
                    'res_id': res_id,
                    'mass_mailing_id': mass_mailing.id,
                    'email': mail_to,
                }
                if mail_values.get('body_html') and mass_mail_layout:
                    mail_values['body_html'] = mass_mail_layout.render(
                        {'body': mail_values['body_html']},
                        engine='ir.qweb',
                        minimal_qcontext=True)
                # propagate ignored state to stat when still-born
                if mail_values.get('state') == 'cancel':
                    stat_vals['ignored'] = fields.Datetime.now()
                mail_values.update({
                    'mailing_id':
                    mass_mailing.id,
                    'statistics_ids': [(0, 0, stat_vals)],
                    # email-mode: keep original message for routing
                    'notification':
                    mass_mailing.reply_to_mode == 'thread',
                    'auto_delete':
                    not mass_mailing.keep_archives,
                })
        return res
Exemple #12
0
 def email_split(self, msg):
     email_list = tools.email_split((msg.get('to') or '') + ',' + (msg.get('cc') or ''))
     # check left-part is not already an alias
     aliases = self.mapped('project_id.alias_name')
     return [x for x in email_list if x.split('@')[0] not in aliases]
Exemple #13
0
def extract_email(email):
    """ extract the email address from a user-friendly email address """
    addresses = email_split(email)
    return addresses[0] if addresses else ''