Files
enterprise-addons/voip/models/res_partner.py
T

135 lines
4.8 KiB
Python

import unicodedata
from odoo import api, fields, models
from odoo.fields import Domain
from odoo.tools import escape_psql
from odoo.addons.mail.tools.discuss import Store
"""
█
█
█
┌────────────────────────┐
│ ██████████████████████ │
│ █ 10:22 PM █ │
│ █ YO LA TEAM █ │
│ ██████████████████████ │ T9 "ENCODING" (ITU E.161)
│ │ =========================
│ ╔══════╦══════╦══════╗ │
│ ║ 1 ║ 2 ║ 3 ║ │ Each letter of the Latin alphabet is mapped to a
│ ║ ║ ABC ║ DEF ║ │ number, which is used to encode a word using only
│ ╠══════╬══════╬══════╣ │ digits, like on an old cell phone keypad.
│ ║ 4 ║ 5 ║ 6 ║ │
│ ║ GHI ║ JKL ║ MNO ║ │
│ ╠══════╬══════╬══════╣ │
│ ║ 7 ║ 8 ║ 9 ║ │
│ ║ PQRS ║ TUV ║ WXYZ ║ │
│ ╠══════╬══════╬══════╣ │
│ ║ * ║ 0 ║ # ║ │
│ ║ ║ ║ ║ │
│ ╚══════╩══════╩══════╝ │
└────────────────────────┘
"""
T9_MAPPING = {
letter: digit
for letters, digit in [
("abc", "2"),
("def", "3"),
("ghi", "4"),
("jkl", "5"),
("mno", "6"),
("pqrs", "7"),
("tuv", "8"),
("wxyz", "9"),
]
for letter in letters
}
LIGATURES = {
"Æ": "Ae",
"æ": "ae",
"Œ": "Oe",
"œ": "oe",
"IJ": "IJ",
"ij": "ij",
}
def expand_ligatures(text):
for ligature, replacement in LIGATURES.items():
text = text.replace(ligature, replacement)
return text
def unaccent(text):
return "".join(
c for c in unicodedata.normalize("NFKD", text) if unicodedata.category(c) != "Mn"
)
class ResPartner(models.Model):
_name = "res.partner"
_inherit = ["res.partner", "voip.country.code.mixin", "voip.queue.mixin"]
t9_name = fields.Char(
compute="_compute_t9_name",
export_string_translation=False,
help=(
"The partner's name, encoded as the digits that correspond to the letters on an old cell phone keypad.\n"
"Useful for searching for partners based on this field.\n"
"Spaces are preserved, characters that can't be encoded are replaced with an 'x'.\n"
"T9 stands for Text on 9 keys, it comes from the name of the original technology on old cell phones."
),
store=True,
)
@api.depends("name")
def _compute_t9_name(self):
def encode(letter):
if letter in T9_MAPPING:
return T9_MAPPING[letter]
if letter in "0123456789 ":
return letter
return "x"
for partner in self:
if not partner.name:
partner.t9_name = False
continue
normalized_name = expand_ligatures(unaccent(partner.name)).casefold()
partner.t9_name = "".join(encode(letter) for letter in normalized_name)
# Add a space at the beginning so you can search for matches at the
# beginning of each word using a pattern like '% 234%'.
partner.t9_name = " " + partner.t9_name
@api.model
def get_contacts(self, offset, limit, search_terms, t9_search=False):
domain = Domain("phone", "!=", False)
if search_terms:
escaped_search_terms = escape_psql(search_terms)
subdomain = Domain.OR([
[("complete_name", "ilike", escaped_search_terms)],
[("email", "ilike", escaped_search_terms)],
])
if len(search_terms) >= self._phone_search_min_length:
subdomain |= Domain("phone_mobile_search", "like", escaped_search_terms)
if t9_search:
subdomain = Domain.OR([subdomain, [("t9_name", "ilike", f" {escaped_search_terms}")]])
domain = Domain.AND([domain, subdomain])
contacts = self.search(domain, offset=offset, limit=limit)
return Store().add(contacts, self._voip_get_store_fields()).get_result()
def _voip_get_store_fields(self):
return [
"commercial_company_name",
"email",
"function",
"is_company",
"name",
"phone",
"phone_sanitized",
Store.One("phone_country_id", self.env["res.country"]._voip_get_store_fields()),
"t9_name",
]