# -*- coding: utf-8 -*- # Part of Odoo. See LICENSE file for full copyright and licensing details. from uuid import uuid4 from odoo.addons.mail.tests.common import MailCommon, mail_new_test_user from odoo.tests.common import Form, users from odoo.tests import tagged # samples use effective TLDs from the Mozilla public suffix # list at http://publicsuffix.org SAMPLES = [ ('"Raoul Grosbedon" ', 'Raoul Grosbedon', 'raoul@chirurgiens-dentistes.fr'), ('ryu+giga-Sushi@aizubange.fukushima.jp', '', 'ryu+giga-Sushi@aizubange.fukushima.jp'), ('Raoul chirurgiens-dentistes.fr', 'Raoul chirurgiens-dentistes.fr', ''), (" Raoul O'hara ", "Raoul O'hara", '!@historicalsociety.museum'), ('Raoul Grosbedon ', 'Raoul Grosbedon', 'raoul@CHIRURGIENS-dentistes.fr'), ('Raoul megaraoul@chirurgiens-dentistes.fr', 'Raoul', 'megaraoul@chirurgiens-dentistes.fr'), ('"Patrick Da Beast Poilvache" ', 'Patrick Poilvache', 'patrick@example.com'), ('Patrick Caché ', 'Patrick Poilvache', 'patrick@example.com'), ('Patrick Caché <2patrick@EXAMPLE.COM>', 'Patrick Caché', '2patrick@example.com'), ] @tagged('res_partner', 'mail_tools') class TestPartner(MailCommon): def _check_find_or_create(self, test_string, expected_name, expected_email, expected_email_normalized=False, check_partner=False, should_create=False): expected_email_normalized = expected_email_normalized or expected_email partner = self.env['res.partner'].find_or_create(test_string) if should_create and check_partner: self.assertTrue(partner.id > check_partner.id, 'find_or_create failed - should have found existing') elif check_partner: self.assertEqual(partner, check_partner, 'find_or_create failed - should have found existing') self.assertEqual(partner.name, expected_name) self.assertEqual(partner.email or '', expected_email) self.assertEqual(partner.email_normalized or '', expected_email_normalized) return partner @users('admin') def test_res_partner_find_or_create(self): Partner = self.env['res.partner'] partner = Partner.browse(Partner.name_create(SAMPLES[0][0])[0]) self._check_find_or_create( SAMPLES[0][0], SAMPLES[0][1], SAMPLES[0][2], check_partner=partner, should_create=False ) partner_2 = Partner.browse(Partner.name_create('sarah.john@connor.com')[0]) found_2 = self._check_find_or_create( 'john@connor.com', 'john@connor.com', 'john@connor.com', check_partner=partner_2, should_create=True ) new = self._check_find_or_create( SAMPLES[1][0], SAMPLES[1][2].lower(), SAMPLES[1][2].lower(), check_partner=found_2, should_create=True ) new2 = self._check_find_or_create( SAMPLES[2][0], SAMPLES[2][1], SAMPLES[2][2], check_partner=new, should_create=True ) self._check_find_or_create( SAMPLES[3][0], SAMPLES[3][1], SAMPLES[3][2], check_partner=new2, should_create=True ) new4 = self._check_find_or_create( SAMPLES[4][0], SAMPLES[0][1], SAMPLES[0][2], check_partner=partner, should_create=False ) self._check_find_or_create( SAMPLES[5][0], SAMPLES[5][1], SAMPLES[5][2], check_partner=new4, should_create=True ) existing = Partner.create({ 'name': SAMPLES[6][1], 'email': SAMPLES[6][0], }) self.assertEqual(existing.name, SAMPLES[6][1]) self.assertEqual(existing.email, SAMPLES[6][0]) self.assertEqual(existing.email_normalized, SAMPLES[6][2]) new6 = self._check_find_or_create( SAMPLES[7][0], SAMPLES[6][1], SAMPLES[6][0], expected_email_normalized=SAMPLES[6][2], check_partner=existing, should_create=False ) self._check_find_or_create( SAMPLES[8][0], SAMPLES[8][1], SAMPLES[8][2], check_partner=new6, should_create=True ) with self.assertRaises(ValueError): self.env['res.partner'].find_or_create("Raoul chirurgiens-dentistes.fr", assert_valid_email=True) @users('admin') def test_res_partner_find_or_create_email(self): """ Test 'find_or_create' tool used in mail, notably when linking emails found in recipients to partners when sending emails using the mail composer. """ partners = self.env['res.partner'].create([ { 'email': 'classic.format@test.example.com', 'name': 'Classic Format', }, { 'email': '"FindMe Format" ', 'name': 'FindMe Format', }, { 'email': 'find.me.multi.1@test.example.com, "FindMe Multi" ', 'name': 'FindMe Multi', }, ]) # check data used for finding / searching self.assertEqual( partners.mapped('email_formatted'), ['"Classic Format" ', '"FindMe Format" ', '"FindMe Multi" '] ) # when having multi emails, first found one is taken as normalized email self.assertEqual( partners.mapped('email_normalized'), ['classic.format@test.example.com', 'find.me.format@test.example.com', 'find.me.multi.1@test.example.com'] ) # classic find or create: use normalized email to compare records for email in ('CLASSIC.FORMAT@TEST.EXAMPLE.COM', '"Another Name" '): with self.subTest(email=email): self.assertEqual(self.env['res.partner'].find_or_create(email), partners[0]) # find on encapsulated email: comparison of normalized should work for email in ('FIND.ME.FORMAT@TEST.EXAMPLE.COM', '"Different Format" '): with self.subTest(email=email): self.assertEqual(self.env['res.partner'].find_or_create(email), partners[1]) # multi-emails -> no normalized email -> fails each time, create new partner (FIXME) for email_input, match_partner in [ ('find.me.multi.1@test.example.com', partners[2]), ('find.me.multi.2@test.example.com', self.env['res.partner']), ]: with self.subTest(email_input=email_input): partner = self.env['res.partner'].find_or_create(email_input) # either matching existing, either new partner if match_partner: self.assertEqual(partner, match_partner) else: self.assertNotIn(partner, partners) self.assertEqual(partner.email, email_input) partner.unlink() # do not mess with subsequent tests # now input is multi email -> '_parse_partner_name' used in 'find_or_create' # before trying to normalize is quite tolerant, allowing positive checks for email_input, match_partner, exp_email_partner in [ ('classic.format@test.example.com,another.email@test.example.com', partners[0], 'classic.format@test.example.com'), # first found email matches existing ('another.email@test.example.com,classic.format@test.example.com', self.env['res.partner'], 'another.email@test.example.com'), # first found email does not match ('find.me.multi.1@test.example.com,find.me.multi.2@test.example.com', self.env['res.partner'], 'find.me.multi.1@test.example.com'), ]: with self.subTest(email_input=email_input): partner = self.env['res.partner'].find_or_create(email_input) # either matching existing, either new partner if match_partner: self.assertEqual(partner, match_partner) else: self.assertNotIn(partner, partners) self.assertEqual(partner.email, exp_email_partner) if partner not in partners: partner.unlink() # do not mess with subsequent tests def test_res_partner_get_mention_suggestions_priority(self): name = uuid4() # unique name to avoid conflict with already existing users self.env['res.partner'].create([{'name': f'{name}-{i}-not-user'} for i in range(0, 2)]) for i in range(0, 2): mail_new_test_user(self.env, login=f'{name}-{i}-portal-user', groups='base.group_portal') mail_new_test_user(self.env, login=f'{name}-{i}-internal-user', groups='base.group_user') partners_format = self.env['res.partner'].get_mention_suggestions(name, limit=5) self.assertEqual(len(partners_format), 5, "should have found limit (5) partners") # return format for user is either a dict (there is a user and the dict is data) or a list of command (clear) self.assertEqual(list(map(lambda p: isinstance(p['user'], dict) and p['user']['isInternalUser'], partners_format)), [True, True, False, False, False], "should return internal users in priority") self.assertEqual(list(map(lambda p: isinstance(p['user'], dict), partners_format)), [True, True, True, True, False], "should return partners without users last") def test_res_partner_log_portal_group(self): Users = self.env['res.users'] subtype_note = self.env.ref('mail.mt_note') group_portal, group_user = self.env.ref('base.group_portal'), self.env.ref('base.group_user') # check at update new_user = Users.create({ 'email': 'micheline@test.example.com', 'login': 'michmich', 'name': 'Micheline Employee', }) self.assertEqual(len(new_user.message_ids), 1, 'Should contain Contact created log message') new_msg = new_user.message_ids self.assertNotIn('Portal Access Granted', new_msg.body) self.assertIn('Contact created', new_msg.body) new_user.write({'groups_id': [(4, group_portal.id), (3, group_user.id)]}) new_msg = new_user.message_ids[0] self.assertIn('Portal Access Granted', new_msg.body) self.assertEqual(new_msg.subtype_id, subtype_note) # check at create new_user = Users.create({ 'email': 'micheline.2@test.example.com', 'groups_id': [(4, group_portal.id)], 'login': 'michmich.2', 'name': 'Micheline Portal', }) self.assertEqual(len(new_user.message_ids), 2, 'Should contain Contact created + Portal access log messages') new_msg = new_user.message_ids[0] self.assertIn('Portal Access Granted', new_msg.body) self.assertEqual(new_msg.subtype_id, subtype_note) @users('admin') def test_res_partner_merge_wizards(self): Partner = self.env['res.partner'] p1 = Partner.create({'name': 'Customer1', 'email': 'test1@test.example.com'}) p1_msg_ids_init = p1.message_ids p2 = Partner.create({'name': 'Customer2', 'email': 'test2@test.example.com'}) p2_msg_ids_init = p2.message_ids p3 = Partner.create({'name': 'Other (dup email)', 'email': 'test1@test.example.com'}) # add some mail related documents p1.message_subscribe(partner_ids=p3.ids) p1_act1 = p1.activity_schedule(act_type_xmlid='mail.mail_activity_data_todo') p1_msg1 = p1.message_post( body='

