Files
ACORE/core/utils/validators.py
T
lokses 131cb27d16 Initial commit — ACORE pharmacy network management system
Django project: employees, locations, visit_manager, it_manager,
mattermost_connector and stub connectors (ad, mail, portal).
2026-05-31 14:21:47 +03:00

180 lines
6.5 KiB
Python

import re, ipaddress
from django.core.exceptions import ValidationError
from datetime import date
from django.core.validators import EmailValidator
from django.utils.translation import gettext_lazy as _
def validate_ukrainian_phone(value: str) -> None:
"""Валидация украинских номеров телефона"""
pattern = r'^\+380\d{9}$'
if not re.match(pattern, value):
raise ValidationError(
_('Номер телефона должен быть в формате +380XXXXXXXXX'),
code='invalid_phone'
)
def validate_international_phone(value: str) -> None:
"""Валидация международных номеров телефона"""
pattern = r'^\+\d{1,15}$'
if not re.match(pattern, value):
raise ValidationError(
_('Номер телефона должен быть в международном формате +XXXXXXXXXXX'),
code='invalid_phone'
)
if len(value) < 8 or len(value) > 16:
raise ValidationError(
_('Номер телефона должен содержать от 8 до 16 цифр включая код страны'),
code='invalid_phone_length'
)
# Класс-валидатор с параметрами
class PhoneValidator:
def __init__(self, country_code='UA'):
self.country_code = country_code
def __call__(self, value):
if self.country_code == 'UA':
return validate_ukrainian_phone(value)
else:
return validate_international_phone(value)
def validate_birth_date(value: date) -> None:
"""Валидация даты рождения"""
if value > date.today():
raise ValidationError(
_('Дата рождения не может быть в будущем'),
code='invalid_birth_date'
)
# Проверка минимального возраста (18 лет)
min_date = date.today().replace(year=date.today().year - 18)
if value > min_date:
raise ValidationError(
_('Возраст должен быть не менее 18 лет'),
code='underage'
)
def get_email_validator(banned_domains=None):
def validator(value):
validate_email_domain(value, banned_domains)
return validator
def validate_email_domain(value: str, banned_domains: list = None) -> None:
"""
Проверка домена email с возможностью кастомизации
Args:
value: Email для проверки
banned_domains: Список запрещенных доменов
"""
EmailValidator()(value)
domain = value.split('@')[-1].lower()
# Дефолтный список запрещенных доменов
default_banned = ['temp-mail.org', '10minutemail.com', 'example.com',
'yopmail.com', 'mailinator.com']
banned_list = banned_domains if banned_domains is not None else default_banned
if domain in banned_list:
raise ValidationError(
_('Использование временных email запрещено'),
code='invalid_email_domain'
)
def validate_ip_address(value: str) -> None:
try:
ipaddress.ip_address(value)
except ValueError:
raise ValidationError(
_('Недопустимый IP адрес: %(value)s') % {'value': value},
code='invalid_ip'
)
def validate_mac_address(value: str) -> None:
pattern = r'^([0-9A-Fa-f]{2}[:-]){5}([0-9A-Fa-f]{2})$'
if not re.match(pattern, value):
raise ValidationError(
_('MAC адрес должен быть в формате XX:XX:XX:XX:XX:XX или XX-XX-XX-XX-XX-XX'),
code='invalid_mac'
)
def validate_ukrainian_tax_number(value: str) -> None:
"""Валидация украинского идентификационного кода (налогового номера)"""
pattern = r'^\d{10}$'
if not re.match(pattern, value):
raise ValidationError(
_('Украинский налоговый номер должен содержать 10 цифр'),
code='invalid_tax_number_length'
)
# Коэффициенты для украинского алгоритма
coefficients = [-1, 5, 7, 9, 4, 6, 10, 5, 7]
total = sum(int(value[i]) * coefficients[i] for i in range(9))
remainder = total % 11
if remainder < 2:
checksum = 0
elif remainder >= 10:
checksum = remainder - 10
else:
checksum = remainder
if int(value[9]) != checksum:
raise ValidationError(
_('Неверная контрольная сумма украинского налогового номера'),
code='invalid_tax_number_checksum'
)
def validate_inn(value: str) -> None:
"""Валидация ИНН (10 или 12 цифр)"""
pattern = r'^\d{10,12}$'
if not re.match(pattern, value):
raise ValidationError(
_('ИНН должен содержать 10 или 12 цифр'),
code='invalid_inn_length'
)
# Проверка контрольных сумм
if len(value) == 10:
_validate_inn_10(value)
elif len(value) == 12:
_validate_inn_12(value)
def _validate_inn_10(value: str) -> None:
"""Проверка контрольной цифры для 10-значного ИНН"""
coefficients = [2, 4, 10, 3, 5, 9, 4, 6, 8]
total = sum(int(value[i]) * coefficients[i] for i in range(9))
checksum = total % 11 % 10
if int(value[9]) != checksum:
raise ValidationError(
_('Неверная контрольная сумма ИНН'),
code='invalid_inn_checksum'
)
def _validate_inn_12(value: str) -> None:
"""Проверка контрольных цифр для 12-значного ИНН"""
coefficients1 = [7, 2, 4, 10, 3, 5, 9, 4, 6, 8]
coefficients2 = [3, 7, 2, 4, 10, 3, 5, 9, 4, 6, 8]
total1 = sum(int(value[i]) * coefficients1[i] for i in range(10))
checksum1 = total1 % 11 % 10
total2 = sum(int(value[i]) * coefficients2[i] for i in range(11))
checksum2 = total2 % 11 % 10
if int(value[10]) != checksum1 or int(value[11]) != checksum2:
raise ValidationError(
_('Неверная контрольная сумма ИНН'),
code='invalid_inn_checksum'
)