Files
HospitalAssistantBackend/src/apps/users/v1/router.py
Miwory b138e4f47c
All checks were successful
Build And Push / publish (push) Successful in 1m23s
Патч
2025-12-14 22:15:50 +03:00

479 lines
13 KiB
Python

import base64
from datetime import UTC, datetime
from json import dumps
from logging import getLogger
from secrets import token_urlsafe
from typing import Annotated
from fastapi import APIRouter, Body, Depends, UploadFile, status
from orjson import loads
from apps.remd.dependencies import convert_aemd_to_pdf, get_parsable_ids
from apps.tdn.auth import token
from apps.users.auth import login
from apps.users.models import User
from clients import clients as c
from clients.tmk import schema as ts
from clients.vitacore import schema as vs
from shared import exceptions as e
from shared.redis import client as cache
from . import schema as s
logger = getLogger(__name__)
router = APIRouter(
prefix='/user',
tags=[
'User',
],
)
@router.get(
'/getProfile',
responses={
status.HTTP_200_OK: {'model': vs.ProfileModel},
},
)
async def get_profile(user: Annotated[User, Depends(login)]):
"""
Get profile of user.
"""
return await c.vitacore_api.getProfile(user.vita_id)
@router.get(
'/getDepartments',
responses={
status.HTTP_200_OK: {'model': vs.OrganizationsModel},
},
)
async def get_departments():
"""
Get list of departments.
"""
return await c.vitacore_api.getDepartments()
@router.get(
'/getWorkers', responses={status.HTTP_200_OK: {'model': vs.WorkersModel}}
)
async def get_workers(
user: Annotated[User, Depends(login)], departmentId: str
):
"""
Get list of workers by department id.
"""
return await c.vitacore_api.getWorkers(departmentId)
@router.get(
'/getSpecs',
responses={status.HTTP_200_OK: {'model': vs.SpecsV021Model}},
)
async def get_specs(user: Annotated[User, Depends(login)]):
"""
Get list of specialties.
"""
return await c.vitacore_api.getSpecsV021()
@router.get(
'/getEntries', responses={status.HTTP_200_OK: {'model': vs.EntriesModel}}
)
async def get_entries(user: Annotated[User, Depends(login)]):
"""
Get list of entries for user by id.
"""
return await c.vitacore_api.getEntries(user.vita_id)
@router.get('/getVaccsReport')
async def get_vaccs_report(
user: Annotated[User, Depends(login)], resultId: str | None = None
):
"""
Get report of vaccinations for user by id.
"""
if resultId is not None:
return await c.vitacore_api.getDiagResultFile(resultId)
return await c.vitacore_api.getVaccsReport(user.vita_id)
@router.get('/getMedExamDict')
async def get_med_exam_dict(user: Annotated[User, Depends(login)]):
"""
Get medical examination dictionary.
"""
return await c.vitacore_api.getMedExamDict()
@router.get('/getRoutesList')
async def get_routes_list(user: Annotated[User, Depends(login)]):
"""
Get list of routes.
"""
return await c.vitacore_api.getRoutesList(user.vita_id)
@router.get('/getHospExaminations')
async def get_hosp_examinations(
user: Annotated[User, Depends(login)], examId: str | None = None
):
"""
Get list of hospital examinations.
"""
return await c.vitacore_api.getHospExaminations(
user.vita_id,
examId,
)
@router.get('/getCurrHosp')
async def get_curr_hosp(user: Annotated[User, Depends(login)]):
"""
Get current hospitalization.
"""
return await c.vitacore_api.getCurrHosp(user.vita_id)
@router.get('/getHosps')
async def get_hosps(user: Annotated[User, Depends(login)]):
"""
Get list of hospitals.
"""
return await c.vitacore_api.getHosps(user.vita_id)
@router.get('/getHospRecommendations')
async def get_hosp_recommendations(user: Annotated[User, Depends(login)]):
"""
Get list of recommended hospitals.
"""
return await c.vitacore_api.getHospRecommendations(user.vita_id)
@router.get('/getHospRoutes')
async def get_hosp_routes(user: Annotated[User, Depends(login)]):
"""
Get list of recommended hospitals.
"""
return await c.vitacore_api.getHospRoutes(user.vita_id)
@router.get('/getDiagnosticResults')
async def get_diagnostic_results(user: Annotated[User, Depends(login)]):
"""
Get list of diagnostic results.
"""
return await c.vitacore_api.getDiagnosticResults(user.vita_id)
@router.get('/getELNs')
async def get_eln(user: Annotated[User, Depends(login)]):
"""
Get list of ELNs.
"""
return await c.vitacore_api.getELNs(user.vita_id)
@router.get('/getPatFLG')
async def get_pat_flg(user: Annotated[User, Depends(login)]):
"""
Get list of ELNs.
"""
return await c.vitacore_api.getPatFLG(user.vita_id)
@router.get('/queue', response_model=list[ts.QueueModel])
async def queue(user: Annotated[User, Depends(login)]):
"""
Get list of VKS queues.
"""
profile = await c.vitacore_api.getProfile(user.vita_id)
return await c.tmk_api.getQueue(patient_snils=profile.SNILS)
@router.get('/aemd')
async def get_aemd(
user: Annotated[User, Depends(login)],
parsable_ids: Annotated[list[str], Depends(get_parsable_ids)],
):
profile = await c.vitacore_api.getProfile(user.vita_id)
snils = profile.SNILS.replace('-', '').replace(' ', '')
docs = await c.aemd_api.searchRegistryItem(patient_snils=snils)
items: list[s.AEMDFile] = docs['items']
return_items: list[s.AEMDReturnFile] = []
for item in items:
if item['DocKind'] not in parsable_ids:
continue
is_cached = await cache.get(f'aemd:{user.vita_id}:{item["emdrId"]}')
return_items.append(
s.AEMDReturnFile(
emdrId=item['emdrId'],
registrationDate=item['registrationDate'],
DocKind=item['DocKind'],
IsSemd=item['IsSemd'],
isCached=bool(is_cached),
)
)
return return_items
@router.post('/aemd', status_code=status.HTTP_202_ACCEPTED)
async def post_aemd(user: Annotated[User, Depends(login)], emdrId: str):
messageId = token_urlsafe(32)
data = s.AEMDDemandContent(
messageId=messageId, emdrId=emdrId, vitaId=user.vita_id
)
await cache.set(f'aemd_messages:{messageId}', dumps(data))
await c.aemd_api.demandContent(messageId=messageId, emdrId=emdrId)
@router.get('/aemd/{emdrId}')
async def get_aemd_file(
user: Annotated[User, Depends(login)], emdrId: str, docKind: str
):
data = await cache.get(f'aemd:{user.vita_id}:{emdrId}')
if not data:
raise e.NotFoundException(status_code=404, detail='File not found')
b64 = loads(data)['data']
decoded = base64.b64decode(b64)
pdf = await convert_aemd_to_pdf(decoded, docKind)
b64_pdf = base64.b64encode(pdf).decode('utf-8')
return {
'filename': f'{emdrId}.pdf',
'content_type': 'application/pdf',
'data': b64_pdf,
}
@router.post('/measurement', status_code=status.HTTP_202_ACCEPTED)
async def measurement(
tdn_access_token: Annotated[str, Depends(token)],
user: Annotated[User, Depends(login)],
ad: Annotated[int, Body()],
sd: Annotated[int, Body()],
pulse: Annotated[int, Body()],
comment: Annotated[str, Body()],
status: Annotated[int, Body(ge=1, le=3)],
serial_number: Annotated[str, Body()],
ekg: UploadFile,
):
vitaId = '109df850-2268-49fb-bb78-2e0f3c57314d'
patient = await c.tdn_api.patient_search(tdn_access_token, vitaId)
patientUid = patient['items'][0]['uid']
observations = await c.tdn_api.observations_search(
tdn_access_token, patientUid
)
if observations.total == 0:
raise e.NotFoundException(detail='No observations found')
ad_obsrvMeasurementUid = None
ad_observationUid = None
health_obsrvMeasurementUid = None
health_observationUid = None
sad_measurement = None
dad_measurement = None
pulse_measurement = None
health_measurement = None
health_measurement_created_at = None
observations = observations.items[::-1]
for observation in observations:
observation_measurements = (
await c.tdn_api.observations_measurement_search(
tdn_access_token, observation.uid
)
)
for measurement in observation_measurements.items:
if measurement.measurement.code == 'ADPULSE':
ad_obsrvMeasurementUid = measurement.uid
ad_observationUid = measurement.observationUid
for metric in measurement.obsrvMtMetrics:
if metric.metric.code == 'SAD':
sad_measurement = metric.uid
if metric.metric.code == 'DAD':
dad_measurement = metric.uid
if metric.metric.code == 'PULSE':
pulse_measurement = metric.uid
if measurement.measurement.code == 'HEALTH':
health_obsrvMeasurementUid = measurement.uid
health_observationUid = measurement.observationUid
for metric in measurement.obsrvMtMetrics:
if metric.metric.code == 'HEALTH' and (
health_measurement_created_at is None
or metric.createdAt > health_measurement_created_at
):
health_measurement = metric.uid
health_measurement_created_at = metric.createdAt
if (
not ad_obsrvMeasurementUid
or not sad_measurement
or not dad_measurement
or not pulse_measurement
or not ad_observationUid
or not health_obsrvMeasurementUid
or not health_observationUid
or not health_measurement
or not health_measurement_created_at
):
ad_obsrvMeasurementUid = None
sad_measurement = None
dad_measurement = None
pulse_measurement = None
ad_observationUid = None
health_obsrvMeasurementUid = None
health_observationUid = None
health_measurement = None
health_measurement_created_at = None
else:
break
if not ad_obsrvMeasurementUid or not ad_observationUid:
raise e.NotFoundException(detail='No ADPULSE measurement found')
if not sad_measurement:
raise e.NotFoundException(detail='No SAD measurement found')
if not dad_measurement:
raise e.NotFoundException(detail='No DAD measurement found')
if not pulse_measurement:
raise e.NotFoundException(detail='No PULSE measurement found')
if not health_obsrvMeasurementUid or not health_observationUid:
raise e.NotFoundException(detail='No HEALTH measurement found')
if not health_measurement:
raise e.NotFoundException(detail='No HEALTH measurement found')
if not health_obsrvMeasurementUid or not health_observationUid:
raise e.NotFoundException(detail='No HEALTH measurement found')
ad_series = await c.tdn_api.create_series(
tdn_access_token,
ad_observationUid,
ad_obsrvMeasurementUid,
)
ad_series_uid = ad_series.uid
# SAD
await c.tdn_api.create_series_values(
tdn_access_token, ad_series_uid, sad_measurement, nvalue=sd
)
# DAD
await c.tdn_api.create_series_values(
tdn_access_token, ad_series_uid, dad_measurement, nvalue=ad
)
# PULSE
await c.tdn_api.create_series_values(
tdn_access_token, ad_series_uid, pulse_measurement, nvalue=pulse
)
health_series = await c.tdn_api.create_series(
tdn_access_token,
health_observationUid,
health_obsrvMeasurementUid,
)
health_series_uid = health_series.uid
# HEALTH
await c.tdn_api.create_series_values(
tdn_access_token,
health_series_uid,
health_measurement,
nvalue=status,
svalue=comment,
)
# EKG
await c.tdn_api.ekg(
tdn_access_token,
patientUid,
serial_number,
ekg,
)
created = datetime.now(UTC).strftime('%Y-%m-%d %H:%M:%S')
data = {
'ad': ad,
'sd': sd,
'pulse': pulse,
'created_at': created,
'comment': comment,
'status': status,
}
cache_key = f'tdn:measurement:{user.id}:{created}'
await cache.set(cache_key, dumps(data))
@router.get('/measurements')
async def measurements(
user: Annotated[User, Depends(login)],
):
data = [
await cache.get(key)
for key in await cache.keys(f'tdn:measurement:{user.id}:*')
]
return data
@router.delete('/account', status_code=status.HTTP_204_NO_CONTENT)
async def delete_account(user: Annotated[User, Depends(login)]):
return
@router.get('/notifications')
async def notifications(user: Annotated[User, Depends(login)]):
keys = await cache.keys(f'tmk:{user.id}:*')
notif: list[dict[str, str | bool]] = []
for key in keys:
val = await cache.get(key)
if val is None:
continue
value = loads(val)
notif_val = value.copy()
notif.append(notif_val)
if value['is_read'] is False:
value['is_read'] = True
await cache.set(key, dumps(value))
return s.Notifications(
notifications=notif,
)
@router.post('/complaint', status_code=status.HTTP_204_NO_CONTENT)
async def complaint(
user: Annotated[User, Depends(login)], complaints: s.Complaints
):
cache_key = f'complaint:{user.vita_id}'
await cache.set(cache_key, dumps(complaints.complaints))