Example #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)

        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', ''))
                for mail in mails:
                    partner_id = self.env['res.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
Example #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)
Example #3
0
    def message_route_verify(self, message, message_dict, route,
                             update_author=True, assert_model=True,
                             create_fallback=True, allow_private=False,
                             drop_alias=False):
        res = super(MailThread, self).message_route_verify(
            message, message_dict, route,
            update_author=update_author,
            assert_model=assert_model,
            create_fallback=create_fallback,
            allow_private=allow_private,
            drop_alias=drop_alias)

        if res:
            alias = route[4]
            email_from = decode_message_header(message, 'From')
            message_id = message.get('Message-Id')

            # Alias: check alias_contact settings for employees
            if alias and alias.alias_contact == 'employees':
                email_address = 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:
                    mail_template = self.env.ref('hr.mail_template_data_unknown_employee_email_address')
                    self._routing_warn(_('alias %s does not accept unknown employees') % alias.alias_name, _('skipping'), message_id, route, False)
                    self._routing_create_bounce_email(email_from, mail_template.body_html, message)
                    return False
        return res
Example #4
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
         mailing.write({'body_html': self.env['mail.thread']._replace_local_links(mailing.body_html)})
         body = tools.html_sanitize(mailing.body_html, 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 = self.env['mail.mail'].create(mail_values)
         mails |= mail
     mails.send()
     return True
Example #5
0
 def _extract_moderation_values(self, message_type, **kwargs):
     """ This method is used to compute moderation status before the creation
     of a message.  For this operation the message's author email address is required.
     This address is returned with status for other computations. """
     moderation_status = 'accepted'
     email = ''
     if self.moderation and message_type in ['email', 'comment']:
         author_id = kwargs.get('author_id')
         if author_id and isinstance(author_id, pycompat.integer_types):
             email = self.env['res.partner'].browse([author_id]).email
         elif author_id:
             email = author_id.email
         elif kwargs.get('email_from'):
             email = tools.email_split(kwargs['email_from'])[0]
         else:
             email = self.env.user.email
         if email in self.mapped('moderator_ids.email'):
             return moderation_status, email
         status = self.env['mail.moderation'].sudo().search([('email', '=', email), ('channel_id', 'in', self.ids)]).mapped('status')
         if status and status[0] == 'allow':
             moderation_status = 'accepted'
         elif status and status[0] == 'ban':
             moderation_status = 'rejected'
         else:
             moderation_status = 'pending_moderation'
     return moderation_status, email
Example #6
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)
     for test_mail in test_emails:
         # Convert links in absolute URLs before the application of the shortener
         mailing.write({'body_html': self.env['mail.template']._replace_local_links(mailing.body_html)})
         mail_values = {
             'email_from': mailing.email_from,
             'reply_to': mailing.reply_to,
             'email_to': test_mail,
             'subject': mailing.name,
             'body_html': '',
             'notification': True,
             'mailing_id': mailing.id,
             'attachment_ids': [(4, attachment.id) for attachment in mailing.attachment_ids],
         }
         mail = self.env['mail.mail'].create(mail_values)
         unsubscribe_url = mail._get_unsubscribe_url(test_mail)
         body = tools.append_content_to_html(mailing.body_html, unsubscribe_url, plaintext=False, container_tag='p')
         mail.write({'body_html': body})
         mails |= mail
     mails.send()
     return True
Example #7
0
    def message_new(self, msg_dict, custom_values=None):
        if custom_values is None:
            custom_values = {}

        # Retrieve the email address from the email field. The string is constructed like
        # 'foo <bar>'. We will extract 'bar' from this
        email_address = email_split(msg_dict.get('email_from', False))[0]

        # Look after an employee who has this email address or an employee for whom the related
        # user has this email address. In the case not employee is found, we send back an email
        # to explain that the expense will not be created.
        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:
            # Send back an email to explain why the expense has not been created
            mail_template = self.env.ref('hr_expense.mail_template_data_expense_unknown_email_address')
            mail_template.with_context(email_to=email_address).send_mail(self.env.ref('base.module_hr_expense').id)
            return False

        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(), '')
            product = self.env['product.product'].search([('default_code', 'ilike', product_code.group(1))]) or default_product

        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,
            'quantity': 1,
            'unit_amount': price
        })
        return super(HrExpense, self).message_new(msg_dict, custom_values)
Example #8
0
 def _update_moderation_email(self, emails, status):
     """ This method adds emails into either white or black of the channel list of emails 
         according to status. If an email in emails is already moderated, the method updates the email status.
         :param emails: list of email addresses to put in white or black list of channel.
         :param status: value is 'allow' or 'ban'. Emails are put in white list if 'allow', in black list if 'ban'.
     """
     self.ensure_one()
     splitted_emails = [tools.email_split(email)[0] for email in emails if tools.email_split(email)]
     moderated = self.env['mail.moderation'].sudo().search([
         ('email', 'in', splitted_emails),
         ('channel_id', 'in', self.ids)
     ])
     cmds = [(1, record.id, {'status': status}) for record in moderated]
     not_moderated = [email for email in splitted_emails if email not in moderated.mapped('email')]
     cmds += [(0, 0, {'email': email, 'status': status}) for email in not_moderated]
     return self.write({'moderation_ids': cmds})
