diff --git a/config.py b/config.py index 8230aef5..466bebe5 100644 --- a/config.py +++ b/config.py @@ -5,8 +5,8 @@ class Config: - VERSION = "v4.16-beta" - FRONTEND_VERSION = "4.0.10" + VERSION = "v4.17-beta" + FRONTEND_VERSION = "4.0.13" ENV = getenv("ENV") or NoHarmENV.DEVELOPMENT.value SECRET_KEY = getenv("SECRET_KEY") or "secret_key" API_KEY = getenv("API_KEY") or "" @@ -32,6 +32,7 @@ class Config: MAIL_HOST = getenv("MAIL_HOST") or "localhost" NIFI_BUCKET_NAME = getenv("NIFI_BUCKET_NAME") or "" + NIFI_SQS_QUEUE_REGION = getenv("NIFI_SQS_QUEUE_REGION") or "" CACHE_BUCKET_NAME = getenv("CACHE_BUCKET_NAME") or "" CACHE_BUCKET_ID = getenv("CACHE_BUCKET_ID") or "" diff --git a/models/enums.py b/models/enums.py index b302baf2..18e352e2 100644 --- a/models/enums.py +++ b/models/enums.py @@ -54,6 +54,7 @@ class FeatureEnum(Enum): CONCILIATION_EDIT = "CONCILIATION_EDIT" DISABLE_CPOE = "DISABLE_CPOE" STAGING_ACCESS = "STAGING_ACCESS" + AUTOMATIC_CHECK_IF_NOT_VALIDATED_ITENS = "AUTOMATIC_CHECK_IF_NOT_VALIDATED_ITENS" class PrescriptionAuditTypeEnum(Enum): @@ -65,11 +66,13 @@ class PrescriptionAuditTypeEnum(Enum): INTEGRATION_PRESCRIPTION_RELEASE = 6 UPSERT_CLINICAL_NOTES = 7 CREATE_AGG = 8 + ERROR_INTEGRATION_PRESCRIPTION_RELEASE = 9 class PrescriptionDrugAuditTypeEnum(Enum): PROCESSED = 1 UPSERT = 2 + INTEGRATION_PRESCRIPTION_DRUG_RELEASE = 3 class PrescriptionReviewTypeEnum(Enum): diff --git a/routes/static.py b/routes/static.py index 145a5a32..e8929711 100644 --- a/routes/static.py +++ b/routes/static.py @@ -24,6 +24,7 @@ def create_aggregated_by_prescription(schema, id_prescription): force = request.args.get("force", False) user_context = User() + user_context.id = 0 user_context.schema = schema user_context.config = {"roles": ["STATIC_USER"]} g.user_context = user_context @@ -64,6 +65,7 @@ def create_aggregated_prescription_by_date(schema, admission_number): ) user_context = User() + user_context.id = 0 user_context.schema = schema user_context.config = {"roles": ["STATIC_USER"]} g.user_context = user_context diff --git a/security/permission.py b/security/permission.py index ce6d7248..3f6032ad 100644 --- a/security/permission.py +++ b/security/permission.py @@ -75,6 +75,7 @@ class Permission(Enum): RUN_AS = "RUN_AS" # "permission to service users" READ_STATIC = "READ_STATIC" # "read static permission" + CHECK_STATIC = "CHECK_STATIC" # check from static context MULTI_SCHEMA = "MULTI_SCHEMA" # "grants multi schema access" MAINTAINER = "MAINTAINER" # "grants access to closed contracts" diff --git a/security/role.py b/security/role.py index dafc9207..31a5f5b5 100644 --- a/security/role.py +++ b/security/role.py @@ -152,7 +152,7 @@ def __init__(self, id: str, permissions: List[Permission]): REGULATOR = "REGULATOR", [Permission.READ_REGULATION, Permission.WRITE_REGULATION] - STATIC_USER = "STATIC_USER", [Permission.READ_STATIC] + STATIC_USER = "STATIC_USER", [Permission.READ_STATIC, Permission.CHECK_STATIC] ORGANIZATION_MANAGER = "ORGANIZATION_MANAGER", [Permission.MULTI_SCHEMA] diff --git a/services/admin/admin_integration_remote_service.py b/services/admin/admin_integration_remote_service.py index 6dcde119..3a1e0dd8 100644 --- a/services/admin/admin_integration_remote_service.py +++ b/services/admin/admin_integration_remote_service.py @@ -1,14 +1,17 @@ import re import boto3 +import json import dateutil as pydateutil from utils import status from markupsafe import escape from datetime import datetime, timedelta from sqlalchemy import desc +from sqlalchemy.orm import Session from botocore.exceptions import ClientError +from botocore.config import Config as BotoConfig from models.main import db, User -from models.appendix import NifiStatus, NifiQueue +from models.appendix import NifiQueue from utils import dateutils from models.enums import NifiQueueActionTypeEnum from exception.validation_error import ValidationError @@ -64,12 +67,12 @@ def _get_cache_data(client, schema, filename="current"): @has_permission(Permission.ADMIN_INTEGRATION_REMOTE) def get_template_date(user_context: User): client = boto3.client("s3") - url, metadata = _get_cache_data( + cache_data = _get_cache_data( client=client, schema=user_context.schema, filename="template" ) - if metadata != None: - return {"updatedAt": metadata["updatedAt"]} + if cache_data != None: + return {"updatedAt": cache_data["updatedAt"]} return {"updatedAt": None} @@ -129,7 +132,9 @@ def get_template(user_context: User): @has_permission(Permission.ADMIN_INTEGRATION_REMOTE) -def push_queue_request(id_processor: str, action_type: str, data: dict): +def push_queue_request( + id_processor: str, action_type: str, data: dict, user_context: User +): if id_processor == None and ( action_type != NifiQueueActionTypeEnum.CUSTOM_CALLBACK.value and action_type != NifiQueueActionTypeEnum.REFRESH_TEMPLATE.value @@ -177,6 +182,8 @@ def push_queue_request(id_processor: str, action_type: str, data: dict): db.session.add(queue) db.session.flush() + _send_to_sqs(queue=queue, schema=user_context.schema) + return { "id": queue.id, "extra": queue.extra, @@ -184,6 +191,38 @@ def push_queue_request(id_processor: str, action_type: str, data: dict): } +def _send_to_sqs(queue: NifiQueue, schema: str): + sqs = boto3.client( + "sqs", + config=BotoConfig( + region_name=Config.NIFI_SQS_QUEUE_REGION, + ), + ) + response = sqs.get_queue_url( + QueueName=schema, + ) + queue_url = response["QueueUrl"] + body_data = { + "schema": schema, + "id": queue.id, + "url": queue.url, + "method": queue.method, + "runStatus": queue.runStatus, + "body": queue.body if queue.body else {"empty": True}, + "type": queue.extra.get("type", "default"), + } + + sqs.send_message( + QueueUrl=queue_url, + DelaySeconds=10, + MessageAttributes={ + "schema": {"DataType": "String", "StringValue": schema}, + "type": {"DataType": "String", "StringValue": "request"}, + }, + MessageBody=json.dumps(body_data), + ) + + def _get_new_queue(id_processor: str, action_type: str, data: dict): queue = NifiQueue() queue.runStatus = False @@ -225,27 +264,50 @@ def _get_new_queue(id_processor: str, action_type: str, data: dict): @has_permission(Permission.ADMIN_INTEGRATION_REMOTE) -def get_queue_status(id_queue_list): - queue_list = ( - db.session.query(NifiQueue).filter(NifiQueue.id.in_(id_queue_list)).all() - ) +def get_queue_status(id_queue_list, user_context: User): queue_results = [] - for q in queue_list: - queue_results.append( - { - "id": q.id, - "url": q.url, - "body": q.body, - "method": q.method, - "extra": q.extra, - "responseCode": q.responseCode, - "response": q.response, - "responseAt": dateutils.to_iso(q.responseAt), - "createdAt": dateutils.to_iso(q.createdAt), - } + update_status = False + + engine = db.engines["report"] + with Session(engine) as session: + session.connection( + execution_options={"schema_translate_map": {None: user_context.schema}} + ) + queue_list = ( + session.query(NifiQueue).filter(NifiQueue.id.in_(id_queue_list)).all() + ) + + for q in queue_list: + if q.responseCode == status.HTTP_200_OK: + update_status = True + + queue_results.append( + { + "id": q.id, + "url": q.url, + "body": q.body, + "method": q.method, + "extra": q.extra, + "responseCode": q.responseCode, + "response": q.response, + "responseAt": dateutils.to_iso(q.responseAt), + "createdAt": dateutils.to_iso(q.createdAt), + } + ) + + status_url = None + status_updated_at = None + if update_status: + status_url, status_updated_at = get_file_url( + schema=user_context.schema, filename="status" ) - return queue_results + return { + "queue": queue_results, + "updateStatus": update_status, + "statusUrl": status_url, + "statusUpdatedAt": status_updated_at, + } def _validate_custom_endpoint(endpoint: str): diff --git a/services/data_authorization_service.py b/services/data_authorization_service.py index f4f846bb..b927be52 100644 --- a/services/data_authorization_service.py +++ b/services/data_authorization_service.py @@ -11,7 +11,7 @@ def has_segment_authorization(id_segment: int, user: User): return True permissions = Role.get_permissions_from_user(user=user) - if Permission.MAINTAINER in permissions: + if Permission.MAINTAINER in permissions or Permission.CHECK_STATIC in permissions: return True if memory_service.has_feature(FeatureEnum.AUTHORIZATION_SEGMENT.value): diff --git a/services/feature_service.py b/services/feature_service.py index 51e122e0..7b6eab4d 100644 --- a/services/feature_service.py +++ b/services/feature_service.py @@ -1,5 +1,25 @@ from flask import g +from models.main import db +from models.appendix import Memory +from models.enums import MemoryEnum, FeatureEnum + def is_cpoe(): return g.get("is_cpoe", False) + + +def has_feature(user_feature: FeatureEnum): + features = g.get("features", []) + + if not features: + features_memory = ( + db.session.query(Memory) + .filter(Memory.kind == MemoryEnum.FEATURES.value) + .first() + ) + if features_memory: + features = features_memory.value + g.features = features + + return user_feature.value in features diff --git a/services/prescription_agg_service.py b/services/prescription_agg_service.py index fcac0ae8..a0d38603 100644 --- a/services/prescription_agg_service.py +++ b/services/prescription_agg_service.py @@ -15,6 +15,7 @@ PrescriptionDrugAuditTypeEnum, DrugTypeEnum, PatientConciliationStatusEnum, + FeatureEnum, ) from services import ( prescription_drug_service, @@ -228,6 +229,7 @@ def create_agg_prescription_by_date( ) _log_processed_date(id_prescription_array=internal_prescription_ids, schema=schema) + _automatic_check(prescription=agg_p, features=features, user_context=user_context) def _log_processed_date(id_prescription_array, schema): @@ -409,3 +411,23 @@ def _audit_create(prescription: Prescription): a.createdBy = 0 db.session.add(a) + + +def _automatic_check(prescription: Prescription, features: dict, user_context: User): + # automatic check prescription if there are no items with validation (drugs, solutions, procedures) + if ( + features.get("totalItens") == 0 + and prescription.status != "s" + and feature_service.has_feature( + FeatureEnum.AUTOMATIC_CHECK_IF_NOT_VALIDATED_ITENS + ) + ): + prescription_check_service.check_prescription( + idPrescription=prescription.id, + p_status="s", + user_context=user_context, + evaluation_time=0, + alerts=[], + service_user=False, + fast_check=True, + ) diff --git a/services/prioritization_service.py b/services/prioritization_service.py index 2b1dd310..5964718a 100644 --- a/services/prioritization_service.py +++ b/services/prioritization_service.py @@ -51,14 +51,9 @@ def get_prioritization_list( Patient, Department.name.label("department"), func.count().over(), - ( - Prescription.features["prescriptionScore"].astext.cast(Integer) - + Prescription.features["av"].astext.cast(Integer) - + Prescription.features["am"].astext.cast(Integer) - + Prescription.features["alertExams"].astext.cast(Integer) - + Prescription.features["alerts"].astext.cast(Integer) - + Prescription.features["diff"].astext.cast(Integer) - ).label("globalScore"), + (Prescription.features["globalScore"].astext.cast(Integer)).label( + "globalScore" + ), ) .outerjoin(Patient, Patient.admissionNumber == Prescription.admissionNumber) .outerjoin( @@ -262,27 +257,13 @@ def get_prioritization_list( if global_score_min != None: q = q.filter( - ( - Prescription.features["prescriptionScore"].astext.cast(Integer) - + Prescription.features["av"].astext.cast(Integer) - + Prescription.features["am"].astext.cast(Integer) - + Prescription.features["alertExams"].astext.cast(Integer) - + Prescription.features["alerts"].astext.cast(Integer) - + Prescription.features["diff"].astext.cast(Integer) - ) + (Prescription.features["globalScore"].astext.cast(Integer)) >= global_score_min ) if global_score_max != None: q = q.filter( - ( - Prescription.features["prescriptionScore"].astext.cast(Integer) - + Prescription.features["av"].astext.cast(Integer) - + Prescription.features["am"].astext.cast(Integer) - + Prescription.features["alertExams"].astext.cast(Integer) - + Prescription.features["alerts"].astext.cast(Integer) - + Prescription.features["diff"].astext.cast(Integer) - ) + (Prescription.features["globalScore"].astext.cast(Integer)) <= global_score_max )