267 lines
9.8 KiB
Python
267 lines
9.8 KiB
Python
from enum import Enum
|
|
from typing import Dict, List, Optional, Tuple, Union
|
|
|
|
|
|
from ..models import Administre, CustomUser, Decision, DecisionChoices, Administres_Pams
|
|
from ..models import StatutPamChoices as StatutPam
|
|
from .logging import get_logger
|
|
from .permissions import KEY_WRITE, Profiles, get_profiles_by_adm
|
|
|
|
logger = get_logger(__name__)
|
|
|
|
# clé d'une valeur de l'arbre de décision : choix disponibles
|
|
KEY_CHOICES = 'choices'
|
|
|
|
# clé d'une valeur de l'arbre de décision : profils habilités à modifier le statut
|
|
KEY_PROFILES = 'editable_by'
|
|
|
|
# clé d'un élément de "get_available_decisions" : pour une création
|
|
KEY_CREATE = 'creation'
|
|
|
|
# clé d'un élément de "get_available_decisions" : pour une mise à jour
|
|
KEY_UPDATE = 'update'
|
|
|
|
class ExtraDecisions(str, Enum):
|
|
""" décisions en plus """
|
|
|
|
EMPTY = ''
|
|
|
|
def __repr__(self):
|
|
return self.__str__()
|
|
|
|
|
|
def __init_decisions():
|
|
D = DecisionChoices
|
|
EX = ExtraDecisions
|
|
P = Profiles
|
|
return {
|
|
# === commun ===
|
|
|
|
None: {
|
|
KEY_PROFILES: (P.FILIERE, P.BVT),
|
|
KEY_CHOICES: (D.PROPOSITION_FE, D.HME_PROPOSITION_VIVIER)
|
|
},
|
|
D.REMIS_A_DISPOSITION: {
|
|
KEY_PROFILES: (P.FILIERE,),
|
|
KEY_CHOICES: (EX.EMPTY,),
|
|
},
|
|
|
|
# === en métropole ===
|
|
|
|
D.PROPOSITION_FE: {
|
|
KEY_PROFILES: (P.PCP, P.PCP_ACTUEL),
|
|
KEY_CHOICES: (D.DIALOGUE_EN_COURS, D.FOREMP_EN_COURS)
|
|
},
|
|
D.DIALOGUE_EN_COURS: {
|
|
KEY_PROFILES: (P.PCP, P.PCP_ACTUEL,),
|
|
KEY_CHOICES: (D.DIALOGUE_TERMINE, D.DIALOGUE_INFRUCTUEUX)
|
|
},
|
|
D.DIALOGUE_TERMINE: {
|
|
KEY_PROFILES: (P.PCP, P.PCP_ACTUEL,),
|
|
KEY_CHOICES: (D.FOREMP_EN_COURS,)
|
|
},
|
|
D.DIALOGUE_INFRUCTUEUX: {
|
|
KEY_PROFILES: (P.PCP, P.PCP_ACTUEL,),
|
|
KEY_CHOICES: (D.FOREMP_EN_COURS, D.REMIS_A_DISPOSITION)
|
|
},
|
|
D.FOREMP_EN_COURS: {
|
|
KEY_PROFILES: (P.PCP, P.PCP_ACTUEL,),
|
|
KEY_CHOICES: (D.FOREMP_TERMINE,)
|
|
},
|
|
D.FOREMP_TERMINE: {
|
|
KEY_PROFILES: (P.PCP, P.PCP_ACTUEL,),
|
|
KEY_CHOICES: (D.PREPOSITIONNE, D.REMIS_A_DISPOSITION)
|
|
},
|
|
D.PREPOSITIONNE: {
|
|
KEY_PROFILES: (P.PCP, P.PCP_FUTUR,),
|
|
KEY_CHOICES: (D.POSITIONNE, D.REMIS_A_DISPOSITION)
|
|
},
|
|
D.POSITIONNE: {
|
|
KEY_PROFILES: (P.PCP, P.PCP_FUTUR,),
|
|
KEY_CHOICES: (D.OMIP_EN_COURS, D.OMI_EN_COURS, D.REMIS_A_DISPOSITION)
|
|
},
|
|
D.OMIP_EN_COURS: {
|
|
KEY_PROFILES: (P.PCP, P.PCP_FUTUR,),
|
|
KEY_CHOICES: (D.OMIP_TERMINE, D.REMIS_A_DISPOSITION),
|
|
},
|
|
D.OMIP_TERMINE: {
|
|
KEY_PROFILES: (P.PCP, P.PCP_FUTUR,),
|
|
KEY_CHOICES: (D.ATTENTE_AVIONAGE, D.OMI_EN_COURS, D.REMIS_A_DISPOSITION),
|
|
},
|
|
D.ATTENTE_AVIONAGE: {
|
|
KEY_PROFILES: (P.PCP, P.PCP_FUTUR,),
|
|
KEY_CHOICES: (D.OMI_EN_COURS,),
|
|
},
|
|
D.OMI_EN_COURS: {
|
|
KEY_PROFILES: (P.PCP, P.PCP_FUTUR,),
|
|
KEY_CHOICES: (D.OMI_ACTIVE, D.REMIS_A_DISPOSITION),
|
|
},
|
|
D.OMI_ACTIVE: {
|
|
KEY_PROFILES: (P.PCP, P.PCP_FUTUR,),
|
|
KEY_CHOICES: (D.OMI_ANNULE,),
|
|
},
|
|
D.OMI_ANNULE: {
|
|
KEY_PROFILES: (P.PCP, P.PCP_FUTUR,),
|
|
KEY_CHOICES: (D.REMIS_A_DISPOSITION,),
|
|
},
|
|
|
|
# === hors métropole (HME) ===
|
|
|
|
D.HME_PROPOSITION_VIVIER: {
|
|
KEY_PROFILES: (P.PCP, P.PCP_ACTUEL, P.PCP_FUTUR),
|
|
KEY_CHOICES: (D.HME_DIALOGUE_INITIE,)
|
|
},
|
|
D.HME_ETUDE_DESISTEMENT: {
|
|
KEY_PROFILES: (P.PCP, P.PCP_ACTUEL, P.PCP_FUTUR),
|
|
KEY_CHOICES: (D.HME_DESISTEMENT,)
|
|
},
|
|
D.HME_DESISTEMENT: {
|
|
KEY_PROFILES: (P.PCP, P.PCP_ACTUEL, P.PCP_FUTUR),
|
|
KEY_CHOICES: (D.REMIS_A_DISPOSITION,)
|
|
},
|
|
D.HME_DIALOGUE_INITIE: {
|
|
KEY_PROFILES: (P.PCP, P.PCP_ACTUEL, P.PCP_FUTUR),
|
|
KEY_CHOICES: (D.HME_DIALOGUE_EN_COURS,)
|
|
},
|
|
D.HME_DIALOGUE_EN_COURS: {
|
|
KEY_PROFILES: (P.PCP, P.PCP_ACTUEL, P.PCP_FUTUR),
|
|
KEY_CHOICES: (D.HME_DIALOGUE_TERMINE, D.HME_DIALOGUE_INFRUCTUEUX)
|
|
},
|
|
D.HME_DIALOGUE_TERMINE: {
|
|
KEY_PROFILES: (P.PCP, P.PCP_ACTUEL, P.PCP_FUTUR),
|
|
KEY_CHOICES: (D.HME_PREPOSITIONNE,)
|
|
},
|
|
D.HME_DIALOGUE_INFRUCTUEUX: {
|
|
KEY_PROFILES: (P.PCP, P.PCP_ACTUEL, P.PCP_FUTUR),
|
|
KEY_CHOICES: (D.HME_ETUDE_DESISTEMENT, D.HME_PREPOSITIONNE, D.REMIS_A_DISPOSITION)
|
|
},
|
|
D.HME_FOREMP_EN_COURS: {
|
|
KEY_PROFILES: (P.PCP, P.PCP_ACTUEL, P.PCP_FUTUR),
|
|
KEY_CHOICES: (D.HME_FOREMP_TERMINE, D.HME_OMI_EN_COURS)
|
|
},
|
|
D.HME_FOREMP_TERMINE: {
|
|
KEY_PROFILES: (P.PCP, P.PCP_ACTUEL, P.PCP_FUTUR),
|
|
KEY_CHOICES: (D.HME_OMIP_EN_COURS, D.HME_OMI_EN_COURS)
|
|
},
|
|
D.HME_PREPOSITIONNE: {
|
|
KEY_PROFILES: (P.HME,),
|
|
KEY_CHOICES: (D.HME_VALIDATION_EXPERT, D.HME_REFUS_EXPERT)
|
|
},
|
|
D.HME_VALIDATION_EXPERT: {
|
|
KEY_PROFILES: (P.PCP, P.PCP_ACTUEL, P.PCP_FUTUR),
|
|
KEY_CHOICES: (D.HME_POSITIONNE,)
|
|
},
|
|
D.HME_POSITIONNE: {
|
|
KEY_PROFILES: (P.PCP, P.PCP_ACTUEL, P.PCP_FUTUR),
|
|
KEY_CHOICES: (D.HME_OMIP_EN_COURS, D.HME_OMI_EN_COURS, D.HME_FOREMP_EN_COURS)
|
|
},
|
|
D.HME_REFUS_EXPERT: {
|
|
KEY_PROFILES: (P.PCP, P.PCP_ACTUEL, P.PCP_FUTUR),
|
|
KEY_CHOICES: (D.HME_PREPOSITIONNE, D.REMIS_A_DISPOSITION),
|
|
},
|
|
D.HME_OMIP_EN_COURS: {
|
|
KEY_PROFILES: (P.PCP, P.PCP_ACTUEL, P.PCP_FUTUR),
|
|
KEY_CHOICES: (D.HME_OMIP_TERMINE,),
|
|
},
|
|
D.HME_OMIP_TERMINE: {
|
|
KEY_PROFILES: (P.PCP, P.PCP_ACTUEL, P.PCP_FUTUR),
|
|
KEY_CHOICES: (D.HME_ATTENTE_AVIONAGE, D.HME_OMI_EN_COURS),
|
|
},
|
|
D.HME_ATTENTE_AVIONAGE: {
|
|
KEY_PROFILES: (P.PCP, P.PCP_ACTUEL, P.PCP_FUTUR),
|
|
KEY_CHOICES: (D.HME_OMI_EN_COURS,),
|
|
},
|
|
D.HME_OMI_EN_COURS: {
|
|
KEY_PROFILES: (P.PCP, P.PCP_ACTUEL, P.PCP_FUTUR),
|
|
KEY_CHOICES: (D.HME_OMI_ACTIVE,),
|
|
},
|
|
D.HME_OMI_ACTIVE: {
|
|
KEY_PROFILES: (P.PCP, P.PCP_FUTUR,),
|
|
KEY_CHOICES: (D.HME_OMI_ANNULE,),
|
|
},
|
|
D.HME_OMI_ANNULE: {
|
|
KEY_PROFILES: (P.PCP, P.PCP_FUTUR,),
|
|
KEY_CHOICES: (D.REMIS_A_DISPOSITION,),
|
|
},
|
|
}
|
|
|
|
|
|
# enchaînement des décisions
|
|
DECISIONS = __init_decisions()
|
|
|
|
|
|
def get_all_decisions() -> Tuple[DecisionChoices]:
|
|
"""
|
|
Renvoie tous les statuts de décisions possibles. Une décision vide correspondrait à une absence de décision et n'est donc pas présente.
|
|
|
|
:return: toutes les décisions
|
|
:rtype: Tuple[DecisionChoices]
|
|
"""
|
|
return tuple(DecisionChoices)
|
|
|
|
|
|
def get_available_decisions(
|
|
administres: Union[List[Administres_Pams], Tuple[Administres_Pams]],
|
|
user: CustomUser = None,
|
|
profiles_by_adm: Dict[int, Tuple[Profiles]] = None
|
|
) -> Dict[int, Dict[str, Tuple[Union[DecisionChoices, ExtraDecisions]]]]:
|
|
"""
|
|
Renvoie les décisions disponibles pour l'utilisateur s'il modifie le statut de décision des administrés donnés.
|
|
|
|
:param administres: Administres_Pams
|
|
:type administres: Union[List[Administres_Pams], Tuple[Administres_Pams]]
|
|
|
|
:param user: utilisateur
|
|
:type user: class:`CustomUser`, optional
|
|
|
|
:param profiles_by_adm: profils pour chaque administré (voir get_profiles_by_adm)
|
|
:type profiles_by_adm: Dict[int, Tuple[Profiles]], optional
|
|
|
|
:return: dictionnaire de dictionnaires {<ID SAP>: {<KEY_CREATE>: <décisions>, <KEY_UPDATE>: <décisions>} }
|
|
:rtype: Dict[int, Dict[str, Tuple[Union[DecisionChoices, ExtraDecisions]]]]
|
|
"""
|
|
pam_without_decision = tuple(x for x in StatutPam if not x.dec_enabled)
|
|
pam_with_decision = tuple(x for x in StatutPam if x.dec_enabled)
|
|
result = {}
|
|
|
|
# restrictions : dictionnaire de dictionnaires {<ID SAP>: <même forme qu'une valeur de DECISIONS>}
|
|
restrictions_create_by_adm = {}
|
|
restrictions_update_by_adm = {}
|
|
|
|
adm_to_process = []
|
|
for adm in administres:
|
|
adm_id = adm.pk
|
|
pam = adm.a_statut_pam_annee
|
|
if pam in pam_without_decision:
|
|
# le statut PAM ne permet aucun choix
|
|
result[adm_id] = {KEY_CREATE: (), KEY_UPDATE: ()}
|
|
elif pam in pam_with_decision:
|
|
# le statut PAM active l'arbre de décisions
|
|
adm_to_process.append(adm)
|
|
statut_decision = adm.decision.de_decision or None if hasattr(adm, Administres_Pams.Cols.REL_DECISION) else None
|
|
restrictions_update_by_adm[adm_id] = DECISIONS.get(statut_decision) or {}
|
|
else:
|
|
logger.info('statut PAM non géré pour les décisions possibles : %s', pam)
|
|
result[adm_id] = {KEY_CREATE: (), KEY_UPDATE: ()}
|
|
|
|
if adm_to_process:
|
|
default_restrictions_create = DECISIONS.get(None) or {}
|
|
|
|
def get_decisions(profiles, restrictions) -> Tuple[Union[DecisionChoices, ExtraDecisions]]:
|
|
allowed_profiles = restrictions.get(KEY_PROFILES) or ()
|
|
choices = restrictions.get(KEY_CHOICES)
|
|
decisions = ()
|
|
if choices and any(p in allowed_profiles for p in profiles):
|
|
decisions = tuple(choices)
|
|
return decisions
|
|
|
|
_profiles_by_adm = profiles_by_adm or get_profiles_by_adm(user, *adm_to_process)
|
|
for adm in adm_to_process:
|
|
adm_id = adm.pk
|
|
profiles = (_profiles_by_adm.get(adm_id) or {}).get(KEY_WRITE) or ()
|
|
result.setdefault(adm_id, {
|
|
KEY_CREATE: get_decisions(profiles, restrictions_create_by_adm.get(adm_id) or default_restrictions_create),
|
|
KEY_UPDATE: get_decisions(profiles, restrictions_update_by_adm.get(adm_id) or {})
|
|
})
|
|
return result
|