Files
kyc/src/application/services/kyc_personal_data.py
2026-05-12 00:26:21 +03:00

88 lines
3.2 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
from __future__ import annotations
from datetime import date,datetime
from typing import Any
from src.application.domain.dto import KycPersonalData
from src.application.domain.exceptions import ApplicationException
FIELD_ALIASES = {
'full_name': {'full_name','fullname','fio','фио'},
'first_name': {'first_name','firstname','name','given_name','givenname','имя'},
'last_name': {'last_name','lastname','surname','family_name','familyname','фамилия'},
'middle_name': {'middle_name','middlename','patronymic','отчество'},
'birth_date': {'birth_date','birthdate','date_birth','datebirth','birthday','дата_рождения'},
'inn': {'inn','tax_id','taxid','инн'},
}
def extract_personal_data(data: Any) -> KycPersonalData:
values: dict[str,str] = {}
for key,value in _walk(data):
normalized = _normalize_key(key)
for field,aliases in FIELD_ALIASES.items():
if field not in values and normalized in aliases and value not in (None,''):
values[field] = str(value).strip()
if values.get('full_name') and (not values.get('first_name') or not values.get('last_name')):
parts = values['full_name'].split()
if len(parts) >= 2:
values.setdefault('last_name',parts[0])
values.setdefault('first_name',parts[1])
if len(parts) >= 3:
values.setdefault('middle_name',' '.join(parts[2:]))
missing = [field for field in ('first_name','last_name','birth_date') if not values.get(field)]
if missing:
raise ApplicationException(status_code=422,message='KYC personal data is incomplete')
return KycPersonalData(
first_name=values['first_name'],
last_name=values['last_name'],
middle_name=values.get('middle_name'),
birth_date=str(_parse_date(values['birth_date'])),
inn=values.get('inn'),
)
def ensure_adult(birth_date: date) -> None:
today = date.today()
try:
adult_from = date(today.year - 18,today.month,today.day)
except ValueError:
adult_from = date(today.year - 18,2,28)
if birth_date > adult_from:
raise ApplicationException(status_code=403,message='KYC is unavailable for users under 18')
def parse_birth_date(value: str) -> date:
return _parse_date(value)
def _walk(data: Any) -> list[tuple[str,Any]]:
items: list[tuple[str,Any]] = []
if isinstance(data,dict):
for key,value in data.items():
if isinstance(value,dict | list):
items.extend(_walk(value))
else:
items.append((str(key),value))
elif isinstance(data,list):
for item in data:
items.extend(_walk(item))
return items
def _normalize_key(key: str) -> str:
return key.strip().lower().replace('-','_').replace(' ','_')
def _parse_date(value: str) -> date:
clean = value.strip()
formats = ('%Y-%m-%d','%d.%m.%Y','%d-%m-%Y','%d/%m/%Y','%Y.%m.%d')
for date_format in formats:
try:
return datetime.strptime(clean,date_format).date()
except ValueError:
continue
raise ApplicationException(status_code=422,message='KYC birth date has invalid format')