Example #9
0
    def generate_data(self, event, isCreating=False):
        if event.allday:
            start_date = event.start_date
            final_date = (
                datetime.strptime(event.stop_date, tools.DEFAULT_SERVER_DATE_FORMAT) + timedelta(days=1)
            ).strftime(tools.DEFAULT_SERVER_DATE_FORMAT)
            type = "date"
            vstype = "dateTime"
        else:
            start_date = fields.Datetime.context_timestamp(self, fields.Datetime.from_string(event.start)).isoformat(
                "T"
            )
            final_date = fields.Datetime.context_timestamp(self, fields.Datetime.from_string(event.stop)).isoformat("T")
            type = "dateTime"
            vstype = "date"
        attendee_list = []
        for attendee in event.attendee_ids:
            email = tools.email_split(attendee.email)
            email = email[0] if email else "*****@*****.**"
            attendee_list.append(
                {
                    "email": email,
                    "displayName": attendee.partner_id.name,
                    "responseStatus": attendee.state or "needsAction",
                }
            )

        reminders = []
        for alarm in event.alarm_ids:
            reminders.append(
                {"method": "email" if alarm.type == "email" else "popup", "minutes": alarm.duration_minutes}
            )
        data = {
            "summary": event.name or "",
            "description": event.description or "",
            "start": {type: start_date, vstype: None, "timeZone": self.env.context.get("tz") or "UTC"},
            "end": {type: final_date, vstype: None, "timeZone": self.env.context.get("tz") or "UTC"},
            "attendees": attendee_list,
            "reminders": {"overrides": reminders, "useDefault": "false"},
            "location": event.location or "",
            "visibility": event["privacy"] or "public",
        }
        if event.recurrency and event.rrule:
            data["recurrence"] = ["RRULE:" + event.rrule]

        if not event.active:
            data["state"] = "cancelled"

        if not self.get_need_synchro_attendee():
            data.pop("attendees")
        if isCreating:
            other_google_ids = [
                other_att.google_internal_event_id
                for other_att in event.attendee_ids
                if other_att.google_internal_event_id
            ]
            if other_google_ids:
                data["id"] = other_google_ids[0]
        return data
Example #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)

        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,
        })
        if account:
            custom_values['account_id'] = account.id
        return super(HrExpense, self).message_new(msg_dict, custom_values)
Example #11
0
 def test_email_split(self):
     cases = [
         ("John <*****@*****.**>", ['*****@*****.**']),  # regular form
         ("d@x; 1@2", ['d@x', '1@2']),  # semi-colon + extra space
         ("'(ss)' <*****@*****.**>, 'foo' <foo@bar>", ['*****@*****.**', 'foo@bar']),  # comma + single-quoting
         ('"*****@*****.**"<*****@*****.**>', ['*****@*****.**']),  # double-quoting
         ('"<jg>" <*****@*****.**>', ['*****@*****.**']),  # double-quoting with brackets
     ]
     for text, expected in cases:
         self.assertEqual(email_split(text), expected, 'email_split is broken')
Example #12
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
Example #13
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)
        if emails:
            email = emails[0]
        partners = self.search([('email', '=ilike', email)], limit=1)
        return partners.id or self.name_create(email)[0]
Example #14
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
Example #15
0
 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.model in [item[0] for item in self.env['mail.mass_mailing']._get_mailing_model()]:
         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': self.model,
                     'mailing_domain': self.active_domain,
             })
         blacklist = self._context.get('mass_mailing_blacklist')
         seen_list = self._context.get('mass_mailing_seen_list')
         for res_id in res_ids:
             mail_values = res[res_id]
             recips = tools.email_split(mail_values.get('email_to'))
             mail_to = recips[0].lower() if recips else False
             if (blacklist and mail_to in blacklist) or (seen_list and mail_to in seen_list):
                 # 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
             }
             # propagate exception state to stat when still-born
             if mail_values.get('state') == 'cancel':
                 stat_vals['exception'] = 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
 def message_new(self, msg_dict, custom_values=None):
     self = self.with_context(default_user_id=False)
     if custom_values is None:
         custom_values = {}
     regex = re.compile("^\[(.*)\]")
     match = regex.match(msg_dict.get('subject')).group(1)
     book_id = self.env['library.book'].search(
         [('name', '=', match), ('state', '=', 'available')], limit=1)
     custom_values['book_id'] = book_id.id
     email_from = email_escape_char(email_split(msg_dict.get('from'))[0])
     custom_values['borrower_id'] = self._search_on_partner(email_from)
     return super(LibraryBookRent,
                  self).message_new(msg_dict, custom_values)
Example #17
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
Example #18
0
 def send(self, auto_commit=False, raise_exception=False):
     """
     Prevents deleting emails for better control.
     Sends a CC to all linked contacts that have option activated.
     """
     self.write({"auto_delete": False})
     for mail in self:
         cc = mail.recipient_ids.mapped("other_contact_ids").filtered("email_copy")
         email_cc = []
         if cc:
             email_cc = email_split(mail.email_cc or "")
             email_cc.extend(cc.mapped("email"))
         mail.email_cc = ";".join(email_cc)
     return super().send(auto_commit, raise_exception)
