Патч
Some checks failed
Build And Push / publish (push) Failing after 1m56s

This commit is contained in:
2025-10-05 10:51:39 +03:00
parent 848d314718
commit ebd4d14508
10 changed files with 238 additions and 6 deletions

0
src/apps/tdn/__init__.py Normal file
View File

15
src/apps/tdn/auth.py Normal file
View File

@ -0,0 +1,15 @@
from clients import clients as c
from shared.redis import client as cache
async def token():
access_token = cache.get('tdn_token')
if access_token is None:
tokens = await c.tdn_api.signin()
cache.set('tdn_token', tokens.accessToken, 60)
return tokens.accessToken
else:
return access_token.decode()

View File

@ -17,4 +17,4 @@ async def login(
if is_exist is None: if is_exist is None:
raise e.UnauthorizedException raise e.UnauthorizedException
return True return is_exist.decode()

View File

@ -59,7 +59,7 @@ async def get_entries():
Get list of entries for user by id. Get list of entries for user by id.
""" """
return await c.vitacore_api.getEntries( return await c.vitacore_api.getEntries(
'b172ddc1-bd94-407f-885f-725193dcc502' '6c7978f0-c573-4ccf-8c6e-f0cd9aceb1e1'
) )
@ -170,6 +170,24 @@ async def get_pat_flg():
) )
# @router.post('/measurement', status_code=status.HTTP_202_ACCEPTED)
# async def measurement(tdn_access_token: Annotated[str, Depends(token)]):
# patientId = '6debe050-b57e-442b-9b0e-8d304ca382b0'
# observations = await c.tdn_api.observations_search(
# tdn_access_token, patientId
# )
# if observations.total == 0:
# raise e.NotFoundException(detail='No observations found')
# observation = observations.items[-1]
# observation_measurements = await c.tdn_api.observations_measurement_search(
# tdn_access_token, observation.uid
# )
# return observation_measurements
@router.post('/measurement', status_code=status.HTTP_202_ACCEPTED) @router.post('/measurement', status_code=status.HTTP_202_ACCEPTED)
async def measurement( async def measurement(
user: Annotated[str, Depends(login)], user: Annotated[str, Depends(login)],

View File

@ -1,10 +1,12 @@
from .esia.api import ESIA_API from .esia.api import ESIA_API
from .tdn.api import TDN_API
from .vitacore.api import VITACORE_API from .vitacore.api import VITACORE_API
class ClientsObject: class ClientsObject:
_esia_api = None _esia_api = None
_vitacore_api = None _vitacore_api = None
_tdn_api = None
@property @property
def esia_api(self): def esia_api(self):
@ -20,5 +22,12 @@ class ClientsObject:
return self._vitacore_api return self._vitacore_api
@property
def tdn_api(self):
if not self._tdn_api:
self._tdn_api = TDN_API()
return self._tdn_api
clients = ClientsObject() clients = ClientsObject()

View File

106
src/clients/tdn/api.py Normal file
View File

@ -0,0 +1,106 @@
from json import dumps
from logging import getLogger
from urllib.parse import quote, urlencode
from fastapi import status as st
from httpx import AsyncClient
from core.config import settings
from shared import exceptions as e
from . import schema as s
class TDN_API(AsyncClient):
def __init__(self):
self.logger = getLogger(__name__)
super().__init__(
base_url=settings.TDN_BASE_URL,
headers={
'Content-Type': 'application/json',
},
)
async def signin(self):
data = {
'username': settings.TDN_LOGIN,
'password': settings.TDN_PASSWORD,
}
res = await self.post('/core/auth/signin', json=data)
match res.status_code:
case st.HTTP_200_OK:
return s.SignInModel.model_validate(res.json())
case _:
self.logger.error(res.json())
raise e.UnknownException
async def patient_search(self, access_token: str, vitaId: str):
data = quote(dumps({'vitaId': vitaId}))
_ = await self.get(
'/ddn/patient/search',
params={'query': data},
headers={'Authorization': f'Bearer {access_token}'},
)
async def observations_search(self, access_token: str, patientUid: str):
data = quote(dumps({'where': {'patientUid': patientUid}}))
res = await self.get(
'/ddn/observations/search',
params={'query': data},
headers={'Authorization': f'Bearer {access_token}'},
)
match res.status_code:
case st.HTTP_200_OK:
return s.ObservationsModel.model_validate(res.json())
case _:
self.logger.error(res.json())
raise e.UnknownException
async def observations_measurement_search(
self, access_token: str, observationUid: str
):
# data = urlencode(
# dumps(
# {
# 'where': {'observationUid': observationUid},
# 'relations': [
# 'measurement',
# 'obsrvMtMetrics',
# 'obsrvMtMetrics.metric',
# ],
# }
# )
# )
encoded_query = urlencode(
{
'query': dumps(
{
'where': {'observationUid': observationUid},
'relations': [
'measurement',
'obsrvMtMetrics',
'obsrvMtMetrics.metric',
],
}
)
}
)
res = await self.get(
f'/ddn/observation/obsrv-measurements/search?{encoded_query}',
headers={'Authorization': f'Bearer {access_token}'},
)
match res.status_code:
case st.HTTP_200_OK:
return s.ObservationMeasurementsModel.model_validate(
res.json()
)
case _:
self.logger.error(res.json())
raise e.UnknownException

80
src/clients/tdn/schema.py Normal file
View File

@ -0,0 +1,80 @@
from datetime import datetime
from pydantic import BaseModel
class SignInModel(BaseModel):
accessToken: str
refreshToken: str
class ObservationModel(BaseModel):
uid: str
createdAt: datetime
updatedAt: datetime
realmUid: str
patientUid: str
nosologyUid: str
exclusionReasonUid: str | None
exclusionComment: str | None
exclusionDate: datetime | None
employeeUid: str
mobileId: str | None
class ObservationsModel(BaseModel):
items: list[ObservationModel]
total: int
class MeasurementModel(BaseModel):
uid: str
createdAt: datetime
updatedAt: datetime
code: str
title: str
order: int
isSelfControl: bool
class MetricModel(BaseModel):
uid: str
createdAt: datetime
updatedAt: datetime
code: str
title: str
order: int
shortName: str
measureUid: str | None
format: str
class ObservationMtMetricModel(BaseModel):
uid: str
createdAt: datetime
updatedAt: datetime
obsrvMeasurementUid: str
metricUid: str
mobileId: str | None
metric: MetricModel
class ObservationMeasurementModel(BaseModel):
uid: str
createdAt: datetime
updatedAt: datetime
observationUid: str
measurementUid: str
timeFrequency: int
timePeriod: int
timePeriodMeasureUid: str
timeOfDay: list[str]
comment: str | None
mobileId: str | None
measurement: MeasurementModel
obsrvMtMetrics: list[ObservationMtMetricModel]
class ObservationMeasurementsModel(BaseModel):
items: list[ObservationMeasurementModel]
total: int

View File

@ -266,9 +266,10 @@ class MedExamItemModel(BaseModel):
title='Наименрование услуги', title='Наименрование услуги',
examples=['Осмотр фельдшером (акушеркой) или врачом акушером'], examples=['Осмотр фельдшером (акушеркой) или врачом акушером'],
) )
SpecialityName: str = Field( SpecialityName: str | None = Field(
title='Специальность', title='Специальность',
examples=['Акушер-гинеколог'], examples=['Акушер-гинеколог'],
default=None,
) )
@ -360,9 +361,7 @@ class ExaminationModel(BaseModel):
DateTime: str = Field( DateTime: str = Field(
title='Дата и время создания', examples=['01.08.2025 15:47:15'] title='Дата и время создания', examples=['01.08.2025 15:47:15']
) )
Resource: str = Field( Post: str = Field(title='Врач', examples=['Абдуллина Ирина Владимировна'])
title='Врач', examples=['Абдуллина Ирина Владимировна']
)
Speciality: str = Field( Speciality: str = Field(
title='Специальность врача', examples=['Акушер-гинеколог'] title='Специальность врача', examples=['Акушер-гинеколог']
) )

View File

@ -57,6 +57,11 @@ class Settings(BaseSettings):
default='https://gist-cws.ezdrav.ru:8899/MP_API' default='https://gist-cws.ezdrav.ru:8899/MP_API'
) )
# TDN
TDN_BASE_URL: str = Field(default='https://tdn.tatar.ru/api')
TDN_LOGIN: str = Field(default='')
TDN_PASSWORD: str = Field(default='')
@model_validator(mode='after') @model_validator(mode='after')
def celery_env(self): def celery_env(self):
environ['CELERY_BROKER_URL'] = self.REDIS_URL environ['CELERY_BROKER_URL'] = self.REDIS_URL