Добавлена умная фильтрация для поиска по номерам телефонов
Проблема: Поиск "x3m" неправильно находит клиента Наталью потому что её номер
содержит цифру "3". Это происходило, потому что система искала по любым цифрам
в query, даже если это явно не номер телефона.
Решение: Добавлена функция is_query_phone_only() которая проверяет, содержит ли
query ТОЛЬКО телефонные символы (цифры, +, -, (), пробелы, точка).
Поиск по номеру телефона происходит ТОЛЬКО если:
1. Query состоит ТОЛЬКО из телефонных символов (никаких букв)
2. И количество цифр >= 3
Примеры:
- "x3m" → НЕ ищет по цифре "3" (содержит букву)
- "29" → НЕ ищет по цифрам (только 2 цифры, нужно минимум 3)
- "295" → ИЩЕТ по цифрам "295" (только цифры, 3+ символов)
- "+375291234567" → ИЩЕТ по номеру (только телефонные символы)
- "team_x3m" → НЕ ищет по цифрам (содержит буквы и _)
Изменения:
1. Добавлена функция is_query_phone_only() в views.py
2. Обновлена api_search_customers() для использования новой функции
3. Обновлена customer_list() для использования новой функции
4. Добавлены 19 unit-тестов для is_query_phone_only()
Результаты тестирования:
✓ 42 теста всего (23 для determine_search_strategy + 19 для is_query_phone_only)
✓ Все тесты проходят успешно
Критические тест-кейсы:
✓ is_query_phone_only('x3m') == False (решает исходную проблему)
✓ is_query_phone_only('295') == True
✓ is_query_phone_only('+375291234567') == True
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -41,10 +41,26 @@ def customer_list(request):
|
||||
# Строим Q-объект для поиска (единая функция)
|
||||
q_objects = build_customer_search_query(query, strategy, search_value)
|
||||
|
||||
# Добавляем поиск по телефону
|
||||
# Добавляем поиск по телефону (умная логика)
|
||||
if phone_normalized:
|
||||
q_objects |= Q(phone__icontains=phone_normalized)
|
||||
|
||||
# Проверяем, похож ли query на номер телефона (только цифры и минимум 3 цифры)
|
||||
query_digits = ''.join(c for c in query if c.isdigit())
|
||||
should_search_by_phone_digits = is_query_phone_only(query) and len(query_digits) >= 3
|
||||
|
||||
if should_search_by_phone_digits:
|
||||
# Ищем клиентов, чьи телефоны содержат введенные цифры
|
||||
customers_by_phone = Customer.objects.filter(phone__isnull=False)
|
||||
matching_by_digits = []
|
||||
for customer in customers_by_phone:
|
||||
customer_digits = ''.join(c for c in str(customer.phone) if c.isdigit())
|
||||
if query_digits in customer_digits:
|
||||
matching_by_digits.append(customer.pk)
|
||||
|
||||
if matching_by_digits:
|
||||
q_objects |= Q(pk__in=matching_by_digits)
|
||||
|
||||
customers = customers.filter(q_objects)
|
||||
|
||||
customers = customers.order_by('-created_at')
|
||||
@@ -167,6 +183,32 @@ def determine_search_strategy(query):
|
||||
return ('name_only', query)
|
||||
|
||||
|
||||
def is_query_phone_only(query):
|
||||
"""
|
||||
Проверяет, содержит ли query только символы телефонного номера.
|
||||
|
||||
Возвращает True, если query состоит ТОЛЬКО из:
|
||||
- цифр: 0-9
|
||||
- телефонных символов: +, -, (, ), пробелов
|
||||
|
||||
Возвращает False, если есть буквы или другие символы (означает, что это поиск по имени/email).
|
||||
|
||||
Примеры:
|
||||
- '295' → True (только цифры)
|
||||
- '+375291234567' → True (цифры и телефонные символы)
|
||||
- '(029) 123-45' → True (цифры и телефонные символы)
|
||||
- 'x3m' → False (содержит буквы)
|
||||
- 'team_x3m' → False (содержит буквы)
|
||||
- 'Иван' → False (содержит буквы)
|
||||
"""
|
||||
if not query:
|
||||
return False
|
||||
|
||||
# Проверяем, что query содержит ТОЛЬКО цифры и телефонные символы
|
||||
phone_chars = set('0123456789+- ().')
|
||||
return all(c in phone_chars for c in query)
|
||||
|
||||
|
||||
def build_customer_search_query(query, strategy, search_value):
|
||||
"""
|
||||
Строит Q-объект для поиска клиентов на основе стратегии.
|
||||
@@ -254,11 +296,17 @@ def api_search_customers(request):
|
||||
# Строим Q-объект для поиска (единая функция, используется везде)
|
||||
q_objects = build_customer_search_query(query, strategy, search_value)
|
||||
|
||||
# Для телефона ищем по нормализованному номеру и по цифрам
|
||||
# Для поиска по номерам телефонов: применяем умную логику
|
||||
# Ищем по телефону ТОЛЬКО если query состоит из ТОЛЬКО цифр и телефонных символов
|
||||
# (никаких букв — потому что если есть буквы, это явно поиск по имени/email, не по телефону)
|
||||
|
||||
if phone_normalized:
|
||||
q_objects |= Q(phone__icontains=phone_normalized)
|
||||
|
||||
if query_digits:
|
||||
# Проверяем, похож ли query на номер телефона (только цифры/+/-/() и минимум 3 цифры)
|
||||
should_search_by_phone_digits = is_query_phone_only(query) and len(query_digits) >= 3
|
||||
|
||||
if should_search_by_phone_digits:
|
||||
# Ищем клиентов, чьи телефоны содержат введенные цифры
|
||||
customers_by_phone = Customer.objects.filter(phone__isnull=False)
|
||||
matching_by_digits = []
|
||||
|
||||
Reference in New Issue
Block a user