Example #19
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.
        """
        custom_values = custom_values if custom_values is not None else {}

        # Concatenate subject and body for request text
        request_text_tmpl = "<h1>%(subject)s</h1>\n<br/>\n<br/>%(body)s"
        request_text = request_text_tmpl % {
            'subject': msg.get('subject', _("No Subject")),
            'body': msg.get('body', '')
        }

        # Compute defaults
        defaults = {
            'request_text': request_text,
            'name': "###new###",  # Special name to avoid
            # placing subject to as name
        }

        # Update defaults with partner and created_by_id if possible
        author_id = msg.get('author_id')
        if author_id:
            author = self.env['res.partner'].browse(author_id)
            defaults['partner_id'] = author.commercial_partner_id.id
            if len(author.user_ids) == 1:
                defaults['created_by_id'] = author.user_ids[0].id
            else:
                defaults['author_id'] = author.id
        else:
            author = False

        defaults.update(custom_values)

        request = super(RequestRequest,
                        self).message_new(msg, custom_values=defaults)

        # Find partners from email and subscribe them
        email_list = tools.email_split((msg.get('to') or '') + ',' +
                                       (msg.get('cc') or ''))
        partner_ids = request._find_partner_from_emails(email_list,
                                                        force_create=False)
        partner_ids = [pid for pid in partner_ids if pid]

        if author:
            partner_ids += [author.id]

        request.message_subscribe(partner_ids)
        return request
Example #20
0
 def test_email_split(self):
     cases = [
         ("John <*****@*****.**>", ['*****@*****.**']),  # regular form
         ("d@x; 1@2", ['d@x', '1@2']),  # semi-colon + extra space
         ("'(ss)' <*****@*****.**>, 'foo' <foo@bar>",
          ['*****@*****.**', 'foo@bar']),  # comma + single-quoting
         ('"*****@*****.**"<*****@*****.**>', ['*****@*****.**'
                                                 ]),  # double-quoting
         ('"<jg>" <*****@*****.**>', ['*****@*****.**'
                                        ]),  # double-quoting with brackets
     ]
     for text, expected in cases:
         self.assertEqual(email_split(text), expected,
                          'email_split is broken')
Example #21
0
 def send_get_email_dict(self, partner=None):
     # TDE: temporary addition (mail was parameter) due to semi-new-API
     res = super(MailMail, self).send_get_email_dict(partner)
     base_url = self.env['ir.config_parameter'].get_param('web.base.url')
     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
Example #22
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_localpart = (tools.email_split(email_to) or [''])[0].split('@', 1)[0].lower()

        if bounce_alias and bounce_alias in email_to_localpart:
            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)
Example #23
0
    def _get_duplicated_leads_by_emails(self,
                                        partner_id,
                                        email,
                                        include_lost=False):
        _logger.info(f"\n\n\nContext Value: {self._context}\n\n\n")
        """ Search for opportunities that have the same partner and that arent done or cancelled """
        if not email:
            return self.env['crm.lead']
        partner_match_domain = []
        for email in set(email_split(email) + [email]):
            partner_match_domain.append(('email_from', '=ilike', email))
        if partner_id:
            partner_match_domain.append(('partner_id', '=', partner_id))
        partner_match_domain = ['|'] * (len(partner_match_domain) -
                                        1) + partner_match_domain
        if not partner_match_domain:
            return self.env['crm.lead']
        domain = partner_match_domain

        if 'lead' in self._context and self._context.get('lead'):
            domain += [('name', '=', self._context.get('lead_name'))]
        if 'team_id' in self._context and self._context.get('team_id'):
            domain += [('team_id', '=', self._context.get('team_id'))]
        if 'user_id' in self._context and self._context.get('user_id'):
            domain += [('user_id', '=', self._context.get('user_id'))]
        if 'contact_name' in self._context and self._context.get(
                'contact_name'):
            domain += [('contact_name', '=', self._context.get('contact_name'))
                       ]
        if 'subdivision_id' in self._context and self._context.get(
                'subdivision_id'):
            domain += [('subdivision_id', '=',
                        self._context.get('subdivision_id'))]
        if 'subdivision_phase_id' in self._context and self._context.get(
                'subdivision_phase_id'):
            domain += [('subdivision_phase_id', '=',
                        self._context.get('subdivision_phase_id'))]
        if 'subdivision_project' in self._context and self._context.get(
                'subdivision_project'):
            domain += [('house_model_id', '=',
                        self._context.get('house_model_id'))]
        if not include_lost:
            domain += ['&', ('active', '=', True), ('probability', '<', 100)]
        else:
            domain += [
                '|', '&', ('type', '=', 'lead'), ('active', '=', True),
                ('type', '=', 'opportunity')
            ]

        return self.search(domain)
Example #24
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_localpart = (tools.email_split(email_to) or [''])[0].split('@', 1)[0].lower()

        if bounce_alias and bounce_alias in email_to_localpart:
            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)
 def message_update(self, msg, update_vals=None):
     """Override message_update to subscribe partners"""
     email_list = tools.email_split(
         (msg.get("to") or "") + "," + (msg.get("cc") or "")
     )
     partner_ids = [
         p.id
         for p in self.env["mail.thread"]._mail_find_partner_from_emails(
             email_list, records=self, force_create=False
         )
         if p
     ]
     self.message_subscribe(partner_ids)
     return super().message_update(msg, update_vals=update_vals)
Example #26
0
 def _alias_check_contact(self, message, message_dict, alias):
     if alias.alias_contact == 'employees' and self.ids:
         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(message, message_dict, alias)
Example #27
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.
        """
        custom_values = custom_values if custom_values is not None else {}

        # Ensure we have message_id
        if not msg.get('message_id'):
            msg['message_id'] = self.env['mail.message']._get_message_id(msg)

        # Compute default request text
        request_text = MAIL_REQUEST_TEXT_TMPL % {
            'subject': msg.get('subject', _("No Subject")),
            'body': msg.get('body', ''),
        }

        # Update defaults with partner and created_by_id if possible
        defaults = {
            'name': "###new###",  # Spec name to avoid using subj as req name
            'request_text': request_text,
            'original_message_id': msg['message_id'],
        }
        author_id = msg.get('author_id')
        if author_id:
            author = self.env['res.partner'].browse(author_id)
            defaults['partner_id'] = author.commercial_partner_id.id
            defaults['author_id'] = author.id
            if len(author.user_ids) == 1:
                defaults['created_by_id'] = author.user_ids[0].id
        else:
            author = False
        defaults.update(custom_values)

        request = super(RequestRequest,
                        self).message_new(msg, custom_values=defaults)

        # Find partners from email and subscribe them
        email_list = tools.email_split((msg.get('to') or '') + ',' +
                                       (msg.get('cc') or ''))
        partner_ids = request._mail_find_partner_from_emails(
            email_list, force_create=False)
        partner_ids = [pid for pid in partner_ids if pid]

        if author:
            partner_ids += [author.id]

        request.message_subscribe(partner_ids)
        return request
