151 lines
4.9 KiB
Python
151 lines
4.9 KiB
Python
"""
|
||
Утилиты для работы с клиентскими счетами
|
||
"""
|
||
import re
|
||
from typing import Optional, List
|
||
|
||
|
||
def validate_account_number(account_number: str) -> bool:
|
||
"""
|
||
Проверяет корректность формата номера клиентского счета
|
||
Формат: XX-XX-XX-XX-XX-XX-XX (7 пар цифр через дефис)
|
||
|
||
Args:
|
||
account_number: Номер счета для проверки
|
||
|
||
Returns:
|
||
bool: True если формат корректен, False иначе
|
||
"""
|
||
if not account_number:
|
||
return False
|
||
|
||
# Паттерн для 7 пар цифр через дефис
|
||
pattern = r'^\d{2}-\d{2}-\d{2}-\d{2}-\d{2}-\d{2}-\d{2}$'
|
||
|
||
return bool(re.match(pattern, account_number))
|
||
|
||
|
||
def format_account_number(account_number: str) -> Optional[str]:
|
||
"""
|
||
Форматирует номер счета, убирая лишние символы
|
||
|
||
Args:
|
||
account_number: Исходный номер счета
|
||
|
||
Returns:
|
||
str: Отформатированный номер счета или None если некорректный
|
||
"""
|
||
if not account_number:
|
||
return None
|
||
|
||
# Убираем все символы кроме цифр
|
||
digits_only = re.sub(r'\D', '', account_number)
|
||
|
||
# Проверяем что осталось ровно 14 цифр
|
||
if len(digits_only) != 14:
|
||
return None
|
||
|
||
# Форматируем как XX-XX-XX-XX-XX-XX-XX
|
||
formatted = '-'.join([digits_only[i:i+2] for i in range(0, 14, 2)])
|
||
|
||
return formatted
|
||
|
||
|
||
def generate_account_number() -> str:
|
||
"""
|
||
Генерирует случайный номер клиентского счета для тестирования
|
||
|
||
Returns:
|
||
str: Сгенерированный номер счета
|
||
"""
|
||
import random
|
||
|
||
# Генерируем 14 случайных цифр
|
||
digits = ''.join([str(random.randint(0, 9)) for _ in range(14)])
|
||
|
||
# Форматируем
|
||
return '-'.join([digits[i:i+2] for i in range(0, 14, 2)])
|
||
|
||
|
||
def mask_account_number(account_number: str, show_last_digits: int = 4) -> str:
|
||
"""
|
||
Маскирует номер счета для безопасного отображения
|
||
|
||
Args:
|
||
account_number: Полный номер счета
|
||
show_last_digits: Количество последних цифр для отображения
|
||
|
||
Returns:
|
||
str: Замаскированный номер счета
|
||
"""
|
||
if not validate_account_number(account_number):
|
||
return "Некорректный номер"
|
||
|
||
if show_last_digits <= 0:
|
||
return "**-**-**-**-**-**-**"
|
||
|
||
# Убираем дефисы для работы с цифрами
|
||
digits = account_number.replace('-', '')
|
||
|
||
# Определяем сколько цифр показать
|
||
show_digits = min(show_last_digits, len(digits))
|
||
|
||
# Создаем маску
|
||
masked_digits = '*' * (len(digits) - show_digits) + digits[-show_digits:]
|
||
|
||
# Возвращаем отформатированный результат (7 пар)
|
||
return '-'.join([masked_digits[i:i+2] for i in range(0, 14, 2)])
|
||
|
||
|
||
def parse_accounts_from_message(text: str) -> List[str]:
|
||
"""
|
||
Извлекает все валидные номера счетов из текста сообщения
|
||
|
||
Args:
|
||
text: Текст сообщения
|
||
|
||
Returns:
|
||
List[str]: Список найденных и отформатированных номеров счетов
|
||
"""
|
||
if not text:
|
||
return []
|
||
|
||
accounts = []
|
||
# Ищем паттерны счетов в тексте (7 пар цифр)
|
||
pattern = r'\b\d{2}[-\s]?\d{2}[-\s]?\d{2}[-\s]?\d{2}[-\s]?\d{2}[-\s]?\d{2}[-\s]?\d{2}\b'
|
||
matches = re.findall(pattern, text)
|
||
|
||
for match in matches:
|
||
formatted = format_account_number(match)
|
||
if formatted and formatted not in accounts:
|
||
accounts.append(formatted)
|
||
|
||
return accounts
|
||
|
||
|
||
def search_accounts_by_pattern(pattern: str, account_list: List[str]) -> List[str]:
|
||
"""
|
||
Ищет счета по частичному совпадению (1-2 пары цифр)
|
||
|
||
Args:
|
||
pattern: Паттерн для поиска (например "11-22" или "11")
|
||
account_list: Список счетов для поиска
|
||
|
||
Returns:
|
||
List[str]: Список найденных счетов
|
||
"""
|
||
if not pattern or not account_list:
|
||
return []
|
||
|
||
# Убираем лишние символы из паттерна
|
||
clean_pattern = re.sub(r'[^\d-]', '', pattern).strip('-')
|
||
|
||
if not clean_pattern:
|
||
return []
|
||
|
||
results = []
|
||
for account in account_list:
|
||
if clean_pattern in account:
|
||
results.append(account)
|
||
|
||
return results |