release
This commit is contained in:
@@ -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}
|
||||
Reference in New Issue
Block a user