Example #28
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)

        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', ''))
                for mail in mails:
                    partner_id = self.env['res.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
                #Add By AARSOL For For user to add in it.
                partner_ids += self.env.user.partner_id and self.env.user.partner_id.ids
            results[res_id]['partner_ids'] = partner_ids
        return results
Example #29
0
 def message_new(self, msg, custom_values=None):
     partner_email = tools.email_split(msg["from"])[0]
     # Automatically create a partner
     if not msg.get("author_id"):
         alias = tools.email_split(msg["to"])[0].split("@")[0]
         project = self.env["project.project"].search([("alias_name", "=",
                                                        alias)])
         partner = self.env["res.partner"].create({
             "parent_id":
             project.partner_id.id,
             "name":
             partner_email.split("@")[0],
             "email":
             partner_email,
         })
         msg["author_id"] = partner.id
     if custom_values is None:
         custom_values = {}
     custom_values.update({
         "description": msg["body"],
         "author_id": msg["author_id"]
     })
     return super(ProjectTask,
                  self).message_new(msg, custom_values=custom_values)
Example #30
0
 def _update_moderation_email(self, emails, status):
     """ This method adds emails into either white or black of the channel list of emails 
         according to status. If an email in emails is already moderated, the method updates the email status.
         :param emails: list of email addresses to put in white or black list of channel.
         :param status: value is 'allow' or 'ban'. Emails are put in white list if 'allow', in black list if 'ban'.
     """
     self.ensure_one()
     splitted_emails = [
         tools.email_split(email)[0] for email in emails
         if tools.email_split(email)
     ]
     moderated = self.env['mail.moderation'].sudo().search([
         ('email', 'in', splitted_emails), ('channel_id', 'in', self.ids)
     ])
     cmds = [(1, record.id, {'status': status}) for record in moderated]
     not_moderated = [
         email for email in splitted_emails
         if email not in moderated.mapped('email')
     ]
     cmds += [(0, 0, {
         'email': email,
         'status': status
     }) for email in not_moderated]
     return self.write({'moderation_ids': cmds})
Example #31
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'):
            records = self.env[self.model].browse(res_ids).sudo()
            default_recipients = self.env['mail.thread']._message_get_default_recipients_on_records(records)
            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
Example #32
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 _('restricted to employees')
         return True
     return super(AliasMixin, self)._alias_check_contact_on_record(
         record, message, message_dict, alias)
    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'):
            records = self.env[self.model].browse(res_ids).sudo()
            default_recipients = records._message_get_default_recipients()
            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 = 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
Example #34
0
 def message_update(self, msg, update_vals=None):
     """ Override message_update to subscribe partners """
     email_list = tools.email_split((msg.get("to") or "") + "," +
                                    (msg.get("cc") or ""))
     partner_ids = list(
         map(
             lambda x: x.id,
             self.env["mail.thread"]._mail_find_partner_from_emails(
                 email_list, records=self, force_create=False),
         ))
     self.message_subscribe(partner_ids)
     stage_id_new = self.env["helpdesk.ticket.stage"].search(
         [("state", "=", "new")], limit=1)
     self.stage_id = stage_id_new.id if stage_id_new else self.stage_id.id
     return super().message_update(msg, update_vals=update_vals)
Example #35
0
 def _get_opt_out_list(self):
     """Handle models with opt_out field for excluding them."""
     self.ensure_one()
     model = self.env[self.mailing_model_real].with_context(
         active_test=False)
     if self.mailing_model_real != "mailing.contact" and "opt_out" in model._fields:
         email_fname = "email_from"
         if "email" in model._fields:
             email_fname = "email"
         domain = safe_eval(self.mailing_domain)
         domain = [("opt_out", "=", True)] + domain
         recs = self.env[self.mailing_model_real].search(domain)
         normalized_email = (tools.email_split(c[email_fname])
                             for c in recs)
         return {e[0].lower() for e in normalized_email if e}
     return super()._get_opt_out_list()
Example #36
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]
Example #37
0
    def message_new(self, msg_dict, custom_values=None):
        """This function extracts required fields of hr.holidays from incoming mail then creating records"""
        try:
            if custom_values is None:
                custom_values = {}
            msg_subject = msg_dict.get('subject', '')
            subject = re.search('LEAVE REQUEST', msg_subject)
            if subject is not None:
                email_address = email_split(msg_dict.get('email_from', False))[0]
                employee = self.env['hr.employee'].sudo().search([
                    '|',
                    ('work_email', 'ilike', email_address),
                    ('user_id.email', 'ilike', email_address)
                ], limit=1)
                msg_body = msg_dict.get('body', '')
                cleaner = re.compile('<.*?>')
                clean_msg_body = re.sub(cleaner, '', msg_body)
                date_list = re.findall(r'\d{2}/\d{2}/\d{4}', clean_msg_body)
                print('date_list',date_list)
                if len(date_list) > 0:
                    date_from = date_list[0]
                    # if len(date_list) > 1:
                    if len(date_list) == 1:
                        start_date = datetime.strptime(date_list[0], '%d/%m/%Y')
                        date_to = start_date
                        print('date_to',date_to)
                        # no_of_days_temp = 1
                    else:
                        start_date = datetime.strptime(date_list[0], '%d/%m/%Y')
                        # start_date = start_date + timedelta(days=1)
                        date_to = datetime.strptime(date_list[1], '%d/%m/%Y')

                    no_of_days_temp = (datetime.strptime(str(date_to), "%Y-%m-%d %H:%M:%S") - datetime.strptime(
                                        str(start_date), '%Y-%m-%d %H:%M:%S')).days

                    no_of_days_temp += 1
                    custom_values.update({
                        'name': msg_subject.strip(),
                        'employee_id': employee.id,
                        'holiday_status_id': 1,
                        'request_date_from': start_date,
                        'request_date_to': date_to,
                        'number_of_days': no_of_days_temp
                    })
            return super(HrLeaveAlias, self).message_new(msg_dict, custom_values)
        except:
            pass
 def _get_opt_out_list(self):
     """Handle models with opt_out field for excluding them."""
     self.ensure_one()
     model = self.env[self.mailing_model_real].with_context(
         active_test=False)
     if (self.mailing_model_real != "mail.mass_mailing.contact"
             and 'opt_out' in model._fields):
         email_fname = 'email_from'
         if 'email' in model._fields:
             email_fname = 'email'
         domain = safe_eval(self.mailing_domain)
         domain = [('opt_out', '=', True)] + domain
         recs = self.env[self.mailing_model_real].search(domain)
         normalized_email = (tools.email_split(c[email_fname])
                             for c in recs)
         return set(e[0].lower() for e in normalized_email if e)
     return super()._get_opt_out_list()
    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

            urls_to_replace = [
               (base_url + '/unsubscribe_from_list', self.mailing_id._get_unsubscribe_url(email_to, self.res_id)),
               (base_url + '/view', self.mailing_id._get_view_url(email_to, self.res_id))
            ]

            for url_to_replace, new_url in urls_to_replace:
                if url_to_replace in res['body']:
                    res['body'] = res['body'].replace(url_to_replace, new_url if new_url else '#')
        return res
