def test_notify_reply_to_computation_mc(self): """ Test reply-to computation in multi company mode. Add notably tests depending on user company_id / company_ids. """ # Test1: no company_id field test_record = self.env['mail.test.gateway'].browse( self.test_record.ids) res = test_record._notify_get_reply_to() self.assertEqual( res[test_record.id], formataddr( ("%s %s" % (self.user_employee_c2.company_id.name, test_record.name), "%s@%s" % (self.alias_catchall, self.alias_domain)))) # Test2: company_id field, MC environment self.user_employee_c2.write( {'company_ids': [(4, self.user_employee.company_id.id)]}) test_records = self.env['mail.test.multi.company'].create([ { 'name': 'Test', 'company_id': self.user_employee.company_id.id }, { 'name': 'Test', 'company_id': self.user_employee_c2.company_id.id }, ]) res = test_records._notify_get_reply_to() for test_record in test_records: self.assertEqual( res[test_record.id], formataddr( ("%s %s" % (self.user_employee_c2.company_id.name, test_record.name), "%s@%s" % (self.alias_catchall, self.alias_domain))))
def test_mail_message_values_document_manual_alias(self): test_record = self.env['mail.test.simple'].create({ 'name': 'Test', 'email_from': '*****@*****.**' }) alias = self.env['mail.alias'].create({ 'alias_name': 'MegaLias', 'alias_user_id': False, 'alias_model_id': self.env['ir.model']._get('mail.test.simple').id, 'alias_parent_model_id': self.env['ir.model']._get('mail.test.simple').id, 'alias_parent_thread_id': test_record.id, }) msg = self.Message.create({ 'model': 'mail.test.simple', 'res_id': test_record.id }) self.assertIn('-openerp-%d-mail.test.simple' % test_record.id, msg.message_id.split('@')[0]) reply_to_name = '%s %s' % (self.env.user.company_id.name, test_record.name) reply_to_email = '%s@%s' % (alias.alias_name, self.alias_domain) self.assertEqual(msg.reply_to, formataddr((reply_to_name, reply_to_email))) self.assertEqual( msg.email_from, formataddr((self.user_employee.name, self.user_employee.email)))
def assertSentEmail(self, author, recipients, **values): """ Tool method to ease the check of send emails. :param author: email author, either a string (email), either a partner record; :param recipients: list of recipients, each being either a string (email), either a partner record; :param values: dictionary of additional values to check email content; """ base_expected = {} for fname in ['reply_to', 'subject', 'attachments', 'body', 'references', 'body_content', 'body_alternative_content', 'references_content']: if fname in values: base_expected[fname] = values[fname] expected = dict(base_expected) if isinstance(author, self.env['res.partner'].__class__): expected['email_from'] = formataddr((author.name, author.email)) else: expected['email_from'] = author email_to_list = [] for email_to in recipients: if isinstance(email_to, self.env['res.partner'].__class__): email_to_list.append(formataddr((email_to.name, email_to.email))) else: email_to_list.append(email_to) expected['email_to'] = email_to_list sent_mail = next( (mail for mail in self._mails if set(mail['email_to']) == set(expected['email_to']) and mail['email_from'] == expected['email_from'] ), False) debug_info = '-'.join('From: %s-To: %s' % (mail['email_from'], mail['email_to']) for mail in self._mails) if not bool(sent_mail) else '' self.assertTrue(bool(sent_mail), 'Expected mail from %s to %s not found in %s' % (expected['email_from'], expected['email_to'], debug_info)) for val in ['reply_to', 'subject', 'references', 'attachments']: if val in expected: self.assertEqual(expected[val], sent_mail[val], 'Value for %s: expected %s, received %s' % (val, expected[val], sent_mail[val])) if 'attachments_info' in values: attachments = sent_mail['attachments'] for attachment_info in values['attachments_info']: attachment = next(attach for attach in attachments if attach[0] == attachment_info['name']) if attachment_info.get('raw'): self.assertEqual(attachment[1], attachment_info['raw']) if attachment_info.get('type'): self.assertEqual(attachment[2], attachment_info['type']) self.assertEqual(len(values['attachments_info']), len(attachments)) for val in ['body']: if val in expected: self.assertHtmlEqual(expected[val], sent_mail[val], 'Value for %s: expected %s, received %s' % (val, expected[val], sent_mail[val])) for val in ['body_content', 'body_alternative', 'references_content']: if val in expected: self.assertIn(expected[val], sent_mail[val[:-8]], 'Value for %s: %s does not contain %s' % (val, sent_mail[val[:-8]], expected[val]))
def test_channel_blacklisted_recipients(self): """ Posting a message on a channel should send one email to all recipients, except the blacklisted ones """ def _join_channel(channel, partners): for partner in partners: channel.write({ 'channel_last_seen_partner_ids': [(0, 0, { 'partner_id': partner.id })] }) channel.invalidate_cache() test_channel = self.env['mail.channel'].create({ 'name': 'Test', 'description': 'Description', 'alias_name': 'test', 'public': 'public', 'email_send': True, }) test_partner = self.env['res.partner'].create({ 'name': 'Test Partner', 'email': '*****@*****.**', }) blacklisted_partner = self.env['res.partner'].create({ 'name': 'Blacklisted Partner', 'email': '*****@*****.**', }) # Set Blacklist self.env['mail.blacklist'].create({ 'email': '*****@*****.**', }) _join_channel(test_channel, test_partner) _join_channel(test_channel, blacklisted_partner) with self.mock_mail_gateway(): test_channel.message_post(body="Test", message_type='comment', subtype_xmlid='mail.mt_comment') self.assertEqual(len(self._mails), 1, 'Number of mail incorrect. Should be equal to 1.') for email in self._mails: self.assertEqual( set(email['email_to']), set([formataddr((test_partner.name, test_partner.email))]), 'email_to incorrect. Should be equal to "%s"' % (formataddr( (test_partner.name, test_partner.email))))
def test_email_formataddr(self): email = '*****@*****.**' email_idna = 'joe@examplé.com' cases = [ # (name, address), charsets expected (('', email), ['ascii', 'utf-8'], '*****@*****.**'), (('joe', email), ['ascii', 'utf-8'], '"joe" <*****@*****.**>'), (('joe doe', email), ['ascii', 'utf-8'], '"joe doe" <*****@*****.**>'), (('joe"doe', email), ['ascii', 'utf-8'], '"joe\\"doe" <*****@*****.**>'), (('joé', email), ['ascii'], '=?utf-8?b?am/DqQ==?= <*****@*****.**>'), (('joé', email), ['utf-8'], '"joé" <*****@*****.**>'), (('', email_idna), ['ascii'], '*****@*****.**'), (('', email_idna), ['utf-8'], 'joe@examplé.com'), (('joé', email_idna), ['ascii'], '=?utf-8?b?am/DqQ==?= <*****@*****.**>'), (('joé', email_idna), ['utf-8'], '"joé" <joe@examplé.com>'), (('', 'joé@example.com'), ['ascii', 'utf-8'], 'joé@example.com'), ] for pair, charsets, expected in cases: for charset in charsets: with self.subTest(pair=pair, charset=charset): self.assertEqual(formataddr(pair, charset), expected)
def _compute_email_formatted(self): for partner in self: if partner.email: partner.email_formatted = tools.formataddr( (partner.name or u"False", partner.email or u"False")) else: partner.email_formatted = ''
def test_complex_mail_mail_send(self): message = self.env['mail.message'].sudo().create({ 'subject': 'Test', 'body': '<p>Test</p>', 'author_id': self.env.user.partner_id.id, 'email_from': self.env.user.partner_id.email, 'model': 'mail.test.container', 'res_id': self.container.id, }) mail = self.env['mail.mail'].sudo().create({ 'body_html': '<p>Test</p>', 'mail_message_id': message.id, 'recipient_ids': [(4, pid) for pid in self.partners.ids], }) mail_ids = mail.ids with self.assertQueryCount(__system__=7, emp=7): self.env['mail.mail'].sudo().browse(mail_ids).send() self.assertEqual(mail.body_html, '<p>Test</p>') self.assertEqual( mail.reply_to, formataddr(('%s %s' % (self.env.company.name, self.container.name), '*****@*****.**')))
def _create_leads_batch(self, lead_type='lead', count=10, partner_ids=None, user_ids=None): """ Helper tool method creating a batch of leads, useful when dealing with batch processes. Please update me. :param string type: 'lead', 'opportunity', 'mixed' (lead then opp), None (depends on configuration); """ types = ['lead', 'opportunity'] leads_data = [{ 'name': 'TestLead_%02d' % (x), 'type': lead_type if lead_type else types[x % 2], 'priority': '%s' % (x % 3), } for x in range(count)] # customer information if partner_ids: for idx, lead_data in enumerate(leads_data): lead_data['partner_id'] = partner_ids[idx % len(partner_ids)] else: for idx, lead_data in enumerate(leads_data): lead_data['email_from'] = tools.formataddr(( 'TestCustomer_%02d' % (idx), '*****@*****.**' % (idx) )) # salesteam information if user_ids: for idx, lead_data in enumerate(leads_data): lead_data['user_id'] = user_ids[idx % len(user_ids)] return self.env['crm.lead'].create(leads_data)
def test_mail_group_notification_recipients_separated(self): # Remove alias, should trigger classic behavior of mail group self.group_private.write({'alias_name': False}) self.group_private.message_subscribe_users( [self.user_employee.id, self.user_portal.id]) self.group_private.message_post(body="Test", message_type='comment', subtype='mt_comment') sent_emails = self._mails self.assertEqual(len(sent_emails), 2) for email in sent_emails: self.assertIn(email['email_to'][0], [ formataddr( (self.user_employee.name, self.user_employee.email)), formataddr((self.user_portal.name, self.user_portal.email)) ])
def _init_mail_gateway(cls): cls.alias_domain = 'test.com' cls.alias_catchall = 'catchall.test' cls.alias_bounce = 'bounce.test' cls.env['ir.config_parameter'].set_param('mail.bounce.alias', cls.alias_bounce) cls.env['ir.config_parameter'].set_param('mail.catchall.domain', cls.alias_domain) cls.env['ir.config_parameter'].set_param('mail.catchall.alias', cls.alias_catchall) cls.mailer_daemon_email = formataddr(('MAILER-DAEMON', '%s@%s' % (cls.alias_bounce, cls.alias_domain)))
def encode_addr(addr): name, email = addr try: return formataddr((name, email), 'ascii') except UnicodeEncodeError: _logger.warning( _('Failed to encode the address %s\n' 'from mail header:\n%s') % (addr, header_text)) return ""
def _mail_cc_sanitized_raw_dict(self, cc_string): '''return a dict of sanitize_email:raw_email from a string of cc''' if not cc_string: return {} return { tools.email_normalize(email): tools.formataddr( (name, tools.email_normalize(email))) for (name, email) in tools.email_split_tuples(cc_string) }
def test_notify_reply_to_computation(self): test_record = self.env['mail.test.gateway'].browse( self.test_record.ids) res = test_record._notify_get_reply_to() self.assertEqual( res[test_record.id], formataddr(("%s %s" % (self.user_employee.company_id.name, test_record.name), "%s@%s" % (self.alias_catchall, self.alias_domain))))
def extract_rfc2822_addresses(text): """Returns a list of valid RFC2822 addresses that can be found in ``source``, ignoring malformed ones and non-ASCII ones. """ if not text: return [] candidates = address_pattern.findall(ustr(text)) return [formataddr(('', c), charset='ascii') for c in candidates]
def test_post_notify(self): self.user_employee.write({'notification_type': 'inbox'}) with self.mock_mail_gateway(): new_notification = self.test_record.message_notify( subject='This should be a subject', body='<p>You have received a notification</p>', partner_ids=[ self.partner_1.id, self.partner_admin.id, self.user_employee.partner_id.id ], ) self.assertEqual(new_notification.subtype_id, self.env.ref('mail.mt_note')) self.assertEqual(new_notification.message_type, 'user_notification') self.assertEqual(new_notification.body, '<p>You have received a notification</p>') self.assertEqual(new_notification.author_id, self.env.user.partner_id) self.assertEqual(new_notification.email_from, formataddr((self.env.user.name, self.env.user.email))) self.assertEqual( new_notification.notified_partner_ids, self.partner_1 | self.user_employee.partner_id | self.partner_admin) self.assertNotIn(new_notification, self.test_record.message_ids) admin_mails = [ x for x in self._mails if self.partner_admin.name in x.get('email_to')[0] ] self.assertEqual(len(admin_mails), 1, 'There should be exactly one email sent to admin') admin_mail = admin_mails[0].get('body') admin_access_link = admin_mail[admin_mail. index('model='):admin_mail.index('/>') - 1] if 'model=' in admin_mail else None self.assertIsNotNone( admin_access_link, 'The email sent to admin should contain an access link') self.assertIn('model=%s' % self.test_record._name, admin_access_link, 'The access link should contain a valid model argument') self.assertIn( 'res_id=%d' % self.test_record.id, admin_access_link, 'The access link should contain a valid res_id argument') partner_mails = [ x for x in self._mails if self.partner_1.name in x.get('email_to')[0] ] self.assertEqual(len(partner_mails), 1, 'There should be exactly one email sent to partner') partner_mail = partner_mails[0].get('body') self.assertNotIn( '/mail/view?model=', partner_mail, 'The email sent to admin should not contain an access link')
def test_post_log(self): new_note = self.test_record.with_user(self.user_employee)._message_log( body='<p>Labrador</p>', ) self.assertEqual(new_note.subtype_id, self.env.ref('mail.mt_note')) self.assertEqual(new_note.body, '<p>Labrador</p>') self.assertEqual(new_note.author_id, self.user_employee.partner_id) self.assertEqual( new_note.email_from, formataddr((self.user_employee.name, self.user_employee.email))) self.assertEqual(new_note.notified_partner_ids, self.env['res.partner'])
def test_mail_group_notification_recipients_grouped(self): # Data: set alias_domain to see emails with alias self.env['ir.config_parameter'].set_param('mail.catchall.domain', 'schlouby.fr') self.group_private.write({'alias_name': 'Test'}) self.group_private.message_subscribe_users( [self.user_employee.id, self.user_portal.id]) self.group_private.message_post(body="Test", message_type='comment', subtype='mt_comment') sent_emails = self._mails self.assertEqual(len(sent_emails), 1) for email in sent_emails: self.assertEqual( set(email['email_to']), set([ formataddr( (self.user_employee.name, self.user_employee.email)), formataddr((self.user_portal.name, self.user_portal.email)) ]))
def _compute_catchall(self): ConfigParameter = self.env['ir.config_parameter'].sudo() alias = ConfigParameter.get_param('mail.catchall.alias') domain = ConfigParameter.get_param('mail.catchall.domain') if alias and domain: for company in self: company.catchall_email = '%s@%s' % (alias, domain) company.catchall_formatted = tools.formataddr( (company.name, company.catchall_email)) else: for company in self: company.catchall_email = '' company.catchall_formatted = ''
def send_get_mail_to(self, partner=None): """Forge the email_to with the following heuristic: - if 'partner', recipient specific (Partner Name <email>) - else fallback on mail.email_to splitting """ self.ensure_one() if partner: email_to = [ tools.formataddr((partner.name or 'False', partner.email or 'False')) ] else: email_to = tools.email_split_and_format(self.email_to) return email_to
def test_mail_message_values_document_no_alias(self): test_record = self.env['mail.test.simple'].create({ 'name': 'Test', 'email_from': '*****@*****.**' }) msg = self.Message.create({ 'model': 'mail.test.simple', 'res_id': test_record.id }) self.assertIn('-openerp-%d-mail.test.simple' % test_record.id, msg.message_id.split('@')[0]) reply_to_name = '%s %s' % (self.env.user.company_id.name, test_record.name) reply_to_email = '%s@%s' % (self.alias_catchall, self.alias_domain) self.assertEqual(msg.reply_to, formataddr((reply_to_name, reply_to_email))) self.assertEqual( msg.email_from, formataddr((self.user_employee.name, self.user_employee.email)))
def message_get_recipient_values(self, notif_message=None, recipient_ids=None): # real mailing list: multiple recipients (hidden by X-Forge-To) if self.alias_domain and self.alias_name: return { 'email_to': ','.join( formataddr((partner.name, partner.email)) for partner in self.env['res.partner'].sudo().browse(recipient_ids)), 'recipient_ids': [], } return super(Channel, self).message_get_recipient_values( notif_message=notif_message, recipient_ids=recipient_ids)
def test_mail_message_values_document_alias(self): msg = self.Message.create({ 'model': 'mail.test.container', 'res_id': self.alias_record.id }) self.assertIn('-openerp-%d-mail.test' % self.alias_record.id, msg.message_id.split('@')[0]) reply_to_name = '%s %s' % (self.env.user.company_id.name, self.alias_record.name) reply_to_email = '%s@%s' % (self.alias_record.alias_name, self.alias_domain) self.assertEqual(msg.reply_to, formataddr((reply_to_name, reply_to_email))) self.assertEqual( msg.email_from, formataddr((self.user_employee.name, self.user_employee.email))) # no alias domain -> author self.env['ir.config_parameter'].search([ ('key', '=', 'mail.catchall.domain') ]).unlink() msg = self.Message.create({ 'model': 'mail.test.container', 'res_id': self.alias_record.id }) self.assertIn('-openerp-%d-mail.test' % self.alias_record.id, msg.message_id.split('@')[0]) self.assertEqual( msg.reply_to, formataddr((self.user_employee.name, self.user_employee.email))) self.assertEqual( msg.email_from, formataddr((self.user_employee.name, self.user_employee.email))) # no catchall -> don't care, alias self.env['ir.config_parameter'].set_param('mail.catchall.domain', self.alias_domain) self.env['ir.config_parameter'].search([ ('key', '=', 'mail.catchall.alias') ]).unlink() msg = self.Message.create({ 'model': 'mail.test.container', 'res_id': self.alias_record.id }) self.assertIn('-openerp-%d-mail.test' % self.alias_record.id, msg.message_id.split('@')[0]) reply_to_name = '%s %s' % (self.env.company.name, self.alias_record.name) reply_to_email = '%s@%s' % (self.alias_record.alias_name, self.alias_domain) self.assertEqual(msg.reply_to, formataddr((reply_to_name, reply_to_email))) self.assertEqual( msg.email_from, formataddr((self.user_employee.name, self.user_employee.email)))
def _message_get_suggested_recipients(self): recipients = super(Applicant, self)._message_get_suggested_recipients() for applicant in self: if applicant.partner_id: applicant._message_add_suggested_recipient( recipients, partner=applicant.partner_id, reason=_('Contact')) elif applicant.email_from: email_from = applicant.email_from if applicant.partner_name: email_from = tools.formataddr( (applicant.partner_name, email_from)) applicant._message_add_suggested_recipient( recipients, email=email_from, reason=_('Contact Email')) return recipients
def test_mail_message_values_no_document(self): msg = self.Message.create({}) self.assertIn( '-private', msg.message_id.split('@')[0], 'mail_message: message_id for a void message should be a "private" one' ) reply_to_name = self.env.user.company_id.name reply_to_email = '%s@%s' % (self.alias_catchall, self.alias_domain) self.assertEqual(msg.reply_to, formataddr((reply_to_name, reply_to_email))) self.assertEqual( msg.email_from, formataddr((self.user_employee.name, self.user_employee.email))) # no alias domain -> author self.env['ir.config_parameter'].search([ ('key', '=', 'mail.catchall.domain') ]).unlink() msg = self.Message.create({}) self.assertIn( '-private', msg.message_id.split('@')[0], 'mail_message: message_id for a void message should be a "private" one' ) self.assertEqual( msg.reply_to, formataddr((self.user_employee.name, self.user_employee.email))) self.assertEqual( msg.email_from, formataddr((self.user_employee.name, self.user_employee.email))) # no alias catchall, no alias -> author self.env['ir.config_parameter'].set_param('mail.catchall.domain', self.alias_domain) self.env['ir.config_parameter'].search([ ('key', '=', 'mail.catchall.alias') ]).unlink() msg = self.Message.create({}) self.assertIn( '-private', msg.message_id.split('@')[0], 'mail_message: message_id for a void message should be a "private" one' ) self.assertEqual( msg.reply_to, formataddr((self.user_employee.name, self.user_employee.email))) self.assertEqual( msg.email_from, formataddr((self.user_employee.name, self.user_employee.email)))
def _send_prepare_values(self, partner=None): """Return a dictionary for specific email values, depending on a partner, or generic to the whole recipients given by mail.email_to. :param Model partner: specific recipient partner """ self.ensure_one() body = self._send_prepare_body() body_alternative = tools.html2plaintext(body) if partner: email_to = [ tools.formataddr((partner.name or 'False', partner.email or 'False')) ] else: email_to = tools.email_split_and_format(self.email_to) res = { 'body': body, 'body_alternative': body_alternative, 'email_to': email_to, } return res
def test_notification_reply_to_batch(self): test_records_sudo = self.env['mail.test.container'].sudo().create([{ 'alias_name': 'alias.test.%s.%d' % (self.env.user.name, index), 'customer_id': self.customer.id, 'name': 'Test_%d' % index, } for index in range(10)]) with self.assertQueryCount(__system__=1, emp=1): test_records = self.env['mail.test.container'].browse( test_records_sudo.ids) reply_to = test_records._notify_get_reply_to( default=self.env.user.email_formatted) for record in test_records: self.assertEqual( reply_to[record.id], formataddr( ("%s %s" % (self.env.user.company_id.name, record.name), "%s@%s" % (record.alias_name, self.alias_domain))))
def _get_default_from(self): if self.env.user.email: return tools.formataddr((self.env.user.name, self.env.user.email)) raise UserError( _("Unable to post message, please configure the sender's email address." ))
def _notify_get_reply_to(self, default=None, records=None, company=None, doc_names=None): """ Returns the preferred reply-to email address when replying to a thread on documents. This method is a generic implementation available for all models as we could send an email through mail templates on models not inheriting from mail.thread. Reply-to is formatted like "MyCompany MyDocument <reply.to@domain>". Heuristic it the following: * search for specific aliases as they always have priority; it is limited to aliases linked to documents (like project alias for task for example); * use catchall address; * use default; This method can be used as a generic tools if self is a void recordset. Override this method on a specific model to implement model-specific behavior. Also consider inheriting from ``mail.thread``. An example would be tasks taking their reply-to alias from their project. :param default: default email if no alias or catchall is found; :param records: DEPRECATED, self should be a valid record set or an empty recordset if a generic reply-to is required; :param company: used to compute company name part of the from name; provide it if already known, otherwise fall back on user company; :param doc_names: dict(res_id, doc_name) used to compute doc name part of the from name; provide it if already known to avoid queries, otherwise name_get on document will be performed; :return result: dictionary. Keys are record IDs and value is formatted like an email "Company_name Document_name <reply_to@email>"/ """ if records: raise ValueError( 'Use of records is deprecated as this method is available on BaseModel.' ) _records = self model = _records._name if _records and _records._name != 'mail.thread' else False res_ids = _records.ids if _records and model else [] _res_ids = res_ids or [ False ] # always have a default value located in False alias_domain = self.env['ir.config_parameter'].sudo().get_param( "mail.catchall.domain") result = dict.fromkeys(_res_ids, False) result_email = dict() doc_names = doc_names if doc_names else dict() if alias_domain: if model and res_ids: if not doc_names: doc_names = dict( (rec.id, rec.display_name) for rec in _records) mail_aliases = self.env['mail.alias'].sudo().search([ ('alias_parent_model_id.model', '=', model), ('alias_parent_thread_id', 'in', res_ids), ('alias_name', '!=', False) ]) # take only first found alias for each thread_id, to match order (1 found -> limit=1 for each res_id) for alias in mail_aliases: result_email.setdefault( alias.alias_parent_thread_id, '%s@%s' % (alias.alias_name, alias_domain)) # left ids: use catchall left_ids = set(_res_ids) - set(result_email) if left_ids: catchall = self.env['ir.config_parameter'].sudo().get_param( "mail.catchall.alias") if catchall: result_email.update( dict((rid, '%s@%s' % (catchall, alias_domain)) for rid in left_ids)) # compute name of reply-to - TDE tocheck: quotes and stuff like that company_name = company.name if company else self.env.company.name for res_id in result_email: name = '%s%s%s' % (company_name, ' ' if doc_names.get(res_id) else '', doc_names.get(res_id, '')) result[res_id] = tools.formataddr((name, result_email[res_id])) left_ids = set(_res_ids) - set(result_email) if left_ids: result.update(dict((res_id, default) for res_id in left_ids)) return result
def test_event_mail_schedule(self): """ Test mail scheduling for events """ event_cron_id = self.env.ref('event.event_mail_scheduler') # deactivate other schedulers to avoid messing with crons self.env['event.mail'].search([]).unlink() # freeze some datetimes, and ensure more than 1D+1H before event starts # to ease time-based scheduler check now = datetime(2021, 3, 20, 14, 30, 15) event_date_begin = datetime(2021, 3, 22, 8, 0, 0) event_date_end = datetime(2021, 3, 24, 18, 0, 0) with freeze_time(now): test_event = self.env['event.event'].with_user( self.user_eventmanager).create({ 'name': 'TestEventMail', 'auto_confirm': True, 'date_begin': event_date_begin, 'date_end': event_date_end, 'event_mail_ids': [ ( 0, 0, { # right at subscription 'interval_unit': 'now', 'interval_type': 'after_sub', 'template_id': self.env['ir.model.data'].xmlid_to_res_id( 'event.event_subscription') }), ( 0, 0, { # one day after subscription 'interval_nbr': 1, 'interval_unit': 'hours', 'interval_type': 'after_sub', 'template_id': self.env['ir.model.data'].xmlid_to_res_id( 'event.event_subscription') }), ( 0, 0, { # 1 days before event 'interval_nbr': 1, 'interval_unit': 'days', 'interval_type': 'before_event', 'template_id': self.env['ir.model.data'].xmlid_to_res_id( 'event.event_reminder') }), ( 0, 0, { # immediately after event 'interval_nbr': 1, 'interval_unit': 'hours', 'interval_type': 'after_event', 'template_id': self.env['ir.model.data'].xmlid_to_res_id( 'event.event_reminder') }), ] }) # check subscription scheduler after_sub_scheduler = self.env['event.mail'].search([ ('event_id', '=', test_event.id), ('interval_type', '=', 'after_sub'), ('interval_unit', '=', 'now') ]) self.assertEqual(len(after_sub_scheduler), 1, 'event: wrong scheduler creation') self.assertEqual(after_sub_scheduler.scheduled_date, test_event.create_date) self.assertTrue(after_sub_scheduler.done) after_sub_scheduler_2 = self.env['event.mail'].search([ ('event_id', '=', test_event.id), ('interval_type', '=', 'after_sub'), ('interval_unit', '=', 'hours') ]) self.assertEqual(len(after_sub_scheduler_2), 1, 'event: wrong scheduler creation') self.assertEqual(after_sub_scheduler_2.scheduled_date, test_event.create_date + relativedelta(hours=1)) self.assertTrue(after_sub_scheduler_2.done) # check before event scheduler event_prev_scheduler = self.env['event.mail'].search([ ('event_id', '=', test_event.id), ('interval_type', '=', 'before_event') ]) self.assertEqual(len(event_prev_scheduler), 1, 'event: wrong scheduler creation') self.assertEqual(event_prev_scheduler.scheduled_date, event_date_begin + relativedelta(days=-1)) self.assertFalse(event_prev_scheduler.done) # check after event scheduler event_next_scheduler = self.env['event.mail'].search([ ('event_id', '=', test_event.id), ('interval_type', '=', 'after_event') ]) self.assertEqual(len(event_next_scheduler), 1, 'event: wrong scheduler creation') self.assertEqual(event_next_scheduler.scheduled_date, event_date_end + relativedelta(hours=1)) self.assertFalse(event_next_scheduler.done) # create some registrations with freeze_time(now), self.mock_mail_gateway(): reg1 = self.env['event.registration'].with_user( self.user_eventuser).create({ 'event_id': test_event.id, 'name': 'Reg1', 'email': '*****@*****.**', }) reg2 = self.env['event.registration'].with_user( self.user_eventuser).create({ 'event_id': test_event.id, 'name': 'Reg2', 'email': '*****@*****.**', }) # REGISTRATIONS / PRE SCHEDULERS # -------------------------------------------------- # check registration state self.assertTrue(all(reg.state == 'open' for reg in reg1 + reg2), 'Registrations: should be auto-confirmed') self.assertTrue( all(reg.date_open == now for reg in reg1 + reg2), 'Registrations: should have open date set to confirm date') # verify that subscription scheduler was auto-executed after each registration self.assertEqual( len(after_sub_scheduler.mail_registration_ids), 2, 'event: should have 2 scheduled communication (1 / registration)') for mail_registration in after_sub_scheduler.mail_registration_ids: self.assertEqual(mail_registration.scheduled_date, now) self.assertTrue( mail_registration.mail_sent, 'event: registration mail should be sent at registration creation' ) self.assertTrue(after_sub_scheduler.done, 'event: all subscription mails should have been sent') # check emails effectively sent self.assertEqual( len(self._new_mails), 2, 'event: should have 2 scheduled emails (1 / registration)') self.assertMailMailWEmails( [ formataddr((reg1.name, reg1.email)), formataddr((reg2.name, reg2.email)) ], 'outgoing', content=None, fields_values={ 'subject': 'Your registration at %s' % test_event.name, 'email_from': self.user_eventmanager.company_id.email_formatted, }) # same for second scheduler: scheduled but not sent self.assertEqual( len(after_sub_scheduler_2.mail_registration_ids), 2, 'event: should have 2 scheduled communication (1 / registration)') for mail_registration in after_sub_scheduler_2.mail_registration_ids: self.assertEqual(mail_registration.scheduled_date, now + relativedelta(hours=1)) self.assertFalse( mail_registration.mail_sent, 'event: registration mail should be scheduled, not sent') self.assertFalse( after_sub_scheduler_2.done, 'event: all subscription mails should be scheduled, not sent') # execute event reminder scheduler explicitly, before scheduled date -> should not do anything with freeze_time(now), self.mock_mail_gateway(): after_sub_scheduler_2.execute() self.assertFalse( any(mail_reg.mail_sent for mail_reg in after_sub_scheduler_2.mail_registration_ids)) self.assertFalse(after_sub_scheduler_2.done) self.assertEqual(len(self._new_mails), 0, 'event: should not send mails before scheduled date') # execute event reminder scheduler explicitly, right at scheduled date -> should sent mails now_registration = now + relativedelta(hours=1) with freeze_time(now_registration), self.mock_mail_gateway(): after_sub_scheduler_2.execute() # verify that subscription scheduler was auto-executed after each registration self.assertEqual( len(after_sub_scheduler_2.mail_registration_ids), 2, 'event: should have 2 scheduled communication (1 / registration)') self.assertTrue( all(mail_reg.mail_sent for mail_reg in after_sub_scheduler_2.mail_registration_ids)) # FIXME: field not updated # self.assertTrue(after_sub_scheduler_2.done, 'event: all subscription mails should have been sent') # check emails effectively sent self.assertEqual( len(self._new_mails), 2, 'event: should have 2 scheduled emails (1 / registration)') self.assertMailMailWEmails( [ formataddr((reg1.name, reg1.email)), formataddr((reg2.name, reg2.email)) ], 'outgoing', content=None, fields_values={ 'subject': 'Your registration at %s' % test_event.name, 'email_from': self.user_eventmanager.company_id.email_formatted, }) # PRE SCHEDULERS (MOVE FORWARD IN TIME) # -------------------------------------------------- self.assertFalse(event_prev_scheduler.mail_sent) self.assertFalse(event_prev_scheduler.done) # execute event reminder scheduler explicitly, before scheduled date -> should not do anything now_start = event_date_begin + relativedelta(hours=-25) with freeze_time(now_start), self.mock_mail_gateway(): event_prev_scheduler.execute() self.assertFalse(event_prev_scheduler.mail_sent) self.assertFalse(event_prev_scheduler.done) self.assertEqual(len(self._new_mails), 0) # execute cron to run schedulers now_start = event_date_begin + relativedelta(hours=-23) with freeze_time(now_start), self.mock_mail_gateway(): event_cron_id.method_direct_trigger() # check that scheduler is finished self.assertTrue(event_prev_scheduler.mail_sent, 'event: reminder scheduler should have run') self.assertTrue(event_prev_scheduler.done, 'event: reminder scheduler should have run') # check emails effectively sent self.assertEqual( len(self._new_mails), 2, 'event: should have scheduled 2 mails (1 / registration)') self.assertMailMailWEmails( [ formataddr((reg1.name, reg1.email)), formataddr((reg2.name, reg2.email)) ], 'outgoing', content=None, fields_values={ 'subject': '%s: tomorrow' % test_event.name, 'email_from': self.user_eventmanager.company_id.email_formatted, }) # NEW REGISTRATION EFFECT ON SCHEDULERS # -------------------------------------------------- test_event.write({'auto_confirm': False}) with freeze_time(now_start), self.mock_mail_gateway(): reg3 = self.env['event.registration'].with_user( self.user_eventuser).create({ 'event_id': test_event.id, 'name': 'Reg3', 'email': '*****@*****.**', }) # no more seats self.assertEqual(reg3.state, 'draft') # schedulers state untouched self.assertTrue(event_prev_scheduler.mail_sent) self.assertTrue(event_prev_scheduler.mail_sent) self.assertFalse(event_next_scheduler.mail_sent) self.assertFalse(event_next_scheduler.done) self.assertFalse( after_sub_scheduler.done, 'event: scheduler registrations should be lower than effective registrations' ) self.assertFalse( after_sub_scheduler_2.done, 'event: scheduler registrations should be lower than effective registrations' ) # confirm registration -> should trigger registration schedulers # NOTE: currently all schedulers are based on date_open which equals create_date # meaning several communications may be sent in the time time with freeze_time(now_start + relativedelta(hours=1)), self.mock_mail_gateway(): reg3.action_confirm() # verify that subscription scheduler was auto-executed after new registration confirmed self.assertEqual( len(after_sub_scheduler.mail_registration_ids), 3, 'event: should have 3 scheduled communication (1 / registration)') new_mail_reg = after_sub_scheduler.mail_registration_ids.filtered( lambda mail_reg: mail_reg.registration_id == reg3) self.assertEqual(new_mail_reg.scheduled_date, now_start) self.assertTrue( new_mail_reg.mail_sent, 'event: registration mail should be sent at registration creation') self.assertTrue(after_sub_scheduler.done, 'event: all subscription mails should have been sent') # verify that subscription scheduler was auto-executed after new registration confirmed self.assertEqual( len(after_sub_scheduler_2.mail_registration_ids), 3, 'event: should have 3 scheduled communication (1 / registration)') new_mail_reg = after_sub_scheduler_2.mail_registration_ids.filtered( lambda mail_reg: mail_reg.registration_id == reg3) self.assertEqual(new_mail_reg.scheduled_date, now_start + relativedelta(hours=1)) self.assertTrue( new_mail_reg.mail_sent, 'event: registration mail should be sent at registration creation') self.assertTrue(after_sub_scheduler_2.done, 'event: all subscription mails should have been sent') # check emails effectively sent self.assertEqual( len(self._new_mails), 2, 'event: should have 1 scheduled emails (new registration only)') # manual check because 2 identical mails are sent and mail tools do not support it easily for mail in self._new_mails: self.assertEqual(mail.email_from, self.user_eventmanager.company_id.email_formatted) self.assertEqual(mail.subject, 'Your registration at %s' % test_event.name) self.assertEqual(mail.state, 'outgoing') self.assertEqual(mail.email_to, formataddr( (reg3.name, reg3.email))) # POST SCHEDULERS (MOVE FORWARD IN TIME) # -------------------------------------------------- self.assertFalse(event_next_scheduler.mail_sent) self.assertFalse(event_next_scheduler.done) # execute event reminder scheduler explicitly after its schedule date new_end = event_date_end + relativedelta(hours=2) with freeze_time(new_end), self.mock_mail_gateway(): event_cron_id.method_direct_trigger() # check that scheduler is finished self.assertTrue(event_next_scheduler.mail_sent, 'event: reminder scheduler should should have run') self.assertTrue(event_next_scheduler.done, 'event: reminder scheduler should have run') # check emails effectively sent self.assertEqual( len(self._new_mails), 3, 'event: should have scheduled 3 mails, one for each registration') self.assertMailMailWEmails( [ formataddr((reg1.name, reg1.email)), formataddr((reg2.name, reg2.email)), formataddr((reg3.name, reg3.email)) ], 'outgoing', content=None, fields_values={ 'subject': '%s: today' % test_event.name, 'email_from': self.user_eventmanager.company_id.email_formatted, })
def test_message_post(self): email1 = '*****@*****.**' email2 = '*****@*****.**' self.channel_1._update_moderation_email([email1], 'ban') self.channel_1._update_moderation_email([email2], 'allow') msg_admin = self.channel_1.message_post(message_type='email', subtype_xmlid='mail.mt_comment', author_id=self.partner_admin.id) msg_moderator = self.channel_1.message_post(message_type='comment', subtype_xmlid='mail.mt_comment', author_id=self.partner_employee.id) msg_email1 = self.channel_1.message_post(message_type='comment', subtype_xmlid='mail.mt_comment', email_from=formataddr(("MyName", email1))) msg_email2 = self.channel_1.message_post(message_type='email', subtype_xmlid='mail.mt_comment', email_from=email2) msg_notif = self.channel_1.message_post() messages = self.env['mail.message'].search([('model', '=', 'mail.channel'), ('res_id', '=', self.channel_1.id)]) pending_messages = messages.filtered(lambda m: m.moderation_status == 'pending_moderation') accepted_messages = messages.filtered(lambda m: m.moderation_status == 'accepted') self.assertFalse(msg_email1) self.assertEqual(msg_admin, pending_messages) self.assertEqual(accepted_messages, msg_moderator | msg_email2 | msg_notif) self.assertFalse(msg_admin.channel_ids) self.assertEqual(msg_email2.channel_ids, self.channel_1)