Добавлена умная фильтрация для поиска по номерам телефонов

Проблема: Поиск "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:
2025-11-11 01:00:21 +03:00
parent 96aa0b2f7f
commit 81cadc8cf9
2 changed files with 144 additions and 4 deletions

View File

@@ -1,5 +1,5 @@
from django.test import TestCase
from .views import determine_search_strategy
from .views import determine_search_strategy, is_query_phone_only
class DetermineSearchStrategyTestCase(TestCase):
@@ -158,3 +158,95 @@ class DetermineSearchStrategyTestCase(TestCase):
strategy, search_value = determine_search_strategy('natul')
self.assertEqual(strategy, 'universal')
self.assertEqual(search_value, 'natul')
class IsQueryPhoneOnlyTestCase(TestCase):
"""
Тесты для функции is_query_phone_only().
Проверяют, что функция правильно определяет, содержит ли query
только символы номера телефона (цифры, +, -, (), пробелы).
"""
# ===== Должны вернуть True (только телефонные символы) =====
def test_phone_only_digits(self):
"""Query '295' должен вернуть True (только цифры)"""
self.assertTrue(is_query_phone_only('295'))
def test_phone_only_single_digit(self):
"""Query '5' должен вернуть True (одна цифра)"""
self.assertTrue(is_query_phone_only('5'))
def test_phone_with_plus(self):
"""Query '+375291234567' должен вернуть True"""
self.assertTrue(is_query_phone_only('+375291234567'))
def test_phone_with_dashes(self):
"""Query '029-123-45' должен вернуть True"""
self.assertTrue(is_query_phone_only('029-123-45'))
def test_phone_with_parentheses(self):
"""Query '(029) 123-45' должен вернуть True"""
self.assertTrue(is_query_phone_only('(029) 123-45'))
def test_phone_with_spaces(self):
"""Query '029 123 45' должен вернуть True"""
self.assertTrue(is_query_phone_only('029 123 45'))
def test_phone_complex_format(self):
"""Query '+375 (29) 123-45-67' должен вернуть True"""
self.assertTrue(is_query_phone_only('+375 (29) 123-45-67'))
def test_phone_with_dot(self):
"""Query '029.123.45' должен вернуть True"""
self.assertTrue(is_query_phone_only('029.123.45'))
# ===== Должны вернуть False (содержат буквы или другие символы) =====
def test_query_with_letters_only(self):
"""Query 'abc' должен вернуть False (содержит буквы)"""
self.assertFalse(is_query_phone_only('abc'))
def test_query_with_mixed_letters_digits(self):
"""Query 'x3m' должен вернуть False (содержит буквы)"""
self.assertFalse(is_query_phone_only('x3m'))
def test_query_name_with_digits(self):
"""Query 'team_x3m' должен вернуть False (содержит буквы и _)"""
self.assertFalse(is_query_phone_only('team_x3m'))
def test_query_name_cyrillic(self):
"""Query 'Наталья' должен вернуть False (содержит кириллицу)"""
self.assertFalse(is_query_phone_only('Наталья'))
def test_query_with_underscore(self):
"""Query '123_456' должен вернуть False (содержит _)"""
self.assertFalse(is_query_phone_only('123_456'))
def test_query_with_hash(self):
"""Query '123#456' должен вернуть False (содержит #)"""
self.assertFalse(is_query_phone_only('123#456'))
def test_empty_string(self):
"""Query '' должен вернуть False (пустая строка)"""
self.assertFalse(is_query_phone_only(''))
def test_only_spaces(self):
"""Query ' ' должен вернуть True (только пробелы разрешены)"""
self.assertTrue(is_query_phone_only(' '))
# ===== Real-world cases =====
def test_real_world_case_x3m_should_not_be_phone(self):
"""
Real-world case: "x3m" содержит букву, поэтому НЕ похож на телефон.
Это критично для решения проблемы с поиском Натальи.
"""
self.assertFalse(is_query_phone_only('x3m'))
# Значит, при поиске "x3m" НЕ будет поиска по цифре "3" в телефонах
def test_real_world_case_295_should_be_phone(self):
"""Real-world case: '295' только цифры, похож на телефон"""
self.assertTrue(is_query_phone_only('295'))
def test_real_world_full_phone_number(self):
"""Real-world case: полный номер в стандартном формате"""
self.assertTrue(is_query_phone_only('+375 (29) 598-62-62'))