Example #40
0
    def message_new(self, msg_dict, custom_values=None):
        if custom_values is None:
            custom_values = {}

        # find or create customer
        email = email_split(msg_dict.get('email_from', False))[0]
        name = email_split_and_format(msg_dict.get('email_from', False))[0]
        customer = self.env['plant.customer'].find_or_create(email, name)

        # happy Xmas
        plants = self.env['plant.plant'].search([])
        plant = self.env['plant.plant'].browse([random.choice(plants.ids)])
        custom_values.update({
            'customer_id': customer.id,
            'line_ids': [(4, plant.id)],
        })
        return super(Order, self).message_new(msg_dict, custom_values=custom_values)
Example #41
0
    def send_mail_test(self):
        """ Send with Sendgrid if needed.
        """
        self.ensure_one()
        mailing = self.mass_mailing_id
        template = mailing.email_template_id.with_context(
            lang=mailing.lang.code or self.env.context['lang'])
        if template:
            # Send with SendGrid (and use E-mail Template)
            sendgrid_template = template.sendgrid_localized_template
            res_id = self.env.user.partner_id.id
            body = template.render_template(mailing.body_html,
                                            template.model, [res_id],
                                            post_process=True)[res_id]
            test_emails = tools.email_split(self.email_to)
            emails = self.env['mail.mail']
            for test_mail in test_emails:
                email_vals = {
                    'email_from':
                    mailing.email_from,
                    'reply_to':
                    mailing.reply_to,
                    'email_to':
                    test_mail,
                    'subject':
                    mailing.name,
                    'body_html':
                    body,
                    'sendgrid_template_id':
                    sendgrid_template.id,
                    'substitution_ids':
                    template.render_substitutions(res_id)[res_id],
                    'notification':
                    True,
                    'mailing_id':
                    mailing.id,
                    'attachment_ids':
                    [(4, attachment.id)
                     for attachment in mailing.attachment_ids],
                }
                emails += emails.create(email_vals)
            emails.send_sendgrid()
        else:
            super(TestMassMailing, self).send_mail_test()

        return True
Example #42
0
    def send_mail_test(self):
        self.ensure_one()
        ctx = dict(self.env.context)
        ctx.pop('default_state', None)
        self = self.with_context(ctx)

        mails_sudo = self.env['mail.mail'].sudo()
        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.render.mixin']._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.subject,
                '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'].sudo().create(mail_values)
            mails_sudo |= mail
        mails_sudo.send()
        return True
Example #43
0
    def _create_lead_partner_data(self, name):
        """ extract data from lead to create a partner
            :param name : furtur name of the partner
            :param is_company : True if the partner is a company
            :param parent_id : id of the parent partner (False if no parent)
            :returns res.partner record
        """
        email_split = tools.email_split(self.partner_email)

        return {
            'name': name,
            'mobile': self.partner_mobile,
            'user_id': self.user_id.id,
            'team_id': self.team_id.id,
            'email': email_split[0] if email_split else False,
            'customer': True
        }
Example #44
0
    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)
Example #45
0
    def message_route_verify(self,
                             message,
                             message_dict,
                             route,
                             update_author=True,
                             assert_model=True,
                             create_fallback=True,
                             allow_private=False,
                             drop_alias=False):
        res = super(MailThread,
                    self).message_route_verify(message,
                                               message_dict,
                                               route,
                                               update_author=update_author,
                                               assert_model=assert_model,
                                               create_fallback=create_fallback,
                                               allow_private=allow_private,
                                               drop_alias=drop_alias)

        if res:
            alias = route[4]
            email_from = decode_message_header(message, 'From')
            message_id = message.get('Message-Id')

            # Alias: check alias_contact settings for employees
            if alias and alias.alias_contact == 'employees':
                email_address = 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:
                    mail_template = self.env.ref(
                        'hr.mail_template_data_unknown_employee_email_address')
                    self._routing_warn(
                        _('alias %s does not accept unknown employees') %
                        alias.alias_name, _('skipping'), message_id, route,
                        False)
                    self._routing_create_bounce_email(email_from,
                                                      mail_template.body_html,
                                                      message)
                    return False
        return res
Example #46
0
    def send_mail_test(self):
        self.ensure_one()
        mails = self.env['mail.mail']
        mailing = self.mass_mailing_id

        outgoing_mail_server = int(
            self.env['ir.config_parameter'].sudo().get_param(
                'mass_mailing_outgoing_mailserver.outgoing_mail_server'))
        test_emails = tools.email_split(self.email_to)
        for test_mail in test_emails:
            # Convert links in absolute URLs before the application of the
            # shortener
            mailing.write({
                'body_html':
                self.env['mail.template']._replace_local_links(
                    mailing.body_html)
            })
            mail_values = {
                'email_from':
                mailing.email_from,
                'reply_to':
                mailing.reply_to,
                'email_to':
                test_mail,
                'subject':
                mailing.name,
                'body_html':
                mailing.body_html,
                'notification':
                True,
                'mailing_id':
                mailing.id,
                'attachment_ids':
                [(4, attachment.id) for attachment in mailing.attachment_ids],
            }
            if mailing.outgoing_mail_server:
                mail_values.update(
                    {'mail_server_id': mailing.outgoing_mail_server.id})
            elif outgoing_mail_server:
                mail_values.update({'mail_server_id': outgoing_mail_server})
            mail = self.env['mail.mail'].create(mail_values)
            mails |= mail
        mails.send()
        return True
Example #47
0
File: enquiry.py Project: tramm/neo
 def _create_lead_partner_data(self, name, is_company, parent_id=False):
     """ extract data from lead to create a partner
         :param name : furtur name of the partner
         :param is_company : True if the partner is a company
         :param parent_id : id of the parent partner (False if no parent)
         :returns res.partner record
     """
     email_split = tools.email_split(self.partner_email)
     return {
         'name': name,
         'user_id': self.env.context.get('default_user_id')
         or self.user_id.id,
         'partner_name': self.partner_name,
         'comment': self.description,
         'team_id': self.team_id.id,
         'mobile': self.partner_mobile,
         'email': email_split[0] if email_split else False,
         'type': 'contact'
     }
