diff --git a/addons/phone_validation/i18n/phone_validation.pot b/addons/phone_validation/i18n/phone_validation.pot index 4dd9f47f91b..0c2fc3ce383 100644 --- a/addons/phone_validation/i18n/phone_validation.pot +++ b/addons/phone_validation/i18n/phone_validation.pot @@ -248,6 +248,12 @@ msgstr "" msgid "Messages" msgstr "" +#. module: phone_validation +#: code:addons/phone_validation/models/mail_thread_phone.py:0 +#, python-format +msgid "Missing definition of phone fields." +msgstr "" + #. module: phone_validation #: model:ir.model.constraint,message:phone_validation.constraint_phone_blacklist_unique_number msgid "Number already exists" diff --git a/addons/phone_validation/models/mail_thread_phone.py b/addons/phone_validation/models/mail_thread_phone.py index 3cb3364f857..229c743d9a4 100644 --- a/addons/phone_validation/models/mail_thread_phone.py +++ b/addons/phone_validation/models/mail_thread_phone.py @@ -6,6 +6,7 @@ import re from odoo import api, fields, models, _ from odoo.addons.phone_validation.tools import phone_validation from odoo.exceptions import AccessError, UserError +from odoo.osv import expression class PhoneMixin(models.AbstractModel): @@ -47,6 +48,13 @@ class PhoneMixin(models.AbstractModel): phone_mobile_search = fields.Char("Phone/Mobile", store=False, search='_search_phone_mobile_search') def _search_phone_mobile_search(self, operator, value): + phone_fields = [ + fname for fname in self._phone_get_number_fields() + if fname in self._fields and self._fields[fname].store + ] + if not phone_fields: + raise UserError(_('Missing definition of phone fields.')) + value = value.strip() if len(value) < 3: raise UserError(_('Please enter at least 3 characters when searching a Phone/Mobile number.')) @@ -55,39 +63,35 @@ class PhoneMixin(models.AbstractModel): if value.startswith('+') or value.startswith('00'): # searching on +32485112233 should also finds 0032485112233 (and vice versa) # we therefore remove it from input value and search for both of them in db + where_str = ' OR '.join( + f"""model.{phone_field} IS NOT NULL AND ( + REGEXP_REPLACE(model.{phone_field}, %s, '', 'g') ILIKE %s OR + REGEXP_REPLACE(model.{phone_field}, %s, '', 'g') ILIKE %s + )""" + for phone_field in phone_fields + ) query = f""" SELECT model.id FROM {self._table} model - WHERE - model.phone IS NOT NULL AND ( - REGEXP_REPLACE(model.phone, %s, '', 'g') ILIKE %s OR - REGEXP_REPLACE(model.phone, %s, '', 'g') ILIKE %s - ) OR - model.mobile IS NOT NULL AND ( - REGEXP_REPLACE(model.mobile, %s, '', 'g') ILIKE %s OR - REGEXP_REPLACE(model.mobile, %s, '', 'g') ILIKE %s - ); + WHERE {where_str}; """ term = re.sub(pattern, '', value[1 if value.startswith('+') else 2:]) + '%' - self._cr.execute(query, ( - pattern, '00' + term, - pattern, '+' + term, - pattern, '00' + term, - pattern, '+' + term - )) + self._cr.execute( + query, + (pattern, '00' + term, pattern, '+' + term) * len(phone_fields) + ) else: + where_str = ' OR '.join( + f"REGEXP_REPLACE(model.{phone_field}, %s, '', 'g') ILIKE %s" + for phone_field in phone_fields + ) query = f""" SELECT model.id FROM {self._table} model - WHERE - REGEXP_REPLACE(model.phone, %s, '', 'g') ILIKE %s OR - REGEXP_REPLACE(model.mobile, %s, '', 'g') ILIKE %s; + WHERE {where_str}; """ term = '%' + re.sub(pattern, '', value) + '%' - self._cr.execute(query, ( - pattern, term, - pattern, term - )) + self._cr.execute(query, (pattern, term) * len(phone_fields)) res = self._cr.fetchall() if not res: return [(0, '=', 1)] diff --git a/addons/test_mail_sms/tests/test_mail_thread_phone.py b/addons/test_mail_sms/tests/test_mail_thread_phone.py index cc8b5aeae1b..e26bef4aee2 100644 --- a/addons/test_mail_sms/tests/test_mail_thread_phone.py +++ b/addons/test_mail_sms/tests/test_mail_thread_phone.py @@ -45,3 +45,49 @@ class TestSMSActionsCommon(TestSMSCommon, TestSMSRecipients): self.test_phone_records.mapped('phone_nbr'), [False] * 5 + ['+32475110505', '0032475110606', '0032475110707', False] ) + + @users('employee') + def test_search_phone_mobile_search_equal(self): + """ Test searching by phone/mobile with direct search """ + test_phone_records = self.test_phone_records.with_env(self.env) + + # test "=" search + # Currently not suported, returning results for "ilike" + results = self.env['mail.test.sms.bl'].search([('phone_mobile_search', '=', '0475')]) + self.assertEqual(results, test_phone_records[:5]) + results = self.env['mail.test.sms.bl'].search([('phone_mobile_search', '=', '0475000000')]) + self.assertEqual(results, test_phone_records[0]) + results = self.env['mail.test.sms.bl'].search([('phone_mobile_search', '=', '0032475110606')]) + self.assertEqual(results, test_phone_records[6]) + results = self.env['mail.test.sms.bl'].search([('phone_mobile_search', '=', '+32475110606')]) + self.assertEqual(results, test_phone_records[6]) + + @users('employee') + def test_search_phone_mobile_search_ilike(self): + """ Test searching by phone/mobile on various ilike combinations """ + test_phone_records = self.test_phone_records.with_env(self.env) + + # test ilike search + results = self.env['mail.test.sms.bl'].search([('phone_mobile_search', 'ilike', '0475')]) + self.assertEqual(results, test_phone_records[:5]) + results = self.env['mail.test.sms.bl'].search([('phone_mobile_search', 'ilike', '101')]) + self.assertEqual(results, test_phone_records[1]) + + # test search using +32/0032 + results = self.env['mail.test.sms.bl'].search([('phone_mobile_search', 'ilike', '+32475')]) + self.assertEqual(results, test_phone_records[5:8], + 'Search on phone_mobile_search: +32/0032 likeliness') + results = self.env['mail.test.sms.bl'].search([('phone_mobile_search', 'ilike', '0032475')]) + self.assertEqual(results, test_phone_records[5:8], + 'Search on phone_mobile_search: +32/0032 likeliness') + + # test inverse ilike search + # Currently not supported, returning results for "ilike" + results = self.env['mail.test.sms.bl'].search([('phone_mobile_search', 'not ilike', '0475')]) + # self.assertEqual(results, test_phone_records - test_phone_records[:5], + self.assertEqual(results, test_phone_records[:5], + 'Seach on phone_mobile_search: not ilike not supported') + results = self.env['mail.test.sms.bl'].search([('phone_mobile_search', 'not ilike', '101')]) + # self.assertEqual(results, test_phone_records - test_phone_records[1], + self.assertEqual(results, test_phone_records[1], + 'Seach on phone_mobile_search: not ilike not supported')