Source code for bqss.bqss.models.documents

import collections
import datetime
import typing
from enum import Enum

# pylint: disable=no-name-in-module
from pydantic import BaseModel, root_validator, validator

##########################
# Document Etablissement #
##########################


[docs] class TailleEnum(str, Enum): """ Valeurs possibles de taille d'établissement """ PETIT = "petit" MOYEN = "moyen" GRAND = "grand"
[docs] class TypeEtablissementEnum(str, Enum): """ Valeurs possibles de type d'établissement """ PUBLIC = "Public" PRIVE = "Privé" PRIVE_NL = "Privé à but non lucratif" CH = "CH" CHU = "CHU" CLCC = "CLCC"
[docs] class ActiviteLibelleEnum(str, Enum): """ Valeurs possibles d'activité d'établissement """ MEDECINE = "Médecine" SSR = "Soins de Suite et de Réadaptation" SLD = "Soins de longue durée" AMP_DPN = ( "Assistance médicale à la procréation - Diagnostic prénatal (AMP-DPN)" ) CANCERO = "Cancérologie" OBSTETRIQUE = "Obstétrique" CHIRURIGE = "Chirurgie" REANIMATION = "Réanimation" NEPHROLOGIE = "Néphrologie" PSYCHATRIE = "Psychiatrie" IMAGERIE = "Imagerie Médicale" DIAGNOSTIC_GENETIQUE = "Diagnostic génétique"
[docs] class ActiviteIdEnum(str, Enum): """ Identifiants d'activité possibles """ MEDECINE = "medecine" SSR = "ssr" SLD = "sld" AMP_DPN = "amp_dpn" CANCERO = "cancerologie" OBSTETRIQUE = "obstetrique" CHIRURIGE = "chirurgie" REANIMATION = "reanimation" NEPHROLOGIE = "nephrologie" PSYCHATRIE = "psychiatrie" IMAGERIE = "imagerie" DIAGNOSTIC_GENETIQUE = "diagnostic_genetique"
[docs] class IQSSSourceEnum(str, Enum): """ Sources possibles des IQSS """ PMSI = "IQSS PMSI" DOSSIER_PATIENT = "IQSS dossier patient" QUESTIONNAIRE_ES = "IQSS questionnaire établissement"
[docs] class ESATISSourceEnum(str, Enum): """ Sources possibles des IQSS questionnaire patient """ QUESTIONNAIRE_PA = "IQSS questionnaire patient"
[docs] class IQSSSecteurEnum(str, Enum): """ Secteurs possibles pour les IQSS """ HAD = "HAD" SSR = "SSR" PSY = "PSY" MHS = "MHS" TCH = "TCH" MCO = "MCO"
[docs] class IQSSThemeEnum(str, Enum): """ Thèmes possibles pour les IQSS """ DIA = "DIA" IDM = "IDM" DPA = "DPA" AVC = "AVC" HPP = "HPP" ETEORTHO = "ETEORTHO" IAS = "IAS" ISOORTHO = "ISOORTHO" CA = "CA" RCP = "RCP" DAN = "DAN" Q48H = "48h" PCC = "PCC" SMHOSP = "SMHOSP"
[docs] class ESATISSecteurEnum(str, Enum): """ Secteurs possibles pour les IQSS questionnaire patient """ MCO = "MCO" SSR = "SSR"
[docs] class ESATISThemeEnum(str, Enum): """ Thèmes possibles pour les IQSS questionnaire patient """ CA = "CA" Q48H = "48h" SSR = "SSR"
[docs] class Certif2021ScoreTypeEnum(str, Enum): """ Type de scores possibles pour la certification 2021 """ DECISION = "decision" CHAPITRE = "chapitre" OBJECTIF = "objectif" DATE_DECISION = "date_decision"
# pylint: disable=too-few-public-methods
[docs] class FinessIdentificationModel(BaseModel): """ Données d'identification de l'établissement """ num_finess_ej: str raison_sociale_et: str raison_sociale_longue_et: typing.Optional[str] raison_sociale_ej: str raison_sociale_longue_ej: typing.Optional[str] date_ouverture: datetime.date statut_juridique: str statut_juridique_ej: int libelle_statut_juridique_ej: str type_etablissement: TypeEtablissementEnum
[docs] class FinessCoordonnesModel(BaseModel): """ Coordonnées de l'établissement """ adresse_postale_ligne_1: typing.Optional[str] adresse_postale_ligne_2: str libelle_commune: str code_postal: str departement: str libelle_departement: str telephone: typing.Optional[str] latitude: typing.Optional[float] longitude: typing.Optional[float]
[docs] class FinessAutorisationModel(BaseModel): """ Données d'autorisation d'activité de l'établissement """ activite: int libelle_activite: str date_mise_en_oeuvre: typing.Optional[datetime.date]
[docs] class FinessActivitesModel(BaseModel): """ Données d'activités pratiquées par l'établissement """ id: ActiviteIdEnum libelle: ActiviteLibelleEnum
class IQSSVariableModel(BaseModel): title: str value: typing.Optional[typing.Union[float, str]] missing_value: typing.Optional[str]
[docs] class IQSSValueModel(BaseModel): """ Données d'un indicateur recueilli pour une année donnée et un établissement donné. Un indicateur peut être constitué d'une ou plusieurs variables. """ annee_recueil: int status: typing.Optional[IQSSVariableModel] resultat: typing.Optional[IQSSVariableModel] classe: typing.Optional[IQSSVariableModel] denominateur: typing.Optional[IQSSVariableModel] positionnement: typing.Optional[IQSSVariableModel] evolution: typing.Optional[IQSSVariableModel] score: typing.Optional[IQSSVariableModel] intervalle_haut: typing.Optional[IQSSVariableModel] intervalle_bas: typing.Optional[IQSSVariableModel] controle: typing.Optional[IQSSVariableModel] obligatoire: typing.Optional[IQSSVariableModel] resultat_min: typing.Optional[IQSSVariableModel] resultat_strict: typing.Optional[IQSSVariableModel] effectif_cible: typing.Optional[IQSSVariableModel] effectif_observe: typing.Optional[IQSSVariableModel] effectif_attendu: typing.Optional[IQSSVariableModel] capacite: typing.Optional[IQSSVariableModel] volumetrie: typing.Optional[IQSSVariableModel]
def check_indicateur_unicity(values): annee_count = collections.Counter(v.annee_recueil for v in values) if annee_count.most_common()[0][1] > 1: raise AssertionError("Année de recueil en doublon") return values
[docs] class FinessIQSSModel(BaseModel): """ Données des IQSS autres que le questionnaire satisfaction patient """ secteur: IQSSSecteurEnum theme: IQSSThemeEnum source: IQSSSourceEnum indicateur: str valeurs: typing.List[IQSSValueModel] _annee_unicity = validator("valeurs", allow_reuse=True)( check_indicateur_unicity )
[docs] class FinessESATISModel(BaseModel): """ Données des IQSS questionnaire statisfaction patient """ secteur: ESATISSecteurEnum theme: ESATISThemeEnum source: ESATISSourceEnum indicateur: str valeurs: typing.List[IQSSValueModel] _annee_unicity = validator("valeurs", allow_reuse=True)( check_indicateur_unicity )
[docs] class FinessCapaciteModel(BaseModel): """ Données de capacité d'activité de l'établissement pour une année """ annee: int key: str title: str value: typing.Union[bool, float, str]
[docs] class FinessVolumetrieModel(BaseModel): """ Données de volumétrie d'activité de l'établissement pour une année """ annee: int key: str title: str value: float
[docs] class FinessCertif2014Model(BaseModel): """ Données de certification du référentiel 2014-2020 """ key: str title: str libelle_thematique: str value: typing.Union[float, str, datetime.date]
[docs] class FinessCertif2021Model(BaseModel): """ Données de certification du référentiel 2021-2025 """ key: str title: str value: typing.Union[float, str, int] score_type: typing.Optional[Certif2021ScoreTypeEnum] chapitre_id: typing.Optional[str] objectif_id: typing.Optional[str] # pylint: disable=no-self-argument
[docs] @root_validator def check_certif_score_type_coherence(cls, values): key = values.get("key") score_type = values.get("score_type") chapitre_id = values.get("chapitre_id") objectif_id = values.get("objectif_id") if "decision" in key and not "date_decision" in key: if score_type != "decision": raise ValueError(f"Incohérence ({score_type=}) et ({key=})") if chapitre_id is not None: raise ValueError( f"({chapitre_id=}) alors qu'il devrait être `None`" " pour une decision" ) if objectif_id is not None: raise ValueError( f"({objectif_id=}) alors qu'il devrait être `None`" " pour une decision" ) if "chapitre" in key: if score_type != "chapitre": raise ValueError(f"Incohérence ({score_type=}) et ({key=})") if objectif_id is not None: raise ValueError( f"({objectif_id=}) alors qu'il devrait être `None`" " pour un chapitre" ) expect_chapitre_id = key.rsplit("_", 1)[-1] if expect_chapitre_id != chapitre_id: raise ValueError( f"{chapitre_id=} mauvaise valeure." f" Valeure attendue: {expect_chapitre_id=}" ) if "objectif" in key: if score_type != "objectif": raise ValueError(f"Incohérence ({score_type=}) et ({key=})") expect_chapitre_id = key.rsplit("_", 1)[-1] expect_chapitre_id, expect_objectif_id = expect_chapitre_id.split( "." ) if expect_chapitre_id != chapitre_id: raise ValueError( f"{chapitre_id=} mauvaise valeure." f" Valeure attendue: {expect_chapitre_id=}" ) if expect_objectif_id != objectif_id: raise ValueError( f"{chapitre_id=} mauvaise valeure." f" Valeure attendue: {objectif_id=}" ) return values
[docs] class FinessDocumentModel(BaseModel): """ Données représentant un FINESS Géographique dans la base document """ finess_geo: str taille: TailleEnum ferme_cette_annee: bool identification: FinessIdentificationModel coordonnees: FinessCoordonnesModel autorisations: typing.List[FinessAutorisationModel] activites: typing.List[FinessActivitesModel] IQSS: typing.List[FinessIQSSModel] satisfaction_patient: typing.List[FinessESATISModel] capacite: typing.List[FinessCapaciteModel] volumetrie: typing.List[FinessVolumetrieModel] certification_v2014: typing.List[FinessCertif2014Model] certification_v2021: typing.Optional[typing.List[FinessCertif2021Model]] # pylint: disable=no-self-argument
[docs] @root_validator() def check_no_empty_data(cls, values): if ( not values["IQSS"] and not values["satisfaction_patient"] and not values["certification_v2014"] and not values["certification_v2021"] ): raise ValueError( f"Aucune donnée HAS pour le finess {values['finess_geo']}" ) return values