Example #48
0
    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)
 def _create_user(self):
     """
     Override portal user creation to prevent sending e-mail to new user.
     """
     res_users = self.env['res.users'].with_context(
         noshortcut=True, no_reset_password=True)
     email = email_split(self.email)
     if email:
         email = email[0]
     else:
         email = self.partner_id.lastname.lower() + '@cs.local'
     values = {
         'email': email,
         'login': email,
         'partner_id': self.partner_id.id,
         'groups_id': [(6, 0, [])],
         'notify_email': 'none',
     }
     return res_users.create(values)
Example #50
0
    def message_route_verify(self, message, message_dict, route, update_author=True, assert_model=True, create_fallback=True, allow_private=False):
        res = super(MailThread, self).message_route_verify(message, message_dict, route, update_author, assert_model, create_fallback, allow_private)

        if res:
            alias = route[4]
            email_from = decode_header(message, 'From')
            message_id = message.get('Message-Id')

            # Identically equal to the definition in mail module because sub methods are local
            # variables and cannot be called with super
            def _create_bounce_email(body_html):
                bounce_to = decode_header(message, 'Return-Path') or email_from
                bounce_mail_values = {
                    'body_html': body_html,
                    'subject': 'Re: %s' % message.get('subject'),
                    'email_to': bounce_to,
                    'auto_delete': True,
                }
                bounce_from = self.env['ir.mail_server']._get_default_bounce_address()
                if bounce_from:
                    bounce_mail_values['email_from'] = 'MAILER-DAEMON <%s>' % bounce_from
                self.env['mail.mail'].create(bounce_mail_values).send()

            def _warn(message):
                _logger.info('Routing mail with Message-Id %s: route %s: %s',
                             message_id, route, message)

            # Alias: check alias_contact settings for employees

            if alias and alias.alias_contact == 'employees':
                email_address = 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:
                    mail_template = self.env.ref('hr.mail_template_data_unknown_employee_email_address')
                    _warn('alias %s does not accept unknown employees, skipping' % alias.alias_name)
                    _create_bounce_email(mail_template.body_html)
                    return False
        return res
Example #51
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)
     for test_mail in test_emails:
         # Convert links in absolute URLs before the application of the shortener
         mailing.write({'body_html': self.env['mail.template']._replace_local_links(mailing.body_html)})
         mail_values = {
             'email_from': mailing.email_from,
             'reply_to': mailing.reply_to,
             'email_to': test_mail,
             'subject': mailing.name,
             'body_html': mailing.body_html,
             'notification': True,
             'mailing_id': mailing.id,
             'attachment_ids': [(4, attachment.id) for attachment in mailing.attachment_ids],
             'auto_delete': True,
         }
         mail = self.env['mail.mail'].create(mail_values)
         mails |= mail
     mails.send()
     return True
Example #52
0
    def message_new(self, msg_dict, custom_values=None):
        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)

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

        if employee.user_id:
            currencies = employee.user_id.company_id.currency_id | employee.user_id.company_ids.mapped('currency_id')
        else:
            currencies = employee.company_id.currency_id

        product, price, currency_id, expense_description = self._parse_expense_subject(expense_description, currencies)
        vals = {
            'employee_id': employee.id,
            'name': expense_description,
            'unit_amount': price,
            'product_id': product.id if product else None,
            'product_uom_id': product.uom_id.id,
            'tax_ids': [(4, tax.id, False) for tax in product.supplier_taxes_id],
            'quantity': 1,
            'company_id': employee.company_id.id,
            'currency_id': currency_id.id
        }

        account = product.product_tmpl_id._get_product_accounts()['expense']
        if account:
            vals['account_id'] = account.id

        expense = super(HrExpense, self).message_new(msg_dict, dict(custom_values or {}, **vals))
        self._send_expense_success_mail(msg_dict, expense)
        return expense
Example #53
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 filter(lambda x: x.split("@")[0] not in aliases, email_list)
Example #54
0
    def generate_data(self, event, isCreating=False):
        if event.allday:
            start_date = fields.Date.to_string(event.start_date)
            final_date = fields.Date.to_string(event.stop_date + timedelta(days=1))
            type = 'date'
            vstype = 'dateTime'
        else:
            start_date = fields.Datetime.context_timestamp(self, event.start).isoformat('T')
            final_date = fields.Datetime.context_timestamp(self, event.stop).isoformat('T')
            type = 'dateTime'
            vstype = 'date'
        attendee_list = []
        for attendee in event.attendee_ids:
            email = tools.email_split(attendee.email)
            email = email[0] if email else '*****@*****.**'
            attendee_list.append({
                'email': email,
                'displayName': attendee.partner_id.name,
                'responseStatus': attendee.state or 'needsAction',
            })

        reminders = []
        for alarm in event.alarm_ids:
            reminders.append({
                "method": "email" if alarm.alarm_type == "email" else "popup",
                "minutes": alarm.duration_minutes
            })
        data = {
            "summary": event.name or '',
            "description": event.description or '',
            "start": {
                type: start_date,
                vstype: None,
                'timeZone': self.env.context.get('tz') or 'UTC',
            },
            "end": {
                type: final_date,
                vstype: None,
                'timeZone': self.env.context.get('tz') or 'UTC',
            },
            "attendees": attendee_list,
            "reminders": {
                "overrides": reminders,
                "useDefault": "false"
            },
            "location": event.location or '',
            "visibility": event['privacy'] or 'public',
        }
        if event.recurrency and event.rrule:
            data["recurrence"] = ["RRULE:" + event.rrule]

        if not event.active:
            data["state"] = "cancelled"

        if not self.get_need_synchro_attendee():
            data.pop("attendees")
        if isCreating:
            other_google_ids = [other_att.google_internal_event_id for other_att in event.attendee_ids
                                if other_att.google_internal_event_id and not other_att.google_internal_event_id.startswith('_')]
            if other_google_ids:
                data["id"] = other_google_ids[0]
        return data
