from kontur_focus.req import Request
from dotenv import load_dotenv
import os
from datetime import datetime
class FocusCompliance(Request):
_basedir = os.path.abspath(os.path.dirname(__file__))
_focus_base_url = None
check_models = [
{
'name': 'corporate',
'description': 'Корпоративный сегмент',
'risk_model_id': 'a9457161-0454-448a-bc2c-83a89cd51b42'
},
{
'name': '115-fz',
'description': '115 ФЗ для некредитных финансовых организаций',
'risk_model_id': '887ee87c-3a43-48d7-a4ad-05c0a64ff53a'
}
]
def __init__(self, inn: str = None, ogrn: str = None):
load_dotenv()
super().__init__(
base_url=os.environ.get('FOCUS_COMPLIANCE_BASE_URL'),
api_key=os.environ.get('FOCUS_COMPLIANCE_ACCESS_KEY'),
inn=inn,
ogrn=ogrn
)
self._focus_base_url = f"/banks/{os.environ.get('FOCUS_COMPLIANCE_BANK_ID')}"
def _save_file(self, filename: str, content, file_type: str = 'pdf', path: str = None) -> dict:
current_datetime = datetime.now().strftime('%d-%m-%Y_%H-%M')
f_name = f'{filename}_{self.inn}_{current_datetime}.{file_type}'
if not path:
file_path = os.path.join(self._basedir, f_name)
else:
file_path = os.path.join(path, f_name)
try:
with open(file_path, mode='wb') as file:
file.write(content)
return {'success': True, 'filename': f_name, 'path': file_path}
except Exception as e:
return {'success': False, 'message': e}
# Компании
def company_is_foreign_agent(self) -> dict:
"""Вхождение организации и ее руководителей в список иностранных агентов
:return: Дата формирования реестра, а также признаки присутствия или отсутствия в списках иностранных агентов
:rtype: dict
"""
response = self.get(path=f'{self._focus_base_url}/companies/lists')
foreign_agent_list = response['foreignAgentList']
company_in_list = []
persons_in_company_in_list = []
for item in foreign_agent_list['uls']:
if item['listItemStatus'] == 'NotInList':
continue
else:
company_in_list.append(item)
for person in foreign_agent_list['fls']:
if person['listItemStatus'] == 'NotInList':
continue
else:
persons_in_company_in_list.append(person)
fal_data = {
'list_date': str(foreign_agent_list['actualListDate']).split('T')[0],
'company_in_list': True if company_in_list else False,
'persons_in_company_in_list': True if persons_in_company_in_list else False
}
return fal_data
def company_in_sanctions_lists(self) -> dict:
"""Вхождение организации и ее руководителей в санкционные списки
:return: Признак присутствия или отсутствия в санкционных списках:\n
.. code-block:: python\n
{'company_in_list': False, 'persons_in_company_in_list': False}
:rtype: dict
"""
response = self.get(path=f'{self._focus_base_url}/companies/lists')
sanctions_list = response['sanctionsList']
company_in_list = []
persons_in_company_in_list = []
for company in sanctions_list['uls']:
if company['listItemStatus'] == 'NotInList':
continue
else:
company_in_list.append(company)
for person in sanctions_list['fls']:
if person['listItemStatus'] == 'NotInList':
continue
else:
persons_in_company_in_list.append(person)
sanctions_lists_data = {
'company_in_list': True if company_in_list else False,
'persons_in_company_in_list': True if persons_in_company_in_list else False
}
return sanctions_lists_data
def search_global_company_profiles_id(self, company_name: str = None, search_accuracy: str = 'Max') -> list:
"""Поиск сводной информации по санкционным профилям ЮЛ
:param company_name: Наименование компании
:type company_name: str
:param search_accuracy: Точность поиска
:type search_accuracy: str
:return: Список идентификаторов профилей
:rtype: list
"""
if self.inn:
query = self.inn
elif company_name:
query = company_name
else:
return {'success': False, 'result': 'Не указан ИНН или наименование контрагента'}
try:
response = self.get(f'{self._focus_base_url}/companies/profiles/search', query=query, searchAccuracy=search_accuracy)
profiles = response['legalEntityProfiles']
if not profiles:
return {'success': True, 'result': profiles}
elif len(profiles) > 1:
return {'success': True, 'result': [profile['id'] for profile in profiles]}
else:
return {'success': True, 'result': [profiles[0]['id']]}
except KeyError:
return {'success': False, 'result': 'Key Error'}
def full_legal_entity_sanctions_profile(self, profile_id_list: list) -> dict:
"""Просмотр полной информации определенного санкционного профиля ЮЛ
:param profile_id_list: Идентификатор санкционного профиля ЮЛ. Идентификатор возвращается в методе
«Поиск сводной информации по санкционным профилям ЮЛ» -
GET /banks/{bankId}/companies/profiles/search
:type profile_id_list: list
:return: Полная информация по профилю ЮЛ
:rtype: dict
"""
if not profile_id_list:
return {'success': False, 'message': 'Не указан список ID профилей'}
else:
try:
profile = profile_id_list[0]
response = self.get(path=f'{self._focus_base_url}/companies/profiles/{profile}')
return {'success': True, 'result': response}
except KeyError:
return {'success': False, 'result': 'Ошибка в ID профиля.'}
def legal_entity_profile_report(self, profile_id_list: list, path: str = None) -> dict:
"""Получение печатного отчета по профилю ЮЛ
:param profile_id_list: Список идентификаторов санкционных профилей компании
:type profile_id_list: list
:param path: Путь сохранения файла, по-умолчанию файл сохраняется в текущий каталог
:type path: str, optional
:return: Отчет о результате сохранения файла
:rtype: dict
"""
if not profile_id_list:
return {'success': False, 'message': 'No profiles is specified'}
elif len(profile_id_list) > 1:
files = []
for profile_id in profile_id_list:
response = self.get(f'{self._focus_base_url}/companies/profiles/{profile_id}/report')
result = self._save_file(
filename=f'Отчет_по_профилю_{profile_id_list[0]}_{profile_id}',
content=response.content,
file_type='docx',
path=path
)
files.append(result)
return {'success': True, 'files': files}
else:
response = self.get(f'{self._focus_base_url}/companies/profiles/{profile_id_list[0]}/report')
result = self._save_file(
filename=f'Отчет_по_профилю_{profile_id_list[0]}',
content=response.content,
file_type='docx',
path=path
)
return {'success': True, 'files': [result]}
def full_company_report(self, model: str = '115-fz', path: str = None) -> dict:
"""Запрос на полную проверку и построение печатного отчёта по организации
:param model: Идентификатор модели, по которой пройдет проверка.
Идентификатор возвращается в методе «Получение списка рисковых моделей организации»
GET /banks/{bankId}/models, defaults to '115-fz'
:type model: str, optional
:param path: Путь сохранения файла, по-умолчанию файл сохраняется в текущий каталог, defaults to None
:type path: str, optional
:return: Отчет о результате сохранения файла
:rtype: dict
"""
if model == '115-fz':
model_id = [d['risk_model_id'] for d in self.check_models if d['name'] == model][0]
else:
model_id = [d['risk_model_id'] for d in self.check_models if d['name'] == 'corporate'][0]
response = self.get(f'{self._focus_base_url}/models/{model_id}/fullCompanyReport')
try:
result = self._save_file(
filename='Полный_отчет',
content=response.content,
file_type='docx',
path=path
)
return {'success': True, 'file': result}
except AttributeError:
return {'success': False, 'result': 'Организация не найдена'}
# Физлица
def person_is_foreign_agent(self):
"""Вхождение физлица в список иностранных агентов
:return: True или False
:rtype: bool
"""
response = self.get(path=f'{self._focus_base_url}/individuals')
fa = response[0]['foreignAgents']
return True if fa else False
def search_global_person_profiles_id(self) -> list:
"""Поиск сводной информации по санкционным/ПДЛ профилям ФЛ
:return: Список идентификаторов профилей
:rtype: list
"""
try:
response = self.get(f'{self._focus_base_url}/individuals/profiles/search', query=self.inn)
return response
except KeyError:
return None
def full_individual_report(self, path: str = None, passport: str = None, fio: str = None) -> dict:
"""Запрос на построение печатного отчёта по физ лицу
Необходимо обязательно указать либо ИНН, либо ФИО и номер паспорта
:param path: Путь сохранения файла, по-умолчанию файл сохраняется в текущий каталог, defaults to None
:type path: str, optional
:param passport: Номер паспорты, defaults to None
:type passport: str, optional
:param fio: ФИО (хотя бы фамилия и имя), defaults to None
:type fio: str, optional
:return: Отчет о результате сохранения файла
:rtype: dict
"""
if self.inn:
response = self.get(path=f'{self._focus_base_url}/formFullIndividualReport')
elif not self.inn and passport and fio:
response = self.get(path=f'{self._focus_base_url}/formFullIndividualReport', passportNumber=passport, fio=fio)
else:
return {'success': False, 'result': 'Необходимо указать: либо ИНН, либо ФИО (хотя бы фамилию и имя) и паспорт'}
try:
if response.status_code == 200:
result = self._save_file(
filename='Полный_отчет',
content=response.content,
file_type='docx',
path=path
)
return {'success': True, 'file': result}
else:
return {'success': False, 'result': 'Ошибка получения отчета. Проверьте корректность ИНН, ФИО или паспортных данных.'}
except AttributeError:
return {'success': False, 'result': 'Ошибка получения отчета. Проверьте корректность ИНН, ФИО или паспортных данных.'}
# Иноагенты
def get_foreign_agents_list(self, fa_type: str = None) -> list: # Не работает, если нет подключенной лицензии
"""Получение списка иноагентов
:param fa_type: Тип иноагента (i - физ. лица, l - юридические лица), если не указано, выгружаются все типы, defaults to None
:type fa_type: str, optional
:return: Список данных по иноагентам
:rtype: list
"""
response = self.get(path=f'{self._focus_base_url}/foreign-agents')
result = None
if fa_type == 'i':
individuals = response['individuals']
result = individuals
elif fa_type == 'l':
legal_entities = response['legalEntities']
result = legal_entities
else:
result = [response]
return result