This commit is contained in:
2026-02-15 17:02:40 +03:00
parent f79e4bcbb5
commit a042942446
78 changed files with 9863 additions and 0 deletions
+405
View File
@@ -0,0 +1,405 @@
from pathlib import Path
from fastapi import APIRouter, Depends, HTTPException
from api.n3health import resend, revoke, sendForSigning
from db.schemas.documents import Document
from db.schemas.patients import Patient
from db.schemas.practitioners import Practitioner
from db.schemas.settings import Settings
from db.schemas.signings import Signing
from db.schemas.statuses import Statuses
from utils import requestDict, logger, convert_docs_to_pdfs
from utils.attachment import pdfGet
router = APIRouter()
@router.get("/health", summary="Health")
async def health():
return {"status": "healthy"}
@router.post("/pre_singing", summary="pre_singing")
async def pre_singing(
reqData: dict = Depends(requestDict),
):
# signature - type: eSignature / eAttorney
logger.info(f"📥 Получен запрос на /pre_singing")
practitioner = await Practitioner.getPractitionerByIdLpu(
reqData.get("body", {}).get("userId", 0)
)
signature = {}
if practitioner.success:
signature["type"] = (
"eSignature" if practitioner.data.get("esiaAuth", False) else "eAttorney"
)
signature["expiration"] = practitioner.data.get("expired_at")[:10]
daysRemainingControl = 0
settings = await Settings.getSettings()
if settings.success:
daysRemainingControl = settings.data.get("expirationAlert", 0)
inProgress = []
complete = []
idPatientMis = reqData.get("body", {}).get("patientId", 0)
if type(idPatientMis) != str:
idPatientMis = str(idPatientMis)
patient = await Patient.getPatientByIdPatientMis(idPatientMis, False, True)
if patient.success:
docNumbers = reqData.get("body", {}).get("docNumbers", [])
for docNumber in docNumbers:
if type(docNumber) != int:
docNumber = int(docNumber)
docs = await Document.getDocumentsByIdPatientMisAndNumber(
idPatientMis, docNumber, True
)
if docs.success:
for doc in docs.data:
docSingingId = doc.singingId
docSinging = await Signing.getSigningById(docSingingId)
if docSinging.success:
if docSinging.data.get("storagePath"):
complete.append(docNumber)
else:
if docSinging.data.get("trackingId"):
inProgress.append(docNumber)
else:
logger.info(f"{docNumber} - {docs.message}")
exitData = {
"signature": signature,
"inProgress": inProgress,
"complete": complete,
"daysRemainingControl": daysRemainingControl,
}
return exitData
@router.post("/singing", summary="singing")
async def singing(
reqData: dict = Depends(requestDict),
):
def correctData(data):
data["practitioner"]["userIdLpu"] = str(data["practitioner"]["userIdLpu"])
for patient in data["patients"]:
patient["idPatientMis"] = str(patient["idPatientMis"])
return data
logger.info(f"📥 Получен запрос на /singing")
# Получаем данные из запроса
body = reqData.get("body", {})
docs = body.pop("docs", [])
# Проверяем наличие документов
if not docs:
logger.warning("Нет документов для обработки")
return {"status": "ERROR", "message": "Нет документов для обработки"}
practitioner = await Practitioner.getPractitionerByIdLpu(
body.get("practitioner", {}).get("userIdLpu", 0)
)
if not practitioner.success:
logger.error(
f"Сотрудник не найден, idLpu: {body.get('practitioner', {}).get('userIdLpu', 0)}"
)
return {"status": "ERROR", "message": "Сотрудник не найден"}
esiaAuth = practitioner.data.get("esiaAuth", False)
userIdLpu = practitioner.data.get("userIdLpu", 0)
patients = body.get("patients", [])
if len(patients) == 0:
logger.error("Данные пациента не получены, пациент не найден")
return {
"status": "ERROR",
"message": "Данные пациента не получены, пациент не найден",
}
patientsData = []
for patient in patients:
idPatientMis = patient.get("idPatientMis", None)
if not idPatientMis:
logger.error("Не указан идентификатор пациента")
return {
"status": "ERROR",
"message": "Не указан идентификатор пациента",
}
patientDB = await Patient.getPatientByIdPatientMis(idPatientMis, isCheck=True)
if not patientDB.success:
patientData = {
"idPatientMis": idPatientMis,
"familyName": patient.get("familyName", "N/A"),
"givenName": patient.get("givenName", "N/A"),
"middleName": patient.get("middleName", "N/A"),
"birthDate": patient.get("birthDate", "N/A"),
"sex": patient.get("sex", "N/A"),
}
newPatient = await Patient.addPatient(**patientData)
if not newPatient.success:
return {
"status": "ERROR",
"message": newPatient.message,
}
patientsData.append(newPatient.data.toDict())
else:
patientsData.append(patientDB.data)
# Логируем информацию о документах
logger.info(f"👨‍⚕️ Медработник: {practitioner.data.get("name")}")
logger.info(
f"👥 Пациенты ({len(patientsData)}): {', '.join([f'{p.get('name')}' for p in patientsData])}"
)
logger.info(f"📄 Документов для обработки: {len(docs)}")
logger.info(f"🔐 ЕСИА: {esiaAuth}")
try:
# Конвертируем документы в PDF
conversion_result = convert_docs_to_pdfs(docs, patientsData)
# logger.info(conversion_result)
if conversion_result.get("status", "") != "SUCCESS":
return {
"status": "ERROR",
"message": "Не удалось сохранить документы",
}
newSinging = await Signing.addSigning(userIdLpu, idPatientMis)
if not newSinging:
return {
"status": "ERROR",
"message": "Не удалось добавить подписание",
}
logger.info(f"🔐 Подписание добавлено: {newSinging.id}")
pdfFiles = conversion_result.get("files", {})
body["medDocument"] = {
"esiaAuth": esiaAuth,
"attachments": [],
}
body["files"] = []
for key in pdfFiles:
pdfFile = pdfFiles[key]
for doc in pdfFile:
newDocument = await Document.addDocument(
singingId=newSinging.id, idPatientMis=key, **doc
)
if not newDocument:
return {
"status": "ERROR",
"message": "Не удалось добавить документ",
}
logger.info(f"📄 Документ добавлен: {newDocument.id}")
partName = f'file{len(body["medDocument"]["attachments"])}'
body["medDocument"]["attachments"].append(
{
"partName": partName,
}
)
body["files"].append(
{
"field": partName,
"path": Path(doc["storagePath"]),
"content_type": "application/pdf",
}
)
if esiaAuth:
partName = f'file{len(body["medDocument"]["attachments"])}'
body["medDocument"]["attachments"].append(
{
"partName": partName,
}
)
body["files"].append(
{
"field": partName,
"path": Path(
f"src/attachments/secure/{userIdLpu}/signature.p7s"
).resolve(),
"content_type": "application/pkcs7-signature",
}
)
signingResult = await sendForSigning(correctData(body))
if not signingResult or signingResult.get("status", "") != "created":
return {
"status": "ERROR",
"message": "Не удалось отправить документы на подписание",
}
newSinging.trackingId = signingResult.get("trackingId", "")
await newSinging.save()
logger.info(
f"🔐 Подписание обновлено: {newSinging.id}. Добавлен Трек-номер подписания"
)
await Statuses.updateStatus(newSinging.id, True)
logger.info(f"✅ Обработка завершена!")
# Возвращаем ответ
response = {
"status": "SUCCESS",
"message": f"Документы успешно обработаны. Трек-номер подписания: {newSinging.trackingId}",
}
return response
except Exception as e:
error_msg = f"Ошибка при обработке документов: {str(e)}"
logger.error(error_msg)
raise HTTPException(status_code=500, detail=error_msg)
@router.post("/statuses", summary="statuses")
async def statuses(
reqData: dict = Depends(requestDict),
):
logger.info(f"📥 Получен запрос на /statuses")
# Получаем данные из запроса
body = reqData.get("body", {})
userIdLpu = str(body.get("userIdLpu"))
filters = body.get("filters", {})
if not userIdLpu or not filters:
logger.error("Не отправлены userIdLpu или filters")
return {"status": "ERROR", "message": "Не отправлены необходимые данные"}
result = await Signing.getFilteredSingings(userIdLpu, filters)
singingsData = result.data
return singingsData
@router.post("/documents", summary="documents")
async def documents(
reqData: dict = Depends(requestDict),
):
logger.info(f"📥 Получен запрос на /documents")
# Получаем данные из запроса
body = reqData.get("body", {})
if "idPatientMis" not in body:
logger.error("Не отправлен idPatientMis")
return {"status": "ERROR", "message": "Не отправлен idPatientMis"}
idPatientMis = body.get("idPatientMis")
singingData = await Signing.getSigningsByIdPatientMis(idPatientMis)
if not singingData.success:
logger.error("Подписания не найдены")
return {"status": "SUCCESS", "data": [], "message": "Подписания не найдены"}
userIdLpus = set([s.get("userIdLpu") for s in singingData.data])
practitioners = {}
for userIdLpu in userIdLpus:
practitioner = await Practitioner.getPractitionerByIdLpu(userIdLpu, False)
practitioners[userIdLpu] = practitioner.data.name
for s in singingData.data:
s["practitioner"] = practitioners[s.get("userIdLpu")]
responseData = {"status": "SUCCESS", "data": singingData.data}
return responseData
@router.post("/document", summary="document")
async def document(
reqData: dict = Depends(requestDict),
):
logger.info(f"📥 Получен запрос на /document")
documentPath = reqData.get("body", {}).get("documentPath", None)
if not documentPath:
return {"status": "ERROR", "message": "Документ не найден"}
docBytes = pdfGet(documentPath)
if not docBytes.success:
return {"status": "ERROR", "message": docBytes.message}
return {"status": "SUCCESS", "data": docBytes.data}
@router.post("/revoke", summary="revoke")
async def revoke_post(
reqData: dict = Depends(requestDict),
):
logger.info(f"📥 Получен запрос на /revoke")
trackingId = reqData.get("body", {}).get("trackingId", None)
if not trackingId:
return {"status": "ERROR", "message": "Документ не найден"}
revokeResult = await revoke(trackingId)
if revokeResult.get("status", "") != "success":
return {
"status": "ERROR",
"message": revokeResult.get("errorMessage", "Отозвать не удалось"),
}
import asyncio
await asyncio.sleep(2)
await Signing.updateStatuses()
return {"status": "SUCCESS", "message": "Документ отозван"}
@router.post("/resend", summary="resend")
async def resend_post(
reqData: dict = Depends(requestDict),
):
logger.info(f"📥 Получен запрос на /resend")
trackingId = reqData.get("body", {}).get("trackingId", None)
idPatientMis = reqData.get("body", {}).get("idPatientMis", None)
errorResponse = {"status": "ERROR", "message": "Повторная отправка не удалось"}
if not trackingId or not idPatientMis:
logger.error("Не отправлен trackingId или idPatientMis")
logger.error(f"trackingId: {trackingId}, idPatientMis: {idPatientMis}")
return errorResponse
resendResult = await resend(trackingId, idPatientMis)
if not resendResult or not resendResult.get("status", ""):
logger.error(resendResult)
return errorResponse
newTrackingId = resendResult.get("tracking_id", "")
singingId = reqData.get("body", {}).get("id", "")
if not newTrackingId or not singingId:
logger.error("Не отправлен trackingId или id")
logger.error(f"trackingId: {newTrackingId}, id: {singingId}")
return errorResponse
singing = await Signing.getSigningById(singingId)
if not singing.success:
logger.error(singing.message)
return errorResponse
await singing.data.edit(trackingId=newTrackingId)
logger.info("✅ Повторная отправка успешна")
return {"status": "SUCCESS", "message": resendResult.get("message", "")}
@router.post("/advanced-search", summary="advanced-search")
async def advanced_search_post(
reqData: dict = Depends(requestDict),
):
logger.info(f"📥 Получен запрос на /advanced-search")
result = await Signing.getFilteredSingings(
"", reqData.get("body", {}).get("filters", {})
)
return {"status": "SUCCESS", "data": result.data}