Example #55
0
    def _send(self, auto_commit=False, raise_exception=False, smtp_session=None):
        IrMailServer = self.env['ir.mail_server']
        for mail_id in self.ids:
            try:
                mail = self.browse(mail_id)
                if mail.state != 'outgoing':
                    if mail.state != 'exception' and mail.auto_delete:
                        mail.sudo().unlink()
                    continue

                # load attachment binary data with a separate read(), as prefetching all
                # `datas` (binary field) could bloat the browse cache, triggerring
                # soft/hard mem limits with temporary data.
                attachments = [(a['datas_fname'], base64.b64decode(a['datas']), a['mimetype'])
                               for a in mail.attachment_ids.sudo().read(['datas_fname', 'datas', 'mimetype'])]

                # specific behavior to customize the send email for notified partners
                email_list = []
                if mail.email_to:
                    email_list.append(mail._send_prepare_values())
                for partner in mail.recipient_ids:
                    email_list.append(mail._send_prepare_values(partner=partner))

                # headers
                headers = {}
                ICP = self.env['ir.config_parameter'].sudo()
                bounce_alias = ICP.get_param("mail.bounce.alias")
                catchall_domain = ICP.get_param("mail.catchall.domain")
                if bounce_alias and catchall_domain:
                    if mail.model and mail.res_id:
                        headers['Return-Path'] = '%s+%d-%s-%d@%s' % (bounce_alias, mail.id, mail.model, mail.res_id, catchall_domain)
                    else:
                        headers['Return-Path'] = '%s+%d@%s' % (bounce_alias, mail.id, catchall_domain)
                if mail.headers:
                    try:
                        headers.update(safe_eval(mail.headers))
                    except Exception:
                        pass

                # Writing on the mail object may fail (e.g. lock on user) which
                # would trigger a rollback *after* actually sending the email.
                # To avoid sending twice the same email, provoke the failure earlier
                mail.write({
                    'state': 'exception',
                    'failure_reason': _('Error without exception. Probably due do sending an email without computed recipients.'),
                })
                mail_sent = False

                # build an RFC2822 email.message.Message object and send it without queuing
                res = None
                for email in email_list:
                    msg = IrMailServer.build_email(
                        email_from=mail.email_from,
                        email_to=email.get('email_to'),
                        subject=mail.subject,
                        body=email.get('body'),
                        body_alternative=email.get('body_alternative'),
                        email_cc=tools.email_split(mail.email_cc),
                        reply_to=mail.reply_to,
                        attachments=attachments,
                        message_id=mail.message_id,
                        references=mail.references,
                        object_id=mail.res_id and ('%s-%s' % (mail.res_id, mail.model)),
                        subtype='html',
                        subtype_alternative='plain',
                        headers=headers)
                    try:
                        res = IrMailServer.send_email(
                            msg, mail_server_id=mail.mail_server_id.id, smtp_session=smtp_session)
                    except AssertionError as error:
                        if str(error) == IrMailServer.NO_VALID_RECIPIENT:
                            # No valid recipient found for this particular
                            # mail item -> ignore error to avoid blocking
                            # delivery to next recipients, if any. If this is
                            # the only recipient, the mail will show as failed.
                            _logger.info("Ignoring invalid recipients for mail.mail %s: %s",
                                         mail.message_id, email.get('email_to'))
                        else:
                            raise
                if res:
                    mail.write({'state': 'sent', 'message_id': res, 'failure_reason': False})
                    mail_sent = True

                # /!\ can't use mail.state here, as mail.refresh() will cause an error
                # see revid:[email protected] in 6.1
                if mail_sent:
                    _logger.info('Mail with ID %r and Message-Id %r successfully sent', mail.id, mail.message_id)
                mail._postprocess_sent_message(mail_sent=mail_sent)
            except MemoryError:
                # prevent catching transient MemoryErrors, bubble up to notify user or abort cron job
                # instead of marking the mail as failed
                _logger.exception(
                    'MemoryError while processing mail with ID %r and Msg-Id %r. Consider raising the --limit-memory-hard startup option',
                    mail.id, mail.message_id)
                raise
            except psycopg2.Error:
                # If an error with the database occurs, chances are that the cursor is unusable.
                # This will lead to an `psycopg2.InternalError` being raised when trying to write
                # `state`, shadowing the original exception and forbid a retry on concurrent
                # update. Let's bubble it.
                raise
            except Exception as e:
                failure_reason = tools.ustr(e)
                _logger.exception('failed sending mail (id: %s) due to %s', mail.id, failure_reason)
                mail.write({'state': 'exception', 'failure_reason': failure_reason})
                mail._postprocess_sent_message(mail_sent=False)
                if raise_exception:
                    if isinstance(e, AssertionError):
                        # get the args of the original error, wrap into a value and throw a MailDeliveryException
                        # that is an except_orm, with name and value as arguments
                        value = '. '.join(e.args)
                        raise MailDeliveryException(_("Mail Delivery Failed"), value)
                    raise

            if auto_commit is True:
                self._cr.commit()
        return True
Example #56
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]
Example #57
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
     return filter(lambda x: x.split('@')[0] not in self.mapped('project_id.alias_name'), email_list)
Example #58
0
    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}

            blacklist = self._context.get('mass_mailing_blacklist')
            seen_list = self._context.get('mass_mailing_seen_list')
            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:
                    recips = tools.email_split(partners_email.get(res_id))
                mail_to = recips[0].lower() if recips else False
                if (blacklist and mail_to in blacklist) or (seen_list and mail_to in seen_list):
                    # 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
                }
                # propagate exception state to stat when still-born
                if mail_values.get('state') == 'cancel':
                    stat_vals['exception'] = 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