Log on P1

', subtype_id=self.env.ref('mail.mt_comment').id ) self.assertEqual(p1.activity_ids, p1_act1) self.assertEqual(p1.message_follower_ids.partner_id, self.partner_admin + p3) self.assertEqual(p1.message_ids, p1_msg_ids_init + p1_msg1) self.assertEqual(p2.activity_ids, self.env['mail.activity']) self.assertEqual(p2.message_follower_ids.partner_id, self.partner_admin) self.assertEqual(p2.message_ids, p2_msg_ids_init) MergeForm = Form(self.env['base.partner.merge.automatic.wizard'].with_context( active_model='res.partner', active_ids=(p1 + p2).ids )) self.assertEqual(MergeForm.partner_ids[:], p1 + p2) self.assertEqual(MergeForm.dst_partner_id, p2) merge_form = MergeForm.save() merge_form.action_merge() # check destination and removal self.assertFalse(p1.exists()) self.assertTrue(p2.exists()) # check mail documents have been moved self.assertEqual(p2.activity_ids, p1_act1) # TDE note: currently not working as soon as there is a single partner duplicated -> should be improved # self.assertEqual(p2.message_follower_ids.partner_id, self.partner_admin + p3) all_msg = p2_msg_ids_init + p1_msg_ids_init + p1_msg1 self.assertEqual(len(p2.message_ids), len(all_msg) + 1, 'Should have original messages + a log') self.assertTrue(all(msg in p2.message_ids for msg in all_msg))