Патч
This commit is contained in:
@ -1,3 +1,4 @@
|
||||
from .aemd.api import AEMD_API
|
||||
from .esia.api import ESIA_API
|
||||
from .tdn.api import TDN_API
|
||||
from .vitacore.api import VITACORE_API
|
||||
@ -7,6 +8,7 @@ class ClientsObject:
|
||||
_esia_api = None
|
||||
_vitacore_api = None
|
||||
_tdn_api = None
|
||||
_aemd_api = None
|
||||
|
||||
@property
|
||||
def esia_api(self):
|
||||
@ -29,5 +31,12 @@ class ClientsObject:
|
||||
|
||||
return self._tdn_api
|
||||
|
||||
@property
|
||||
def aemd_api(self):
|
||||
if not self._aemd_api:
|
||||
self._aemd_api = AEMD_API()
|
||||
|
||||
return self._aemd_api
|
||||
|
||||
|
||||
clients = ClientsObject()
|
||||
|
||||
0
src/clients/aemd/__init__.py
Normal file
0
src/clients/aemd/__init__.py
Normal file
46
src/clients/aemd/api.py
Normal file
46
src/clients/aemd/api.py
Normal file
@ -0,0 +1,46 @@
|
||||
from logging import getLogger
|
||||
|
||||
from httpx import AsyncClient
|
||||
|
||||
from core.config import settings
|
||||
|
||||
|
||||
class AEMD_API(AsyncClient):
|
||||
def __init__(self):
|
||||
self.logger = getLogger(__name__)
|
||||
super().__init__(
|
||||
base_url=settings.AEMD_BASE_URL,
|
||||
headers={'Content-Type': 'application/soap+xml'},
|
||||
)
|
||||
|
||||
def get_envelope(self, endpoint: str, body: str):
|
||||
return (
|
||||
'<?xml version="1.0" encoding="utf-8"?>'
|
||||
'<s:Envelope xmlns:s= "http://www.w3.org/2003/05/soap-envelope" '
|
||||
'xmlns:a= "http://www.w3.org/2005/08/addressing">'
|
||||
'<s:Header>'
|
||||
f'<a:Action s:mustUnderstand="1">{endpoint}</a:Action>'
|
||||
'<h:transportHeader xmlns:h="http://egisz.rosminzdrav.ru" '
|
||||
'xmlns="http://egisz.rosminzdrav.ru" '
|
||||
'xmlns:xsd="http://www.w3.org/2001/XMLSchema" '
|
||||
'xmlns:xsi= "http://www.w3.org/2001/XMLSchema-instance">'
|
||||
'<authInfo>'
|
||||
f'<clientEntityId>{settings.AEMD_TOKEN}</clientEntityId>'
|
||||
'</authInfo>'
|
||||
'</h:transportHeader>'
|
||||
'<a:To s:mustUnderstand= "1">http://gist-sdw.ezdrav.ru:8708/EMDAService</a:To>'
|
||||
'</s:Header>'
|
||||
'<s:Body xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">'
|
||||
f'{body}'
|
||||
'</s:Body>'
|
||||
'</s:Envelope>'
|
||||
)
|
||||
|
||||
async def searchRegistryItem(self, patient_snils: str):
|
||||
envelope = self.get_envelope(
|
||||
'searchRegistryItem',
|
||||
f'<searchRegistryItemRequest xmlns="http://egisz.rosminzdrav.ru/iehr/emdr/service/"><patientSnils>{patient_snils}</patientSnils></searchRegistryItemRequest>',
|
||||
)
|
||||
req = await self.post('/', content=envelope)
|
||||
|
||||
return req.text
|
||||
@ -33,7 +33,7 @@ class IDTokenModel(BaseModel):
|
||||
exp: int
|
||||
iat: int
|
||||
iss: str
|
||||
acr: IDTokenACRModel
|
||||
# acr: IDTokenACRModel
|
||||
urn_esia_amd: str = Field(alias='urn:esia:amd')
|
||||
urn_esia_sid: str = Field(alias='urn:esia:sid')
|
||||
urn_esia_sbj: IDTokenSBJModel = Field(alias='urn:esia:sbj')
|
||||
@ -44,10 +44,10 @@ class UserInfoModel(BaseModel):
|
||||
firstName: str
|
||||
lastName: str
|
||||
middleName: str
|
||||
birthDate: str
|
||||
gender: str
|
||||
# birthDate: str
|
||||
# gender: str
|
||||
trusted: bool
|
||||
citizenship: str
|
||||
# citizenship: str
|
||||
snils: str
|
||||
inn: int
|
||||
updatedOn: int
|
||||
|
||||
@ -1,10 +1,12 @@
|
||||
from datetime import UTC, datetime
|
||||
from logging import getLogger
|
||||
|
||||
from fastapi import status as st
|
||||
from httpx import AsyncClient
|
||||
from httpx import AsyncClient, BasicAuth
|
||||
|
||||
from core.config import settings
|
||||
from shared import exceptions as e
|
||||
from shared.redis import client as cache
|
||||
|
||||
from . import schema as s
|
||||
|
||||
@ -14,11 +16,56 @@ class VITACORE_API(AsyncClient):
|
||||
self.logger = getLogger(__name__)
|
||||
super().__init__(base_url=settings.VITACORE_BASE_URL)
|
||||
|
||||
async def get_token(self):
|
||||
token = cache.get('vitacore_token')
|
||||
|
||||
if token is None:
|
||||
token = await self.login()
|
||||
cache.set('vitacore_token', token, 10800)
|
||||
|
||||
else:
|
||||
token = token.decode()
|
||||
|
||||
return token
|
||||
|
||||
async def login(self):
|
||||
req = await self.post(
|
||||
'/auth',
|
||||
auth=BasicAuth(
|
||||
settings.VITACORE_USERNAME, settings.VITACORE_PASSWORD
|
||||
),
|
||||
)
|
||||
|
||||
match req.status_code:
|
||||
case st.HTTP_200_OK:
|
||||
return req.text
|
||||
|
||||
case _:
|
||||
self.logger.error(req.text)
|
||||
raise e.UnknownException
|
||||
|
||||
async def findBySnils(self, snils: str):
|
||||
return
|
||||
token = await self.get_token()
|
||||
req = await self.get(
|
||||
'/findBySnils',
|
||||
params={'snils': snils},
|
||||
headers={'Authorization': f'Bearer {token}'},
|
||||
)
|
||||
|
||||
match req.status_code:
|
||||
case st.HTTP_200_OK:
|
||||
return s.PatientsModel.model_validate(req.json())
|
||||
case _:
|
||||
self.logger.error(req.json())
|
||||
raise e.UnknownException
|
||||
|
||||
async def getProfile(self, patId: str):
|
||||
req = await self.get('/getProfile', params={'patId': patId})
|
||||
token = await self.get_token()
|
||||
req = await self.get(
|
||||
'/getProfile',
|
||||
params={'patId': patId},
|
||||
headers={'Authorization': f'Bearer {token}'},
|
||||
)
|
||||
|
||||
match req.status_code:
|
||||
case st.HTTP_200_OK:
|
||||
@ -28,18 +75,24 @@ class VITACORE_API(AsyncClient):
|
||||
raise e.UnknownException
|
||||
|
||||
async def getDepartments(self):
|
||||
req = await self.get('/getDepartments')
|
||||
token = await self.get_token()
|
||||
req = await self.get(
|
||||
'/getDepartments', headers={'Authorization': f'Bearer {token}'}
|
||||
)
|
||||
|
||||
match req.status_code:
|
||||
case st.HTTP_200_OK:
|
||||
return s.OrganizationsModel.model_validate(req.json())
|
||||
case _:
|
||||
self.logger.error(req.json())
|
||||
self.logger.error(req.text)
|
||||
raise e.UnknownException
|
||||
|
||||
async def getWorkers(self, departmentId: str):
|
||||
token = await self.get_token()
|
||||
req = await self.get(
|
||||
'/getWorkers', params={'departmentId': departmentId}
|
||||
'/getWorkers',
|
||||
params={'departmentId': departmentId},
|
||||
headers={'Authorization': f'Bearer {token}'},
|
||||
)
|
||||
|
||||
match req.status_code:
|
||||
@ -50,7 +103,10 @@ class VITACORE_API(AsyncClient):
|
||||
raise e.UnknownException
|
||||
|
||||
async def getSpecsV021(self):
|
||||
req = await self.get('/getSpecsV021')
|
||||
token = await self.get_token()
|
||||
req = await self.get(
|
||||
'/getSpecsV021', headers={'Authorization': f'Bearer {token}'}
|
||||
)
|
||||
|
||||
match req.status_code:
|
||||
case st.HTTP_200_OK:
|
||||
@ -60,7 +116,13 @@ class VITACORE_API(AsyncClient):
|
||||
raise e.UnknownException
|
||||
|
||||
async def getEntries(self, patId: str):
|
||||
req = await self.get('/getEntries', params={'patId': patId})
|
||||
token = await self.get_token()
|
||||
patId = 'b66a85f1-4aaa-4db8-942a-2de44341824e'
|
||||
req = await self.get(
|
||||
'/getEntries',
|
||||
params={'patId': patId},
|
||||
headers={'Authorization': f'Bearer {token}'},
|
||||
)
|
||||
|
||||
match req.status_code:
|
||||
case st.HTTP_200_OK:
|
||||
@ -76,17 +138,31 @@ class VITACORE_API(AsyncClient):
|
||||
raise e.UnknownException
|
||||
|
||||
async def getVaccsReport(self, patId: str):
|
||||
req = await self.get('/getVaccsReport', params={'patId': patId})
|
||||
token = await self.get_token()
|
||||
patId = 'b66a85f1-4aaa-4db8-942a-2de44341824e'
|
||||
req = await self.get(
|
||||
'/getVaccsReport',
|
||||
params={'patId': patId},
|
||||
headers={'Authorization': f'Bearer {token}'},
|
||||
)
|
||||
|
||||
match req.status_code:
|
||||
case st.HTTP_200_OK:
|
||||
return s.VaccsReportModel.model_validate(req.json())
|
||||
case st.HTTP_206_PARTIAL_CONTENT:
|
||||
error = s.ErrorModel.model_validate(req.json())
|
||||
|
||||
if error.error == 'Не найдены записи по указанному patId':
|
||||
return s.VaccsReportModel(content='')
|
||||
case _:
|
||||
self.logger.error(req.json())
|
||||
raise e.UnknownException
|
||||
|
||||
async def getMedExamDict(self):
|
||||
req = await self.get('/getMedExamDict')
|
||||
token = await self.get_token()
|
||||
req = await self.get(
|
||||
'/getMedExamDict', headers={'Authorization': f'Bearer {token}'}
|
||||
)
|
||||
|
||||
match req.status_code:
|
||||
case st.HTTP_200_OK:
|
||||
@ -96,19 +172,39 @@ class VITACORE_API(AsyncClient):
|
||||
raise e.UnknownException
|
||||
|
||||
async def getRoutesList(self, patId: str):
|
||||
req = await self.get('/getRoutesList', params={'patId': patId})
|
||||
token = await self.get_token()
|
||||
patId = 'b66a85f1-4aaa-4db8-942a-2de44341824e'
|
||||
req = await self.get(
|
||||
'/getRoutesList',
|
||||
params={'patId': patId},
|
||||
headers={'Authorization': f'Bearer {token}'},
|
||||
)
|
||||
|
||||
match req.status_code:
|
||||
case st.HTTP_200_OK:
|
||||
return s.RoutesListModel.model_validate(req.json())
|
||||
|
||||
case st.HTTP_206_PARTIAL_CONTENT:
|
||||
error = s.ErrorModel.model_validate(req.json())
|
||||
|
||||
if error.error == 'Не найдены случаи по указанному patId':
|
||||
return s.RoutesListModel(
|
||||
EventID='none',
|
||||
EventDate=datetime.now(UTC),
|
||||
LpuName='fakeName',
|
||||
Routes=[],
|
||||
)
|
||||
|
||||
case _:
|
||||
self.logger.error(req.json())
|
||||
raise e.UnknownException
|
||||
|
||||
async def getHospExaminations(self, patId: str, examId: str):
|
||||
token = await self.get_token()
|
||||
req = await self.get(
|
||||
'/getHospExaminations',
|
||||
params={'patId': patId, 'examId': examId},
|
||||
headers={'Authorization': f'Bearer {token}'},
|
||||
)
|
||||
|
||||
match req.status_code:
|
||||
@ -119,49 +215,123 @@ class VITACORE_API(AsyncClient):
|
||||
raise e.UnknownException
|
||||
|
||||
async def getCurrHosp(self, patId: str):
|
||||
req = await self.get('/getCurrHosp', params={'patId': patId})
|
||||
token = await self.get_token()
|
||||
patId = 'b66a85f1-4aaa-4db8-942a-2de44341824e'
|
||||
req = await self.get(
|
||||
'/getCurrHosp',
|
||||
params={'patId': patId},
|
||||
headers={'Authorization': f'Bearer {token}'},
|
||||
)
|
||||
|
||||
match req.status_code:
|
||||
case st.HTTP_200_OK:
|
||||
return s.CurHospitalizationsModel.model_validate(req.json())
|
||||
|
||||
case st.HTTP_206_PARTIAL_CONTENT:
|
||||
error = s.ErrorModel.model_validate(req.json())
|
||||
|
||||
if error.error == 'Пациент не госпитализирован!':
|
||||
return s.CurHospitalizationsModel(
|
||||
Hospitalizations=[],
|
||||
)
|
||||
|
||||
case _:
|
||||
self.logger.error(req.json())
|
||||
raise e.UnknownException
|
||||
|
||||
async def getHosps(self, patId: str):
|
||||
req = await self.get('/getHosps', params={'patId': patId})
|
||||
token = await self.get_token()
|
||||
patId = 'b66a85f1-4aaa-4db8-942a-2de44341824e'
|
||||
req = await self.get(
|
||||
'/getHosps',
|
||||
params={'patId': patId},
|
||||
headers={'Authorization': f'Bearer {token}'},
|
||||
)
|
||||
|
||||
match req.status_code:
|
||||
case st.HTTP_200_OK:
|
||||
return s.HospitalizationsModel.model_validate(req.json())
|
||||
|
||||
case st.HTTP_206_PARTIAL_CONTENT:
|
||||
error = s.ErrorModel.model_validate(req.json())
|
||||
|
||||
if (
|
||||
error.error
|
||||
== 'Не найдены госпитализации по указанному patId'
|
||||
):
|
||||
return s.HospitalizationsModel(
|
||||
Hospitalizations=[],
|
||||
)
|
||||
|
||||
case _:
|
||||
self.logger.error(req.json())
|
||||
raise e.UnknownException
|
||||
|
||||
async def getHospRecommendations(self, patId: str):
|
||||
token = await self.get_token()
|
||||
patId = 'b66a85f1-4aaa-4db8-942a-2de44341824e'
|
||||
req = await self.get(
|
||||
'/getHospRecommendations', params={'patId': patId}
|
||||
'/getHospRecommendations',
|
||||
params={'patId': patId},
|
||||
headers={'Authorization': f'Bearer {token}'},
|
||||
)
|
||||
|
||||
match req.status_code:
|
||||
case st.HTTP_200_OK:
|
||||
return s.HospRecommendationsModel.model_validate(req.json())
|
||||
|
||||
case st.HTTP_206_PARTIAL_CONTENT:
|
||||
error = s.ErrorModel.model_validate(req.json())
|
||||
|
||||
if (
|
||||
error.error
|
||||
== 'Не найдены госпитализации по указанному patId'
|
||||
):
|
||||
return s.HospRecommendationsModel(
|
||||
EventID='none',
|
||||
EventDate=datetime.now(UTC),
|
||||
Recommendations=[],
|
||||
)
|
||||
|
||||
case _:
|
||||
self.logger.error(req.json())
|
||||
raise e.UnknownException
|
||||
|
||||
async def getHospRoutes(self, patId: str):
|
||||
req = await self.get('/getHospRoutes', params={'patId': patId})
|
||||
token = await self.get_token()
|
||||
patId = 'b66a85f1-4aaa-4db8-942a-2de44341824e'
|
||||
req = await self.get(
|
||||
'/getHospRoutes',
|
||||
params={'patId': patId},
|
||||
headers={'Authorization': f'Bearer {token}'},
|
||||
)
|
||||
|
||||
match req.status_code:
|
||||
case st.HTTP_200_OK:
|
||||
return s.HospRoutesModel.model_validate(req.json())
|
||||
|
||||
case st.HTTP_206_PARTIAL_CONTENT:
|
||||
error = s.ErrorModel.model_validate(req.json())
|
||||
|
||||
if error.error == 'Пациент не госпитализирован!':
|
||||
return s.HospRoutesModel(
|
||||
EventID='none',
|
||||
EventDate=datetime.now(UTC),
|
||||
RoutesToDoctor=[],
|
||||
RoutesToDiagnostic=[],
|
||||
)
|
||||
|
||||
case _:
|
||||
self.logger.error(req.json())
|
||||
raise e.UnknownException
|
||||
|
||||
async def getDiagnosticResults(self, patId: str):
|
||||
req = await self.get('/getDiagnosticResults', params={'patId': patId})
|
||||
token = await self.get_token()
|
||||
req = await self.get(
|
||||
'/getDiagnosticResults',
|
||||
params={'patId': patId},
|
||||
headers={'Authorization': f'Bearer {token}'},
|
||||
)
|
||||
|
||||
match req.status_code:
|
||||
case st.HTTP_200_OK:
|
||||
@ -171,7 +341,12 @@ class VITACORE_API(AsyncClient):
|
||||
raise e.UnknownException
|
||||
|
||||
async def getELNs(self, patId: str):
|
||||
req = await self.get('/getELNs', params={'patId': patId})
|
||||
token = await self.get_token()
|
||||
req = await self.get(
|
||||
'/getELNs',
|
||||
params={'patId': patId},
|
||||
headers={'Authorization': f'Bearer {token}'},
|
||||
)
|
||||
|
||||
match req.status_code:
|
||||
case st.HTTP_200_OK:
|
||||
@ -181,7 +356,12 @@ class VITACORE_API(AsyncClient):
|
||||
raise e.UnknownException
|
||||
|
||||
async def getPatFLG(self, patId: str):
|
||||
req = await self.get('/getPatFLG', params={'patId': patId})
|
||||
token = await self.get_token()
|
||||
req = await self.get(
|
||||
'/getPatFLG',
|
||||
params={'patId': patId},
|
||||
headers={'Authorization': f'Bearer {token}'},
|
||||
)
|
||||
|
||||
match req.status_code:
|
||||
case st.HTTP_200_OK:
|
||||
|
||||
@ -7,6 +7,31 @@ class ErrorModel(BaseModel):
|
||||
error: str = Field(title='Текст ошибки')
|
||||
|
||||
|
||||
class PatientModel(BaseModel):
|
||||
id: str = Field(
|
||||
title='Идентификатор пациента',
|
||||
examples=['b62e9f22-a871-4c52-96d6-559c707a716d'],
|
||||
)
|
||||
SNILS: str = Field(title='СНИЛС', examples=['000-000-600 18'])
|
||||
lastName: str = Field(title='Фамилия', examples=['Тестовый'])
|
||||
firstName: str = Field(title='Имя', examples=['Пациент'])
|
||||
middleName: str = Field(title='Отчество', examples=['Пациентович'])
|
||||
birthDate: datetime = Field(title='Дата рождения', examples=['2024-10-16'])
|
||||
gender: str = Field(title='Пол', examples=['М'])
|
||||
docType: str = Field(title='Тип документа', examples=['Паспорт РФ'])
|
||||
docSer: str = Field(title='Серия документа', examples=['12 34'])
|
||||
docNum: str = Field(title='Номер документа', examples=['999999'])
|
||||
polNum: str = Field(title='Номер полиса', examples=['999999'])
|
||||
address1: str = Field(
|
||||
title='Адрес проживания',
|
||||
examples=['г. Москва, ул. Пушкина, д. 1'],
|
||||
)
|
||||
|
||||
|
||||
class PatientsModel(BaseModel):
|
||||
patients: list[PatientModel]
|
||||
|
||||
|
||||
class TrustedPersonModel(BaseModel):
|
||||
parentSnils: str = Field(
|
||||
title='СНИЛС представителя', examples=['156-125-394 57']
|
||||
@ -66,7 +91,7 @@ class ProfileModel(BaseModel):
|
||||
# examples=['99'],
|
||||
# )
|
||||
trustedPersons: list[TrustedPersonModel] = Field(
|
||||
title='Информация о представителе',
|
||||
title='Информация о представителе', default=[]
|
||||
)
|
||||
|
||||
|
||||
@ -79,10 +104,10 @@ class DepartmentAddressModel(BaseModel):
|
||||
title='Адрес строкой',
|
||||
examples=['420097, г.Казань, ул.Заслонова, д.5'],
|
||||
)
|
||||
latitude: float | None = Field(
|
||||
latitude: str | None = Field(
|
||||
title='Широта, при наличии', examples=[55.789], default=None
|
||||
)
|
||||
longitude: float | None = Field(
|
||||
longitude: str | None = Field(
|
||||
title='Долгота, при наличии', examples=[37.789], default=None
|
||||
)
|
||||
|
||||
@ -92,16 +117,19 @@ class DepartmentModel(BaseModel):
|
||||
title='Идентификатор МО/Филиала',
|
||||
examples=['a3677271-3385-4f27-a65d-c3430b7c61c2'],
|
||||
)
|
||||
OID: str = Field(
|
||||
title='OID МО / Филиала', examples=['1.2.643.5.1.13.13.12.2.16.1084']
|
||||
OID: str | None = Field(
|
||||
title='OID МО / Филиала',
|
||||
examples=['1.2.643.5.1.13.13.12.2.16.1084'],
|
||||
default=None,
|
||||
)
|
||||
parentId: str | None = Field(
|
||||
title='Идентификатор вышестоящего подразделения',
|
||||
examples=['a3677271-3385-4f27-a65d-c3430b7c61c2'],
|
||||
)
|
||||
fullname: str = Field(
|
||||
fullname: str | None = Field(
|
||||
title='Полное наименование',
|
||||
examples=['ГБУЗС "Тестовая медицинская организация"'],
|
||||
default=None,
|
||||
)
|
||||
shortname: str = Field(
|
||||
title='Краткое наименование',
|
||||
@ -112,14 +140,12 @@ class DepartmentModel(BaseModel):
|
||||
', для филиалов: Стационар / Поликлиника / ФАП / Амбулатория)',
|
||||
examples=['Юридическое лицо'],
|
||||
)
|
||||
inn: str = Field(title='ИНН', examples=['0000000000'])
|
||||
ogrn: str = Field(title='ОГРН', examples=['1149204047816'])
|
||||
inn: str | None = Field(title='ИНН', examples=['0000000000'], default=None)
|
||||
ogrn: str | None = Field(
|
||||
title='ОГРН', examples=['1149204047816'], default=None
|
||||
)
|
||||
kpp: str | None = Field(title='КПП', examples=['0000000000'], default=None)
|
||||
address: list[DepartmentAddressModel]
|
||||
# code: str = Field(
|
||||
# title='Региональный код или код ТФОМС',
|
||||
# examples=['0000000000'],
|
||||
# )
|
||||
address: list[DepartmentAddressModel] | None = None
|
||||
|
||||
|
||||
class OrganizationsModel(BaseModel):
|
||||
@ -642,7 +668,7 @@ class PatientFLGModel(BaseModel):
|
||||
title='Дата следующего флюорографического осмотра',
|
||||
examples=['2021-09-24'],
|
||||
)
|
||||
PrgContingent: str = Field(
|
||||
PrgContingent: str | None = Field(
|
||||
title='Контингент (флюорография)',
|
||||
examples=['Неорганизованное население'],
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user