Example #59
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 ''
Example #60
0
    def _send(self, auto_commit=False, raise_exception=False, smtp_session=None):
        IrMailServer = self.env['ir.mail_server']
        IrAttachment = self.env['ir.attachment']
        for mail_id in self.ids:
            success_pids = []
            failure_type = None
            processing_pid = None
            mail = None
            try:
                mail = self.browse(mail_id)
                if mail.state != 'outgoing':
                    if mail.state != 'exception' and mail.auto_delete:
                        mail.sudo().unlink()
                    continue

                # remove attachments if user send the link with the access_token
                body = mail.body_html or ''
                attachments = mail.attachment_ids
                for link in re.findall(r'/web/(?:content|image)/([0-9]+)', body):
                    attachments = attachments - IrAttachment.browse(int(link))

                # load attachment binary data with a separate read(), as prefetching all
                # `datas` (binary field) could bloat the browse cache, triggerring
                # soft/hard mem limits with temporary data.
                attachments = [(a['datas_fname'], base64.b64decode(a['datas']), a['mimetype'])
                               for a in attachments.sudo().read(['datas_fname', 'datas', 'mimetype'])]

                # specific behavior to customize the send email for notified partners
                email_list = []
                if mail.email_to:
                    email_list.append(mail._send_prepare_values())
                for partner in mail.recipient_ids:
                    values = mail._send_prepare_values(partner=partner)
                    values['partner_id'] = partner
                    email_list.append(values)

                # headers
                headers = {}
                ICP = self.env['ir.config_parameter'].sudo()
                bounce_alias = ICP.get_param("mail.bounce.alias")
                catchall_domain = ICP.get_param("mail.catchall.domain")
                if bounce_alias and catchall_domain:
                    if mail.model and mail.res_id:
                        headers['Return-Path'] = '%s+%d-%s-%d@%s' % (bounce_alias, mail.id, mail.model, mail.res_id, catchall_domain)
                    else:
                        headers['Return-Path'] = '%s+%d@%s' % (bounce_alias, mail.id, catchall_domain)
                if mail.headers:
                    try:
                        headers.update(safe_eval(mail.headers))
                    except Exception:
                        pass

                # Writing on the mail object may fail (e.g. lock on user) which
                # would trigger a rollback *after* actually sending the email.
                # To avoid sending twice the same email, provoke the failure earlier
                mail.write({
                    'state': 'exception',
                    'failure_reason': _('Error without exception. Probably due do sending an email without computed recipients.'),
                })
                # Update notification in a transient exception state to avoid concurrent
                # update in case an email bounces while sending all emails related to current
                # mail record.
                notifs = self.env['mail.notification'].search([
                    ('is_email', '=', True),
                    ('mail_id', 'in', mail.ids),
                    ('email_status', 'not in', ('sent', 'canceled'))
                ])
                if notifs:
                    notif_msg = _('Error without exception. Probably due do concurrent access update of notification records. Please see with an administrator.')
                    notifs.sudo().write({
                        'email_status': 'exception',
                        'failure_type': 'UNKNOWN',
                        'failure_reason': notif_msg,
                    })

                # build an RFC2822 email.message.Message object and send it without queuing
                res = None
                for email in email_list:
                    msg = IrMailServer.build_email(
                        email_from=mail.email_from,
                        email_to=email.get('email_to'),
                        subject=mail.subject,
                        body=email.get('body'),
                        body_alternative=email.get('body_alternative'),
                        email_cc=tools.email_split(mail.email_cc),
                        reply_to=mail.reply_to,
                        attachments=attachments,
                        message_id=mail.message_id,
                        references=mail.references,
                        object_id=mail.res_id and ('%s-%s' % (mail.res_id, mail.model)),
                        subtype='html',
                        subtype_alternative='plain',
                        headers=headers)
                    processing_pid = email.pop("partner_id", None)
                    try:
                        res = IrMailServer.send_email(
                            msg, mail_server_id=mail.mail_server_id.id, smtp_session=smtp_session)
                        if processing_pid:
                            success_pids.append(processing_pid)
                        processing_pid = None
                    except AssertionError as error:
                        if str(error) == IrMailServer.NO_VALID_RECIPIENT:
                            failure_type = "RECIPIENT"
                            # No valid recipient found for this particular
                            # mail item -> ignore error to avoid blocking
                            # delivery to next recipients, if any. If this is
                            # the only recipient, the mail will show as failed.
                            _logger.info("Ignoring invalid recipients for mail.mail %s: %s",
                                         mail.message_id, email.get('email_to'))
                        else:
                            raise
                if res:  # mail has been sent at least once, no major exception occured
                    mail.write({'state': 'sent', 'message_id': res, 'failure_reason': False})
                    _logger.info('Mail with ID %r and Message-Id %r successfully sent', mail.id, mail.message_id)
                    # /!\ can't use mail.state here, as mail.refresh() will cause an error
                    # see revid:[email protected] in 6.1
                mail._postprocess_sent_message(success_pids=success_pids, failure_type=failure_type)
            except MemoryError:
                # prevent catching transient MemoryErrors, bubble up to notify user or abort cron job
                # instead of marking the mail as failed
                _logger.exception(
                    'MemoryError while processing mail with ID %r and Msg-Id %r. Consider raising the --limit-memory-hard startup option',
                    mail.id, mail.message_id)
                # mail status will stay on ongoing since transaction will be rollback
                raise
            except (psycopg2.Error, smtplib.SMTPServerDisconnected):
                # If an error with the database or SMTP session occurs, chances are that the cursor
                # or SMTP session are unusable, causing further errors when trying to save the state.
                _logger.exception(
                    'Exception while processing mail with ID %r and Msg-Id %r.',
                    mail.id, mail.message_id)
                raise
            except Exception as e:
                failure_reason = tools.ustr(e)
                _logger.exception('failed sending mail (id: %s) due to %s', mail.id, failure_reason)
                mail.write({'state': 'exception', 'failure_reason': failure_reason})
                mail._postprocess_sent_message(success_pids=success_pids, failure_reason=failure_reason, failure_type='UNKNOWN')
                if raise_exception:
                    if isinstance(e, (AssertionError, UnicodeEncodeError)):
                        if isinstance(e, UnicodeEncodeError):
                            value = "Invalid text: %s" % e.object
                        else:
                            # get the args of the original error, wrap into a value and throw a MailDeliveryException
                            # that is an except_orm, with name and value as arguments
                            value = '. '.join(e.args)
                        raise MailDeliveryException(_("Mail Delivery Failed"), value)
                    raise

            if auto_commit is True:
                self._cr.commit()
        return True