1464 lines
70 KiB
Python
1464 lines
70 KiB
Python
from ast import For
|
|
import time
|
|
from datetime import date
|
|
#from tkinter.tix import Form
|
|
|
|
import numpy as np
|
|
import pandas as pd
|
|
from django.db.models import Case, IntegerField, Prefetch, Sum, When
|
|
from django.db.transaction import atomic
|
|
from django.forms import model_to_dict
|
|
from django.http import Http404, JsonResponse
|
|
from django.shortcuts import get_object_or_404
|
|
from django_filters.rest_framework import DjangoFilterBackend
|
|
from rest_framework import status, viewsets
|
|
from rest_framework.exceptions import APIException
|
|
from rest_framework.permissions import IsAdminUser, IsAuthenticated
|
|
from rest_framework.response import Response
|
|
from rest_framework.views import APIView
|
|
from django.db.models import Q
|
|
|
|
|
|
|
|
from .. import constants
|
|
from ..filters import AdministreFilter, AdministrePAMFilter, PosteFilter, PostePAMFilter, RelatedOrderingFilter
|
|
from ..models import (FMOB, Administre, Decision, DecisionChoices, Domaine,
|
|
Filiere, FormationEmploi, Marque, MarquesGroupe,
|
|
PcpFeGroupe, Poste, PreferencesListe, SousVivier,
|
|
SousVivierAssociation, SpecifiqueChoices, Administres_Pams, StatutPamChoices as StatutPam,
|
|
Postes_Pams,PAM)
|
|
from ..paginations import HeavyDataPagination
|
|
from ..reporting import (reporting_suivi_pam_admin, reporting_suivi_pam_poste,
|
|
reporting_taux_armement_gestionnaire,
|
|
reporting_taux_armement_pcp)
|
|
from ..serializers import (CTX_KEY_DECISIONS, CTX_KEY_PROFILES,
|
|
AdministreSerializer,
|
|
AdministresPamsSerializer,
|
|
AlimentationReferentielSerializer,
|
|
DomaineSerializer, FileSVSerializer,
|
|
FiliereSerializer, FmobSerializer, MarqueSerializer,
|
|
MarquesGroupeSerializer, PcpFeGroupeSerializer,
|
|
PosteSerializer, SousVivierAssociationSerializer,
|
|
PostesPamsSerializer)
|
|
from ..utils import sous_viviers_du_cellule, without_keys, generate_sv_id, nf2categorie
|
|
from ..utils.decisions import get_available_decisions
|
|
from ..utils.decorators import class_logger
|
|
from ..utils.permissions import get_profiles_by_adm
|
|
from ..utils_extraction import (DataFrameTypes, FileTypes, open_excel,
|
|
read_files_by_type)
|
|
from .commun import (GestionnairePermission, execution_time_viewset,
|
|
query_count_viewset)
|
|
|
|
|
|
# Vue de calcul des indicateurs
|
|
# Renvoie les indicateurs pour les vues :
|
|
# - taux armement FE pour les PCP
|
|
# - taux armement FE pour les gestionnaires
|
|
# - suivi pam des gestionnaires pour les administrés
|
|
# - suivi pam des gestionnaires pour les postes
|
|
@class_logger
|
|
@execution_time_viewset
|
|
@query_count_viewset
|
|
class ReportingView(APIView):
|
|
"""
|
|
Cette classe est dédiée au vue du calcul des indicateurs
|
|
- taux armement FE pour les PCP
|
|
- taux armement FE pour les gestionnaires
|
|
- suivi pam des gestionnaires pour les administrés
|
|
- suivi pam des gestionnaires pour les postes
|
|
|
|
"""
|
|
permission_classes = [IsAuthenticated, GestionnairePermission]
|
|
|
|
def __str__(self):
|
|
return 'ReportingView'
|
|
|
|
def get(self, request):
|
|
"""La fonction get renvoie les indicateurs
|
|
|
|
:type request: rest_framework.request.Request
|
|
:param request: Request contenant le type, sous_vivier id, niveau fonctinonel et l'id de la formation emploi.
|
|
|
|
:return: - **return** (*json*): Si le type est SUIVI_PAM_GESTIONNAIRE le json contiendra l'information sur le suivi pam des
|
|
gestionnaires pour les administrés et les postes. Si le type est TAUX_ARMEMENT_FE le json contiendra les indicateurs sur les taux d'armement.
|
|
|
|
|
|
"""
|
|
type = request.query_params["type"]
|
|
|
|
sv_id = []
|
|
if 'sv_id' in request.query_params:
|
|
sv_id = request.query_params["sv_id"]
|
|
|
|
if 'vue' in request.query_params:
|
|
vue = request.query_params["vue"]
|
|
|
|
if "nf" in request.query_params:
|
|
nf = request.query_params.getlist("nf")
|
|
else:
|
|
nf = ['1A', '1B', '1C', '2.', '3A', '3B', '3B NFS', '4.', '5A', '5B', '5C', '6A', '6B']
|
|
|
|
if 'fe_id' in request.query_params: # a voir
|
|
fe_id = request.query_params.getlist('fe_id')
|
|
else:
|
|
fe_id = list(FormationEmploi.objects.values_list('fe_code', flat=True))
|
|
|
|
# Vues pour les indicateurs sur le suivi du pam
|
|
if (type == "SUIVI_PAM_GESTIONNAIRE"):
|
|
if "d_code" in request.query_params:
|
|
d_id = request.query_params.getlist("d_code")
|
|
else:
|
|
filieres = list(SousVivierAssociation.objects.filter(sous_vivier__sv_id=sv_id).values_list('filiere_id',
|
|
flat=True).distinct())
|
|
d_id = list(Filiere.objects.filter(f_code__in=filieres).values_list('domaine_id', flat=True).distinct())
|
|
if "f_code" in request.query_params:
|
|
f_id = request.query_params.getlist("f_code")
|
|
else:
|
|
f_id = list(SousVivierAssociation.objects.filter(sous_vivier__sv_id=sv_id).values_list('filiere_id',
|
|
flat=True).distinct())
|
|
if "categorie" in request.query_params:
|
|
categorie = request.query_params.getlist("categorie")
|
|
else:
|
|
categorie = list(
|
|
SousVivierAssociation.objects.filter(sous_vivier__sv_id=sv_id).values_list('sva_categorie',
|
|
flat=True).distinct())
|
|
# résultats pour la vue suivi pam des gestionnaires pour les administrés
|
|
nb_a_etudier, nb_a_muter, nb_a_maintenir, nb_non_etudie_administres, nb_a_partant, nb_a_non_dispo, nb_prepos_administres, nb_pos_administres, nb_omi_active_administres, nb_omi_en_cours_administres, reste_a_realiser_administres, reste_a_realiser_a_etudier, reste_a_realiser_a_muter = reporting_suivi_pam_admin(
|
|
sv_id, f_id, d_id, nf, categorie)
|
|
# résultats pour la vue suivi pam des gestionnaires pour les postes
|
|
nb_p1, nb_p2, nb_p3, nb_p4, nb_gele, nb_non_etudie_postes, reste_a_realiser_postes, reste_a_realiser_p1, reste_a_realiser_p2, reste_a_realiser_p3, reste_a_realiser_p4, nb_prepos_postes, nb_pos_postes, nb_omi_active_postes, nb_omi_en_cours_postes = reporting_suivi_pam_poste(
|
|
sv_id, f_id, d_id, nf, categorie)
|
|
return JsonResponse(
|
|
{"nb_a_etudier": nb_a_etudier, "nb_a_muter": nb_a_muter, "nb_a_maintenir": nb_a_maintenir,
|
|
"nb_a_partant": nb_a_partant, "nb_a_non_dispo": nb_a_non_dispo,
|
|
"nb_non_etudie_administres": nb_non_etudie_administres,
|
|
"nb_prepos_administres": nb_prepos_administres, "nb_pos_administres": nb_pos_administres,
|
|
"nb_omi_en_cours_administres": nb_omi_en_cours_administres,
|
|
"nb_omi_active_administres": nb_omi_active_administres,
|
|
"reste_a_realiser_administres": reste_a_realiser_administres,
|
|
"reste_a_realiser_a_etudier": reste_a_realiser_a_etudier,
|
|
"reste_a_realiser_a_muter": reste_a_realiser_a_muter,
|
|
"nb_p1": nb_p1, "nb_p2": nb_p2, "nb_p3": nb_p3, "nb_p4": nb_p4, "nb_gele": nb_gele,
|
|
"nb_non_etudie_postes": nb_non_etudie_postes, "reste_a_realiser_postes": reste_a_realiser_postes,
|
|
"reste_a_realiser_p1": reste_a_realiser_p1, "reste_a_realiser_p2": reste_a_realiser_p2,
|
|
"reste_a_realiser_p3": reste_a_realiser_p3, "reste_a_realiser_p4": reste_a_realiser_p4,
|
|
"nb_prepos_postes": nb_prepos_postes, "nb_pos_postes": nb_pos_postes,
|
|
"nb_omi_en_cours_postes": nb_omi_en_cours_postes, "nb_omi_active_postes": nb_omi_active_postes},
|
|
safe=False)
|
|
# Vues pour les indicateurs sur les taux d'armement
|
|
elif (type == 'TAUX_ARMEMENT_FE'):
|
|
if "d_code" in request.query_params:
|
|
d_id = request.query_params.getlist("d_code")
|
|
else:
|
|
d_id = list(Domaine.objects.all().values_list('d_code', flat=True))
|
|
if "f_code" in request.query_params:
|
|
f_id = request.query_params.getlist("f_code")
|
|
else:
|
|
f_id = list(Filiere.objects.all().values_list('f_code', flat=True))
|
|
if "categorie" in request.query_params:
|
|
categorie = request.query_params.getlist("categorie")
|
|
else:
|
|
categorie = ['MDR', 'SOFF', 'OFF', 'OGX']
|
|
|
|
if len(sv_id) == 0:
|
|
# résultats pour la vue taux armement FE pour les PCP
|
|
nb_militaires_actuel, nb_postes_actuel, ecart_actuel, taux_armement_actuel, nb_militaires_entrants, nb_militaires_sortants, nb_militaires_projete, taux_armement_projete, taux_armement_cible = reporting_taux_armement_pcp(
|
|
fe_id, f_id, d_id, nf, categorie)
|
|
else:
|
|
# résultats pour la vue taux armement FE pour les gestionnaires
|
|
nb_militaires_actuel, nb_postes_actuel, ecart_actuel, taux_armement_actuel, nb_militaires_entrants, nb_militaires_sortants, nb_militaires_projete, taux_armement_projete, taux_armement_cible = reporting_taux_armement_gestionnaire(
|
|
fe_id, f_id, d_id, nf, categorie, sv_id)
|
|
return JsonResponse({'nb_militaires_actuel': nb_militaires_actuel, "nb_postes_actuel": nb_postes_actuel,
|
|
'ecart_actuel': ecart_actuel, 'taux_armement_actuel': taux_armement_actuel,
|
|
'nb_militaires_entrants': nb_militaires_entrants,
|
|
'nb_militaires_sortants': nb_militaires_sortants,
|
|
'nb_militaires_projete': nb_militaires_projete,
|
|
'taux_armement_projete': taux_armement_projete,
|
|
'taux_armement_cible': taux_armement_cible}, safe=False)
|
|
else:
|
|
return JsonResponse({"autre vue": "autres indicateurs demandes"})
|
|
|
|
|
|
# TODO : Supprimer cette vue qui n'est plus utilisée
|
|
# Vue de chargement des sous-viviers :
|
|
# - Charge et traite le fichier de définition des sous-viviers
|
|
# - Attribue les sous-viviers présents aux administrés et postes correspondants
|
|
@class_logger
|
|
@execution_time_viewset
|
|
@query_count_viewset
|
|
class ChargementSVView(APIView):
|
|
"""
|
|
Cette classe est dédiée au vue de chargement des sous-viviers. Charge et traite le fichier de définition des sous-viviers et attribue les sous-viviers présents aux administrés et postes correspondants
|
|
"""
|
|
permission_classes = [IsAuthenticated, GestionnairePermission]
|
|
|
|
serializer_class = FileSVSerializer
|
|
|
|
def get(self, request):
|
|
"""La fonction get renvoie une reponse contenant ok
|
|
|
|
:type request: rest_framework.request.Request
|
|
:param request: Requset
|
|
|
|
|
|
:return: - **return** (*json*): json contenant "ok".
|
|
"""
|
|
return Response({"get": "ok"})
|
|
|
|
def post(self, request):
|
|
"""La fonction post charge les sous-viviers
|
|
|
|
:type request: rest_framework.request.Request
|
|
:param request: Request contenant le fichier SV
|
|
|
|
:return: - **Response** (*Response*): Reponse contient la liste des sous-viviers créés, ignorés et où il y a eu une erreur.
|
|
"""
|
|
serializer = FileSVSerializer(data=request.data)
|
|
|
|
if not serializer.is_valid():
|
|
return Response(
|
|
data=serializer.errors,
|
|
status=status.HTTP_400_BAD_REQUEST
|
|
)
|
|
|
|
sv_file = request.data['SV']
|
|
|
|
sv_df = open_excel(sv_file, sheetname="GESTIONNAIRES", engine='openpyxl')
|
|
|
|
sv = pd.DataFrame(columns=['gestionnaire_id_sap', 'f_code', 'asso_sv_categorie', 'arme'])
|
|
|
|
for i in range(len(sv_df)):
|
|
sv.loc[i] = [sv_df.iloc[i, 0], sv_df.iloc[i, 3], sv_df.iloc[i, 4], sv_df.iloc[i, 5]]
|
|
|
|
sv.dropna(subset=['f_code'], inplace=True)
|
|
sv['arme'] = sv['arme'].replace({np.nan: None})
|
|
sv.reset_index(drop=True, inplace=True)
|
|
sv['asso_sv_categorie'].replace({"SOUS-OFFICIER": "SOFF", "OFFICIER": "OFF", "MILITAIRE DU RANG": "MDR"},
|
|
inplace=True)
|
|
sv['sv_id'] = sv.f_code + '_' + sv.asso_sv_categorie
|
|
sv.f_code = sv.f_code.apply(lambda x: x.split(','))
|
|
sv = sv.explode(column='f_code')
|
|
sv.reset_index(drop=True, inplace=True)
|
|
errors = []
|
|
created = []
|
|
ignored = []
|
|
sv.fillna(np.nan, inplace=True)
|
|
sv.replace([np.nan], [None], inplace=True)
|
|
self.logger.debug(sv.head())
|
|
|
|
for i in range(len(sv)):
|
|
try:
|
|
filiere = Filiere.objects.get(f_code=sv.at[i, "f_code"])
|
|
categorie = sv.at[i, "asso_sv_categorie"]
|
|
asso_sv = SousVivierAssociation.objects.filter(sva_categorie=categorie,
|
|
filiere__f_code=sv.at[i, "f_code"])
|
|
|
|
# Vérifier que filiere et catégorie n'ont pas déjà de sous vivier
|
|
if asso_sv.count() == 0 and categorie is not None:
|
|
# Créer le sous-vivier correspondant dans la table SousVivier
|
|
sous_vivier = SousVivier(sv_id=sv.at[i, "sv_id"],
|
|
sv_libelle=str(sv.at[i, "sv_id"]))
|
|
self.logger.debug(model_to_dict(sous_vivier))
|
|
sous_vivier.save()
|
|
|
|
self.logger.debug(sv.at[i, "sv_id"])
|
|
|
|
# Insertion du nouveau sous-vivier dans la table d'association (sans le droit arme dans un premier temps)
|
|
sva = SousVivierAssociation(sva_id=i, sous_vivier_id=sous_vivier.sv_id, filiere_id=filiere.f_code,
|
|
sva_categorie=categorie, sva_arme=sv.at[i, "arme"])
|
|
sva.save()
|
|
|
|
# Mise à jour du sous_vivier_id pour les postes et administres ayant la filiere et la categorie en cours
|
|
Administre.objects.filter(a_categorie=categorie, a_filiere_id=filiere.f_code).update(
|
|
sous_vivier_id=sous_vivier.sv_id)
|
|
|
|
# En fonction du fichier excel, changer la mise à jour du sous_vivier
|
|
Poste.objects.filter(p_categorie=categorie, p_filiere_id=filiere.f_code).sous_viviers.set([sous_vivier.sv_id])
|
|
created.append(str(sv.at[i, "asso_sv_categorie"]) + " " + str(sv.at[i, "f_code"]))
|
|
|
|
else:
|
|
ignored.append(str(sv.at[i, "asso_sv_categorie"]) + " " + str(sv.at[i, "f_code"]))
|
|
# Si l'association appartient déjà à un sous_vivier, on ne fait rien
|
|
except Filiere.DoesNotExist:
|
|
errors.append("Filiere " + sv.at[i, 'f_code'] + "non retrouvée")
|
|
|
|
return Response({"created": created, "ignored": ignored, "errors": errors})
|
|
|
|
|
|
|
|
@class_logger
|
|
@execution_time_viewset
|
|
@query_count_viewset
|
|
class AlimentationReferentielView(APIView):
|
|
""" Vue pour alimenter la base à partir de référentiels """
|
|
|
|
permission_classes = [IsAuthenticated, IsAdminUser]
|
|
serializer_class = AlimentationReferentielSerializer
|
|
|
|
def get(self, request):
|
|
return Response("Formulaire d'alimentation d'OGURE NG (référentiel)")
|
|
|
|
@atomic
|
|
def post(self, request):
|
|
"""
|
|
Charge le(s) fichier(s) et met à jour la base.
|
|
|
|
:param request: requête, contient les fichiers
|
|
:type request: class:`rest_framework.request.Request`
|
|
|
|
:raises: class:`rest_framework.exceptions.APIException`
|
|
:return: réponse
|
|
:rtype: class:`rest_framework.response.Response`
|
|
"""
|
|
|
|
try:
|
|
validator = self.serializer_class(data=request.data)
|
|
validator.is_valid(raise_exception=True)
|
|
|
|
# récupération des fichiers
|
|
referentiel_fe = validator.validated_data.get('referentiel_fe')
|
|
|
|
if referentiel_fe:
|
|
Cols = FormationEmploi.Cols
|
|
col_pk = Cols.PK
|
|
col_pk_mere = Cols.REL_MERE
|
|
col_libelle_mere = Cols.LIBELLE
|
|
col_zone_def = Cols.ZONE_DEFENSE
|
|
|
|
def process_referentiel_fe(referentiel) -> pd.DataFrame:
|
|
"""
|
|
Fonction de lecture du référentiel de FE.
|
|
|
|
:param referentiel: Fichier du référentiel FE
|
|
:type referentiel: XLSX
|
|
|
|
:return: DataFrame
|
|
:rtype: class:`pandas.DataFrame`
|
|
"""
|
|
return open_excel(referentiel, sheetname=0, engine='openpyxl')
|
|
|
|
def convertir_fe(df: pd.DataFrame) -> pd.DataFrame:
|
|
"""
|
|
Fonction de conversion du DataFrame de FE.
|
|
|
|
:param df: DataFrame du référentiel FE
|
|
:type df: class:`pandas.DataFrame`
|
|
|
|
:return: DataFrame
|
|
:rtype: class:`pandas.DataFrame`
|
|
"""
|
|
|
|
col_pk_avant = 'FE CREDO' # B
|
|
col_pk_mere_avant = 'FE mère CREDO' # D
|
|
col_libelle_mere_avant = 'FE mère LA' # E
|
|
col_zone_def_avant = 'Zone de Défense' # O
|
|
|
|
return (
|
|
df[[col_pk_avant, col_pk_mere_avant, col_libelle_mere_avant, col_zone_def_avant]]
|
|
.drop_duplicates(subset=col_pk_avant, keep='first')
|
|
.rename(columns={
|
|
col_pk_avant: col_pk,
|
|
col_pk_mere_avant: col_pk_mere,
|
|
col_libelle_mere_avant: col_libelle_mere,
|
|
col_zone_def_avant: col_zone_def
|
|
})
|
|
.astype({col_pk: 'str', col_pk_mere: 'str'})
|
|
)
|
|
|
|
def mettre_a_jour_fe(df: pd.DataFrame) -> None:
|
|
"""
|
|
Met à jour les FE base à partir du DataFrame de FE.
|
|
|
|
:param df: DataFrame du référentiel FE
|
|
:type df: class:`pandas.DataFrame`
|
|
|
|
:return: DataFrame
|
|
:rtype: class:`pandas.DataFrame`
|
|
"""
|
|
|
|
TypeModele = FormationEmploi
|
|
Cols = TypeModele.Cols
|
|
champs_maj = (Cols.REL_MERE, Cols.ZONE_DEFENSE)
|
|
modeles_en_base = {m.pk: m for m in TypeModele.objects.select_related(Cols.REL_MERE).only('pk', *champs_maj)}
|
|
|
|
taille_batch = 100
|
|
dict_update = {}
|
|
dict_mere_create = {}
|
|
error_count = 0
|
|
for idx, rec in enumerate(df.to_dict('records')):
|
|
pk = rec.get(col_pk)
|
|
try:
|
|
id_mere = rec.get(col_pk_mere)
|
|
zone_defense = rec.get(col_zone_def)
|
|
|
|
en_base = modeles_en_base.get(pk)
|
|
|
|
# TODO pas de création pour l'instant (ni de suppression) quand en_base est falsy
|
|
if en_base:
|
|
mere = None
|
|
if id_mere is not None:
|
|
mere = modeles_en_base.get(id_mere) or dict_mere_create.get(id_mere)
|
|
if not mere:
|
|
try:
|
|
# les FE mères manquantes seront créées
|
|
mere = TypeModele(pk=id_mere, fe_libelle=rec.get(col_libelle_mere))
|
|
except Exception as e:
|
|
raise RuntimeError(f'la création d\'un modèle de type "{TypeModele.__name__}" (mère) a échoué') from e
|
|
dict_mere_create.setdefault(id_mere, mere)
|
|
|
|
if mere != getattr(en_base, Cols.REL_MERE, None) or zone_defense != getattr(en_base, Cols.ZONE_DEFENSE, None):
|
|
try:
|
|
modele = TypeModele(pk=pk, mere=mere, zone_defense=zone_defense)
|
|
except Exception as e:
|
|
raise RuntimeError(f'la création d\'un modèle de type "{TypeModele.__name__}" a échoué') from e
|
|
dict_update.setdefault(pk, modele)
|
|
except Exception:
|
|
error_count = error_count + 1
|
|
self.logger.exception('%s une erreur est survenue à la ligne : %s (pk=%s)', TypeModele.__name__, idx, pk)
|
|
|
|
if error_count:
|
|
self.logger.warning("%s(s) en erreur : %s", TypeModele.__name__, error_count)
|
|
|
|
if dict_mere_create:
|
|
TypeModele.objects.bulk_create(dict_mere_create.values(), batch_size=taille_batch)
|
|
self.logger.info('%s(s) mères créée(s) : %s', TypeModele.__name__, len(dict_mere_create))
|
|
|
|
if dict_update and champs_maj:
|
|
TypeModele.objects.bulk_update(dict_update.values(), batch_size=taille_batch, fields=champs_maj)
|
|
self.logger.info('%s(s) mise(s) à jour : %s', TypeModele.__name__, len(dict_update))
|
|
|
|
df_referentiel_fe = process_referentiel_fe(referentiel_fe)
|
|
self.logger.info('Lecture du référentiel FE ------> Succès')
|
|
|
|
df_referentiel_fe = convertir_fe(df_referentiel_fe)
|
|
self.logger.info('Extraction des données du référentiel FE ------> Succès')
|
|
|
|
mettre_a_jour_fe(df_referentiel_fe)
|
|
self.logger.info('Mise à jour du référentiel FE ------> Succès')
|
|
|
|
return Response({'Insertion réussie'})
|
|
except (Http404, APIException):
|
|
raise
|
|
except BaseException:
|
|
message = "Impossible d'alimenter le(s) référentiel(s)"
|
|
self.logger.exception(message)
|
|
raise APIException(message)
|
|
|
|
# Vue API des administrés
|
|
# Pagination OK
|
|
# Ordering OK
|
|
# Search NOK
|
|
# Filtering NOK
|
|
|
|
@class_logger
|
|
@execution_time_viewset
|
|
@query_count_viewset
|
|
class AdministreView(viewsets.ModelViewSet):
|
|
"""
|
|
Cette classe est dédiée au vue de l'administre.
|
|
"""
|
|
permission_classes = [IsAuthenticated, GestionnairePermission]
|
|
serializer_class = AdministreSerializer
|
|
|
|
filter_backends = [DjangoFilterBackend, RelatedOrderingFilter]
|
|
# filterset_fields = ['category', 'in_stock']
|
|
filterset_class = AdministreFilter
|
|
ordering_fields = Administre.Cols.PK
|
|
ordering = [Administre.Cols.PK]
|
|
pagination_class = HeavyDataPagination
|
|
|
|
# important : mettre à jour quand le serializer change
|
|
def get_queryset(self):
|
|
Cols = Administre.Cols
|
|
ColsFE = FormationEmploi.Cols
|
|
return Administre.objects.select_related(
|
|
Cols.REL_FONCTION, Cols.REL_GRADE, Cols.REL_SOUS_VIVIER
|
|
).prefetch_related(
|
|
Cols.M2M_COMPETENCES,
|
|
Prefetch(Cols.M2M_PAM, queryset=Administres_Pams.objects.select_related(Administres_Pams.Cols.O2M_FMOB)),
|
|
# Prefetch(Cols.REL_DECISION, queryset=Decision.objects.select_related(
|
|
# f'{Decision.Cols.REL_POSTE}__{Poste.Cols.REL_FORMATION_EMPLOI}__{ColsFE.REL_MERE}',
|
|
# )),
|
|
Prefetch(Cols.REL_FORMATION_EMPLOI, queryset=FormationEmploi.objects.select_related(ColsFE.REL_MERE)),
|
|
)
|
|
|
|
def get_serializer(self, *args, **kwargs):
|
|
ser = super().get_serializer(*args, **kwargs)
|
|
arg = args[0] if args else None
|
|
if arg and isinstance(arg, (list, tuple)) and self.request.method == 'GET':
|
|
# calcule directement, si besoin, les profils et les décisions disponibles pour tous les résultats
|
|
if CTX_KEY_PROFILES not in ser.context:
|
|
ser.context[CTX_KEY_PROFILES] = get_profiles_by_adm(self.request.user, *arg)
|
|
if CTX_KEY_DECISIONS not in ser.context:
|
|
ser.context[CTX_KEY_DECISIONS] = get_available_decisions(arg, profiles_by_adm=ser.context[CTX_KEY_PROFILES],
|
|
annee_pam = self.request.query_params['pam__in'])
|
|
return ser
|
|
|
|
@atomic
|
|
def put(self, request):
|
|
"""La fonction put met à jour une liste d'administres.
|
|
|
|
:type request: rest_framework.request.Request
|
|
:param request: Request contenant la liste d'administres.
|
|
|
|
:return: - **Response** (*Response*): Reponse contient un message de la réussite de met à jour des administres .
|
|
"""
|
|
try:
|
|
req_data = request.data
|
|
is_list = isinstance(req_data, list)
|
|
validator = self.serializer_class(data=req_data, many=is_list, partial=True)
|
|
validator.is_valid(raise_exception=True)
|
|
|
|
today = date.today()
|
|
Cols = Administre.Cols
|
|
|
|
if 'annee_pam' in req_data:
|
|
annee_pam = req_data.pop('annee_pam')
|
|
else:
|
|
annee_pam = ''
|
|
|
|
|
|
def copy_data_item(input, pk):
|
|
"""Copie et complète si besoin le dictionnaire en entrée"""
|
|
result = {**input}
|
|
if pk and Cols.PK not in result:
|
|
result[Cols.PK] = pk
|
|
return result
|
|
|
|
def set_competences(administre_obj, a_comp):
|
|
"""Set competences to administre object"""
|
|
a_comp_id = [competence.comp_id for competence in a_comp]
|
|
administre_obj.a_liste_id_competences.set(a_comp_id)
|
|
return administre_obj
|
|
|
|
if is_list: # Update multiple elements
|
|
data = [copy_data_item(item, req_data[idx][Cols.PK]) for idx, item in enumerate(validator.validated_data)]
|
|
fields = [key for key in data[0].keys() if key != Cols.PK]
|
|
|
|
# Direct assignment to the forward side of a many-to-many set is prohibited. Use a_liste_id_competences.set() instead.
|
|
if Cols.STATUT_PAM in fields:
|
|
fields_to_update_pam = ['a_statut_pam_annee']
|
|
data_statut_pam = [{'id' :str(o['a_id_sap'])+str(annee_pam), 'a_statut_pam_annee' : o[Cols.STATUT_PAM]} for o in data]
|
|
objs = [Administres_Pams(**data_item) for data_item in data_statut_pam]
|
|
Administres_Pams.objects.bulk_update(objs, fields=fields_to_update_pam)
|
|
|
|
|
|
elif 'a_liste_id_competences' not in fields:
|
|
objs = [Administre(**data_item) for data_item in data]
|
|
if Cols.STATUT_PAM in fields:
|
|
list_error = []
|
|
for i in range(len(objs)):
|
|
old_administre = Administre.objects.get(a_id_sap=objs[i].a_id_sap)
|
|
administre = objs[i]
|
|
eip = administre.a_eip
|
|
fe_code = old_administre.formation_emploi_id
|
|
avis = administre.a_statut_pam
|
|
old_avis = old_administre.a_statut_pam
|
|
try:
|
|
categorie = constants.CATEGORIE_BY_NF[old_administre.a_nf.upper()]
|
|
except:
|
|
erreur = 'la catégorie de l\'administré n\'est pas reconnue dans ogure.'
|
|
raise Exception(erreur)
|
|
|
|
|
|
|
|
# liste_error = impact_decisions(old_administre, administre, old_avis, avis, eip, fe_code, categorie)
|
|
|
|
Administre.objects.bulk_update(objs, fields=fields)
|
|
else:
|
|
objs_w_comp = [set_competences(Administre(**without_keys(i, ['a_liste_id_competences'])), i['a_liste_id_competences']) for i in data]
|
|
|
|
else: # Update one element
|
|
data = copy_data_item(validator.validated_data, validator.validated_data[Cols.PK])
|
|
# c'est un bug la récupération de a_id_sap en-dessous, non ?
|
|
a_id_sap = Administre.objects.update(data)
|
|
db_instance = Administre.objects.filter(a_id_sap=a_id_sap).first()
|
|
db_instance.tag.clear()
|
|
|
|
return Response({'msg': 'updated'})
|
|
except APIException:
|
|
raise
|
|
except Exception:
|
|
message = 'échec de la mise à jour de N administrés'
|
|
self.logger.exception(message)
|
|
raise APIException(message)
|
|
|
|
def partial_update(self, request, pk=None):
|
|
""" La fonction put met à jour un administre.
|
|
|
|
:type request: rest_framework.request.Request
|
|
:param request: Request contenant l'administre.
|
|
|
|
:type pk: integer
|
|
:param pk: Primary Key de l'administre.
|
|
|
|
:return: - **Response** (*Response*): Reponse contient un message de la réussite de met à jour de l'administre .
|
|
"""
|
|
try:
|
|
a = get_object_or_404(Administre.objects, a_id_sap=pk) # Permet de déclancher la vérification des droits au niveau de l'objet
|
|
self.check_object_permissions(self.request, a)
|
|
req_data = request.data
|
|
|
|
if 'annee_pam' in req_data:
|
|
annee_pam = req_data.pop('annee_pam')
|
|
|
|
|
|
# TODO valider les données (il faut d'abord corriger la MAJ des compétences)
|
|
# validator = self.serializer_class(data=req_data, partial=True)
|
|
# validator.is_valid(raise_exception=True)
|
|
|
|
Cols = Administre.Cols
|
|
|
|
# Copie et complète si besoin le dictionnaire en entrée
|
|
# administre = {**validator.validated_data}
|
|
administre = {**req_data}
|
|
administre[Cols.PK] = pk
|
|
|
|
fields = [key for key in administre.keys() if key != Cols.PK] # and key != 'a_liste_id_competences']
|
|
|
|
if 'a_domaine_futur' in fields:
|
|
administre['a_domaine_futur_id'] = administre['a_domaine_futur']
|
|
del administre['a_domaine_futur']
|
|
|
|
if 'a_filiere_futur' in fields:
|
|
administre['a_filiere_futur_id'] = administre['a_filiere_futur']
|
|
del administre['a_filiere_futur']
|
|
|
|
if Cols.STATUT_PAM in fields:
|
|
old_administre = Administre.objects.get(a_id_sap=pk)
|
|
eip = old_administre.a_eip
|
|
fe_code = old_administre.formation_emploi_id
|
|
avis = administre[Cols.STATUT_PAM]
|
|
old_avis = old_administre.a_statut_pam
|
|
try:
|
|
categorie = constants.CATEGORIE_BY_NF[old_administre.a_nf.upper()]
|
|
except:
|
|
erreur = 'la catégorie de l\'administré n\'est pas reconnue dans ogure.'
|
|
raise APIException(erreur)
|
|
|
|
|
|
|
|
|
|
# liste_error = impact_decisions(old_administre, Administre(**administre), old_avis, avis, eip, fe_code, categorie)
|
|
|
|
|
|
if 'a_liste_id_competences' in fields:
|
|
adm=Administre(pk=pk)
|
|
#adm=request.data['a_liste_id_competences']
|
|
if administre['a_liste_id_competences']:
|
|
adm.a_liste_id_competences.set(administre['a_liste_id_competences'].split(','))
|
|
else:
|
|
adm.a_liste_id_competences.set("")
|
|
elif Cols.STATUT_PAM in fields:
|
|
adm_pam = Administres_Pams.objects.get(id = str(pk)+str(annee_pam))
|
|
adm_pam.a_statut_pam_annee = administre[Cols.STATUT_PAM]
|
|
adm_pam.save()
|
|
else:
|
|
copy = { k: v for k, v in administre.items() if k != 'a_liste_id_competences'}
|
|
adm = Administre(**copy)
|
|
|
|
if fields:
|
|
Administre.objects.bulk_update([adm], fields=fields)
|
|
|
|
return Response({'msg': 'updated'})
|
|
|
|
except (Http404, APIException):
|
|
raise
|
|
except Exception:
|
|
message = "échec de la mise à jour de l'administré"
|
|
self.logger.exception(message)
|
|
raise APIException(message)
|
|
|
|
|
|
# GET /api/administres => 0 administrés
|
|
# POST /api/administres => Crée 1 nouvel administres => id=1
|
|
# GET /api/administres/1 => 1 administre précédemment créé
|
|
# POST /api/administres/1 => 1 administre précédemment créé
|
|
|
|
|
|
@class_logger
|
|
@execution_time_viewset
|
|
@query_count_viewset
|
|
class AdministrePAMView(viewsets.ModelViewSet):
|
|
"""
|
|
Cette classe est dédiée au vue de l'administre.
|
|
"""
|
|
permission_classes = [IsAuthenticated, GestionnairePermission]
|
|
serializer_class = AdministresPamsSerializer
|
|
|
|
filter_backends = [DjangoFilterBackend, RelatedOrderingFilter]
|
|
# filterset_fields = ['category', 'in_stock']
|
|
filterset_class = AdministrePAMFilter
|
|
ordering_fields = Administres_Pams.Cols.PK
|
|
ordering = [Administres_Pams.Cols.PK]
|
|
pagination_class = HeavyDataPagination
|
|
# important : mettre à jour quand le serializer change
|
|
def get_queryset(self):
|
|
Cols = Administres_Pams.Cols
|
|
Cols_Administre = Administre.Cols
|
|
ColsFE = FormationEmploi.Cols
|
|
|
|
return Administres_Pams.objects.select_related(
|
|
Cols.REL_DECISION, Cols.REL_PAM, Cols.O2M_FMOB
|
|
).prefetch_related(
|
|
Prefetch(Cols.REL_ADMINISTRE, queryset = Administre.objects.select_related(Cols_Administre.REL_FONCTION, Cols_Administre.REL_GRADE, Cols_Administre.REL_SOUS_VIVIER
|
|
).prefetch_related(
|
|
Cols_Administre.M2M_COMPETENCES,
|
|
Prefetch(Cols_Administre.REL_FORMATION_EMPLOI, queryset=FormationEmploi.objects.select_related(ColsFE.REL_MERE)),
|
|
))
|
|
)
|
|
|
|
def get_serializer(self, *args, **kwargs):
|
|
ser = super().get_serializer(*args, **kwargs)
|
|
arg = args[0] if args else None
|
|
|
|
if arg and isinstance(arg, (list, tuple)) and self.request.method == 'GET':
|
|
# calcule directement, si besoin, les profils et les décisions disponibles pour tous les résultats
|
|
if CTX_KEY_PROFILES not in ser.context:
|
|
ser.context[CTX_KEY_PROFILES] = get_profiles_by_adm(self.request.user, *arg)
|
|
if CTX_KEY_DECISIONS not in ser.context:
|
|
ser.context[CTX_KEY_DECISIONS] = get_available_decisions(arg, profiles_by_adm=ser.context[CTX_KEY_PROFILES])
|
|
return ser
|
|
|
|
@atomic
|
|
def put(self, request):
|
|
"""La fonction put met à jour une liste d'administres.
|
|
|
|
:type request: rest_framework.request.Request
|
|
:param request: Request contenant la liste d'administres.
|
|
|
|
:return: - **Response** (*Response*): Reponse contient un message de la réussite de met à jour des administres .
|
|
"""
|
|
try:
|
|
req_data = request.data
|
|
is_list = isinstance(req_data, list)
|
|
# validator = AdministreSerializer(data=req_data, many=is_list, partial=True)
|
|
# validator.is_valid(raise_exception=True)
|
|
|
|
today = date.today()
|
|
Cols = Administre.Cols
|
|
|
|
# Extraire l'annee
|
|
if 'pam_id' in req_data[0]:
|
|
annee_pam = req_data[0]['pam_id']
|
|
|
|
|
|
def copy_data_item(input, pk):
|
|
"""Copie et complète si besoin le dictionnaire en entrée"""
|
|
result = {**input}
|
|
if pk and Cols.PK not in result:
|
|
result[Cols.PK] = pk
|
|
return result
|
|
|
|
def set_competences(administre_obj, a_comp):
|
|
"""Set competences to administre object"""
|
|
a_comp_id = [competence.comp_id for competence in a_comp]
|
|
administre_obj.a_liste_id_competences.set(a_comp_id)
|
|
return administre_obj
|
|
|
|
if is_list:
|
|
data = [copy_data_item(item, req_data[idx][Cols.PK]) for idx, item in enumerate(req_data)]
|
|
fields = [key for key in data[0].keys() if key != Cols.PK]
|
|
|
|
# Direct assignment to the forward side of a many-to-many set is prohibited. Use a_liste_id_competences.set() instead.
|
|
|
|
# Update Administres Pams dans les if et elif et le else et elif est utilisé pour la mise a jour des Administres
|
|
|
|
if Cols.STATUT_PAM in fields:
|
|
fields_to_update_pam = ['a_statut_pam_annee']
|
|
# Creation d'une liste qui contient l'id ( a_id_sap + annee_pam) avec le statut choisi
|
|
data_statut_pam = [{'id' :str(o['a_id_sap'])+str(annee_pam), 'a_statut_pam_annee' : o[Cols.STATUT_PAM]} for o in data]
|
|
# Creation des objets Administres Pams
|
|
objs = [Administres_Pams(**data_item) for data_item in data_statut_pam]
|
|
# Mise a jour des objets Administres Pams
|
|
Administres_Pams.objects.bulk_update(objs, fields=fields_to_update_pam)
|
|
|
|
elif 'a_liste_depts_souhaites_pam' in fields:
|
|
fields_to_update_pam = ['a_liste_depts_souhaites_pam']
|
|
# Creation d'une liste qui contient l'id ( a_id_sap + annee_pam) avec le statut choisi
|
|
data_statut_pam = [{'id' :str(o['a_id_sap'])+str(annee_pam), 'a_liste_depts_souhaites_pam' : o['a_liste_depts_souhaites_pam']} for o in data]
|
|
# Creation des objets Administres Pams
|
|
objs = [Administres_Pams(**data_item) for data_item in data_statut_pam]
|
|
# Mise a jour des objets Administres Pams
|
|
Administres_Pams.objects.bulk_update(objs, fields=fields_to_update_pam)
|
|
|
|
elif 'a_liste_id_competences' in fields:
|
|
objs_w_comp = [set_competences(Administre(**without_keys(i, ['a_liste_id_competences'])), i['a_liste_id_competences']) for i in data]
|
|
|
|
elif 'a_liste_zones_geographiques_shm_pam' in fields:
|
|
fields_to_update_pam = ['a_liste_zones_geographiques_shm_pam']
|
|
data_statut_pam = [{'id' :str(o['a_id_sap'])+str(annee_pam), 'a_liste_zones_geographiques_shm_pam' : o['a_liste_zones_geographiques_shm_pam']} for o in data]
|
|
objs = [Administres_Pams(**data_item) for data_item in data_statut_pam]
|
|
# Mise a jour des objets Administres Pams
|
|
Administres_Pams.objects.bulk_update(objs, fields=fields_to_update_pam)
|
|
|
|
else:
|
|
objs = [Administre(**data_item) for data_item in data]
|
|
if Cols.STATUT_PAM in fields:
|
|
list_error = []
|
|
for i in range(len(objs)):
|
|
old_administre = Administre.objects.get(a_id_sap=objs[i].a_id_sap)
|
|
administre = objs[i]
|
|
eip = administre.a_eip
|
|
fe_code = old_administre.formation_emploi_id
|
|
avis = administre.a_statut_pam
|
|
old_avis = old_administre.a_statut_pam
|
|
try:
|
|
categorie = constants.CATEGORIE_BY_NF[old_administre.a_nf.upper()]
|
|
except:
|
|
erreur = 'la catégorie de l\'administré n\'est pas reconnue dans ogure.'
|
|
raise Exception(erreur)
|
|
|
|
# liste_error = impact_decisions(old_administre, administre, old_avis, avis, eip, fe_code, categorie)
|
|
|
|
elif 'a_domaine_futur_id' in fields or 'a_filiere_futur_id' in fields or 'a_nf_futur' in fields:
|
|
for i in range(len(objs)):
|
|
old_administre = Administre.objects.get(a_id_sap=objs[i].a_id_sap)
|
|
administre = objs[i]
|
|
|
|
dom = administre.a_domaine_futur_id if 'a_domaine_futur_id' in fields else old_administre.a_domaine_futur_id
|
|
fil = administre.a_filiere_futur_id if 'a_filiere_futur_id' in fields else old_administre.a_filiere_futur_id
|
|
nf = administre.a_nf_futur if 'a_nf_futur' in fields else old_administre.a_nf_futur
|
|
cat = nf2categorie(nf)
|
|
|
|
sv_id = generate_sv_id(dom, fil, cat)
|
|
sv = SousVivier.objects.filter(sv_id=sv_id)
|
|
|
|
try:
|
|
sv.exists()
|
|
administre.sous_vivier_id = sv_id
|
|
if 'sous_vivier_id' not in fields:
|
|
fields += ['sous_vivier_id']
|
|
except:
|
|
message = f"La mise à jour a échoué car la sous-vivier d'id : {sv_id} n'est pas en base"
|
|
self.logger.exception(message)
|
|
raise APIException(message)
|
|
|
|
Administre.objects.bulk_update(objs, fields=fields)
|
|
|
|
return Response({'msg': 'updated'})
|
|
except APIException:
|
|
raise
|
|
except Exception:
|
|
message = 'échec de la mise à jour de N administrés'
|
|
self.logger.exception(message)
|
|
raise APIException(message)
|
|
|
|
def partial_update(self, request, pk=None):
|
|
""" La fonction put met à jour un administre.
|
|
|
|
:type request: rest_framework.request.Request
|
|
:param request: Request contenant l'administre.
|
|
|
|
:type pk: integer
|
|
:param pk: Primary Key de l'administre.
|
|
|
|
:return: - **Response** (*Response*): Reponse contient un message de la réussite de met à jour de l'administre .
|
|
"""
|
|
try:
|
|
a = get_object_or_404(Administre.objects, a_id_sap=pk) # Permet de déclancher la vérification des droits au niveau de l'objet
|
|
self.check_object_permissions(self.request, a)
|
|
req_data = request.data
|
|
|
|
if 'annee_pam' in req_data:
|
|
annee_pam = req_data.pop('annee_pam')
|
|
|
|
|
|
# TODO valider les données (il faut d'abord corriger la MAJ des compétences)
|
|
# validator = self.serializer_class(data=req_data, partial=True)
|
|
# validator.is_valid(raise_exception=True)
|
|
|
|
Cols = Administre.Cols
|
|
|
|
# Copie et complète si besoin le dictionnaire en entrée
|
|
# administre = {**validator.validated_data}
|
|
administre = {**req_data}
|
|
administre[Cols.PK] = pk
|
|
|
|
fields = [key for key in administre.keys() if key != Cols.PK] # and key != 'a_liste_id_competences']
|
|
|
|
if 'a_domaine_futur' in fields:
|
|
administre['a_domaine_futur_id'] = administre['a_domaine_futur']
|
|
del administre['a_domaine_futur']
|
|
|
|
if 'a_filiere_futur' in fields:
|
|
administre['a_filiere_futur_id'] = administre['a_filiere_futur']
|
|
del administre['a_filiere_futur']
|
|
|
|
if 'a_domaine_futur' in fields or 'a_filiere_futur' in fields or 'a_nf_futur' in fields:
|
|
old_administre = Administre.objects.get(a_id_sap=pk)
|
|
|
|
dom = administre['a_domaine_futur_id'] if 'a_domaine_futur' in fields else old_administre.a_domaine_futur_id
|
|
fil = administre['a_filiere_futur_id'] if 'a_filiere_futur' in fields else old_administre.a_filiere_futur_id
|
|
nf = administre['a_nf_futur'] if 'a_nf_futur' in fields else old_administre.a_nf_futur
|
|
cat = nf2categorie(nf)
|
|
|
|
sv_id = generate_sv_id(dom, fil, cat)
|
|
sv = SousVivier.objects.filter(sv_id=sv_id)
|
|
|
|
try:
|
|
sv.exists()
|
|
administre['sous_vivier_id'] = sv_id
|
|
fields += ['sous_vivier_id']
|
|
except:
|
|
message = f"La mise à jour a échoué car la sous-vivier d'id : {sv_id} n'est pas en base"
|
|
self.logger.exception(message)
|
|
raise APIException(message)
|
|
|
|
if Cols.STATUT_PAM in fields:
|
|
old_administre = Administre.objects.get(a_id_sap=pk)
|
|
eip = old_administre.a_eip
|
|
fe_code = old_administre.formation_emploi_id
|
|
avis = administre[Cols.STATUT_PAM]
|
|
old_avis = old_administre.a_statut_pam
|
|
try:
|
|
categorie = constants.CATEGORIE_BY_NF[old_administre.a_nf.upper()]
|
|
except:
|
|
erreur = 'la catégorie de l\'administré n\'est pas reconnue dans ogure.'
|
|
raise APIException(erreur)
|
|
|
|
if 'a_liste_id_competences' in fields:
|
|
adm=Administre(pk=pk)
|
|
if administre['a_liste_id_competences']:
|
|
adm.a_liste_id_competences.set(administre['a_liste_id_competences'].split(','))
|
|
else:
|
|
adm.a_liste_id_competences.set("")
|
|
|
|
elif Cols.STATUT_PAM in fields:
|
|
adm_pam = Administres_Pams.objects.get(id = str(pk)+str(annee_pam))
|
|
adm_pam.a_statut_pam_annee = administre[Cols.STATUT_PAM]
|
|
adm_pam.save()
|
|
|
|
elif 'notes_pam' in fields:
|
|
adm_pam = Administres_Pams.objects.get(id = str(pk)+str(annee_pam))
|
|
adm_pam.notes_pam = administre['notes_pam']
|
|
adm_pam.save()
|
|
|
|
elif 'a_ciat_pam' in fields:
|
|
adm_pam = Administres_Pams.objects.get(id = str(pk)+str(annee_pam))
|
|
adm_pam.a_ciat_pam = administre['a_ciat_pam']
|
|
adm_pam.save()
|
|
|
|
elif 'a_specifique_pam' in fields:
|
|
adm_pam = Administres_Pams.objects.get(id = str(pk)+str(annee_pam))
|
|
adm_pam.a_specifique_pam = administre['a_specifique_pam']
|
|
adm_pam.save()
|
|
|
|
elif 'a_liste_depts_souhaites_pam' in fields:
|
|
adm_pam = Administres_Pams.objects.get(id = str(pk)+str(annee_pam))
|
|
adm_pam.a_liste_depts_souhaites_pam = administre['a_liste_depts_souhaites_pam']
|
|
adm_pam.save()
|
|
|
|
elif 'a_liste_zones_geographiques_shm_pam' in fields:
|
|
adm_pam = Administres_Pams.objects.get(id = str(pk)+str(annee_pam))
|
|
adm_pam.a_liste_zones_geographiques_shm_pam = administre['a_liste_zones_geographiques_shm_pam']
|
|
adm_pam.save()
|
|
|
|
elif 'a_situationfuture_notes_fe' in fields:
|
|
adm_pam = Administres_Pams.objects.get(id = str(pk)+str(annee_pam))
|
|
adm_pam.a_situationfuture_notes_fe = administre['a_situationfuture_notes_fe']
|
|
adm_pam.save()
|
|
|
|
else:
|
|
copy = {k: v for k, v in administre.items() if k != 'a_liste_id_competences'}
|
|
adm = Administre(**copy)
|
|
|
|
if fields:
|
|
Administre.objects.bulk_update([adm], fields=fields)
|
|
|
|
return Response({'msg': 'updated'})
|
|
|
|
except (Http404, APIException):
|
|
raise
|
|
except Exception:
|
|
message = "échec de la mise à jour de l'administré"
|
|
self.logger.exception(message)
|
|
raise APIException(message)
|
|
|
|
|
|
@execution_time_viewset
|
|
@query_count_viewset
|
|
@class_logger
|
|
class PostePAMView(viewsets.ModelViewSet):
|
|
"""
|
|
Cette classe est dédiée au vue des postes.
|
|
"""
|
|
permission_classes = [IsAuthenticated, GestionnairePermission]
|
|
lookup_value_regex = r"[\w.]+"
|
|
serializer_class = PostesPamsSerializer
|
|
pagination_class = HeavyDataPagination
|
|
filter_backends = [DjangoFilterBackend, RelatedOrderingFilter]
|
|
filterset_class = PostePAMFilter
|
|
# ordering_fields = '__all_related__'
|
|
ordering = ['poste_id','-p_pam']
|
|
|
|
# important : mettre à jour quand le serializer change
|
|
def get_queryset(self):
|
|
"""Cette fonction permet d'ajouter plus de logique à l'attribut queryset."""
|
|
|
|
Cols = Postes_Pams.Cols
|
|
Poste_Cols = Poste.Cols
|
|
|
|
queryset = Postes_Pams.objects.select_related(
|
|
Cols.REL_PAM
|
|
).prefetch_related(
|
|
Prefetch(Cols.O2M_DECISION, queryset=Decision.objects.select_related(f'{Decision.Cols.REL_ADMINISTRE}__{Administre.Cols.REL_GRADE}')),
|
|
Prefetch(Cols.REL_POSTE, queryset=Poste.objects.select_related(Poste_Cols.REL_FONCTION)
|
|
.prefetch_related(
|
|
Poste_Cols.M2M_COMPETENCES,
|
|
Poste_Cols.M2M_SOUS_VIVIERS,
|
|
Prefetch(Poste_Cols.REL_FORMATION_EMPLOI,
|
|
queryset=FormationEmploi.objects.select_related(FormationEmploi.Cols.REL_MERE))))
|
|
)
|
|
|
|
sous_viviers_name = self.request.query_params.get('sous_vivier')
|
|
if sous_viviers_name is not None:
|
|
queryset = queryset.filter(poste__sous_viviers__in=sous_viviers_name.split('-'))
|
|
|
|
|
|
return queryset
|
|
|
|
def put(self, request):
|
|
"""La fonction put met à jour une liste des postes.
|
|
|
|
:type request: rest_framework.request.Request
|
|
:param request: Request contenant la liste des postes.
|
|
|
|
:return: - **Response** (*Response*): Reponse contient un message de la réussite de met à jour des postes .
|
|
"""
|
|
data = request.data
|
|
self.logger.debug('------------------------- Modification Multiple de Poste verification ---------------------')
|
|
self.logger.debug('Request data : %s', data)
|
|
|
|
if 'pam_id' in data[0]:
|
|
annee_pam = data[0]['pam_id']
|
|
|
|
# serialized = self.serializer_class(data=data, many=isinstance(data, list), partial=True)
|
|
# serialized.is_valid(raise_exception=True)
|
|
|
|
if isinstance(data, list): # Update multiple elements
|
|
try:
|
|
fields = [key for key in data[0].keys() if key != 'p_id' ]
|
|
|
|
|
|
|
|
if 'p_avis_fe' in fields:
|
|
fields_to_update_pam = ['p_avis_fe_pam', 'p_avis_pam']
|
|
# Creation d'une liste qui contient l'id ( p_id + annee_pam) avec l'avis choisi
|
|
data_statut_pam = [{'id' :str(o['p_id'])+str(annee_pam), 'p_avis_fe_pam' : o['p_avis_fe'], 'p_avis_pam' : o['p_avis_fe']} for o in data]
|
|
# Creation des objets Poste Pams
|
|
objs = [Postes_Pams(**data_item) for data_item in data_statut_pam]
|
|
# Mise a jour des objets Poste Pams
|
|
Postes_Pams.objects.bulk_update(objs, fields=fields_to_update_pam)
|
|
|
|
elif 'p_avis' in fields:
|
|
fields_to_update_pam = ['p_avis_pam']
|
|
data_statut_pam = [{'id' :str(o['p_id'])+str(annee_pam), 'p_avis_pam' : o['p_avis']} for o in data]
|
|
objs = [Postes_Pams(**data_item) for data_item in data_statut_pam]
|
|
Postes_Pams.objects.bulk_update(objs, fields=fields_to_update_pam)
|
|
|
|
elif 'p_direct_commissionne' in fields:
|
|
fields_to_update_pam = ['p_direct_commissionne_pam']
|
|
data_statut_pam = [{'id' :str(o['p_id'])+str(annee_pam), 'p_direct_commissionne_pam' : o['p_direct_commissionne']} for o in data]
|
|
objs = [Postes_Pams(**data_item) for data_item in data_statut_pam]
|
|
Postes_Pams.objects.bulk_update(objs, fields=fields_to_update_pam)
|
|
|
|
elif 'p_itd_cellule' in fields:
|
|
sous_viviers = sous_viviers_du_cellule(data[0]['p_itd_cellule'])
|
|
self.logger.debug('Modification Multiple de p_itd_cellule, les sous_viviers de la cellule sont : %s', sous_viviers)
|
|
if sous_viviers:
|
|
objs = [Poste(**data[i]) for i in range(len(data))]
|
|
Poste.objects.bulk_update(objs, fields=fields)
|
|
objs_w_comp = [Poste(**without_keys(data[i], ['p_itd_cellule'])).sous_viviers.set(sous_viviers) for i in range(len(data))]
|
|
else:
|
|
return JsonResponse({'info': f"La mise à jour n'a pas réussi : la cellule '{data[0]['p_itd_cellule']}' n'a pas de sous viviers enregistrés dans l'application."})
|
|
|
|
elif 'competence_id' not in fields:
|
|
if 'supression' in fields:
|
|
elem = data[0]
|
|
Postes_Pams.objects.filter(p_pam_id=elem['pam_id'],poste_id=elem['p_id']).delete()
|
|
|
|
if 'departement' and 'codeFe' and 'lieu' and 'zoneDeDefense' and 'codeFeMere' and 'etr' in fields:
|
|
elem = data[0]
|
|
#generate random id : create compteur de poste en sureff
|
|
no_sureff = str(Postes_Pams.objects.filter(p_pam_id=str(annee_pam),id__contains='_').count() + 1)
|
|
|
|
pam_actuel = PAM.objects.get(pam_statut='PAM en cours').pam_id
|
|
|
|
#on crée l'instance de formation d'emploi
|
|
fe = FormationEmploi.objects.get(fe_code=elem['codeFe'])
|
|
fe_poste_duplique = fe
|
|
fe_poste_duplique.zone_defense =elem['zoneDeDefense']
|
|
fe_poste_duplique.fe_garnison_lieu = elem['lieu']
|
|
fe_poste_duplique.save()
|
|
#créer une copie d'instance de poste qui existe déjà en base:
|
|
poste = Poste.objects.get(p_id=elem['p_id'])
|
|
poste_duplique = poste
|
|
poste_duplique.p_id = poste.p_id + '_'+ no_sureff
|
|
poste_duplique.p_dep= elem['departement']
|
|
poste_duplique.p_fonction = elem['etr']
|
|
poste_duplique.formation_emploi = fe_poste_duplique
|
|
poste_duplique.save()
|
|
|
|
if elem['pam_id'] == pam_actuel:
|
|
poste_sureffA = Postes_Pams.objects.get(id=elem['p_id'] + elem['pam_id'])
|
|
poste_sureffA.id = elem['p_id']+ '_'+ no_sureff + elem['pam_id']
|
|
poste_sureffA.poste_id = elem['p_id']+ '_'+ no_sureff
|
|
poste_sureffA.poste = poste_duplique
|
|
poste_sureffA.info_reo = f"SUREFF {str(annee_pam)}"
|
|
poste_sureffA.save()
|
|
|
|
poste_sureffA1 = Postes_Pams.objects.get(id=elem['p_id'] + str(int(elem['pam_id'])+1))
|
|
poste_sureffA1.id = elem['p_id']+ '_'+ no_sureff +str(int(elem['pam_id'])+1)
|
|
poste_sureffA1.poste_id = elem['p_id']+ '_'+ no_sureff
|
|
poste_sureffA1.poste = poste_duplique
|
|
poste_sureffA1.info_reo = f"SUREFF {str(annee_pam)}"
|
|
poste_sureffA1.save()
|
|
|
|
else:
|
|
poste_sureffA1 = Postes_Pams.objects.get(id=elem['p_id'] + elem['pam_id'])
|
|
poste_sureffA1.id = elem['p_id']+ '_'+ no_sureff + elem['pam_id']
|
|
poste_sureffA1.poste_id = elem['p_id']+ '_'+ no_sureff
|
|
poste_sureffA1.poste = poste_duplique
|
|
poste_sureffA1.info_reo = f"SUREFF {str(annee_pam)}"
|
|
poste_sureffA1.save()
|
|
|
|
else:
|
|
objs = [Poste(**data[i]) for i in range(len(data))]
|
|
Poste.objects.bulk_update(objs, fields=fields)
|
|
else:
|
|
objs_w_comp = [Poste(**without_keys(data[i],['competence_id'])).competences.set(data[i]['competence_id'].split(',')) for i in range(len(data))]
|
|
|
|
except:
|
|
raise Exception("bulk update error")
|
|
|
|
|
|
return Response({'msg': 'updated'})
|
|
|
|
def partial_update(self, request, pk=None):
|
|
""" La fonction put met à jour un poste.
|
|
|
|
:type request: rest_framework.request.Request
|
|
:param request: Request contenant le poste.
|
|
|
|
:type pk: integer
|
|
:param pk: Primary Key du poste.
|
|
:return: - **Response** (*Response*): Reponse contient un message de la réussite de met à jour du poste .
|
|
"""
|
|
p = get_object_or_404(Poste.objects, p_id=pk) # Permet de déclancher la vérification des droits au niveau de l'objet
|
|
self.check_object_permissions(self.request, p)
|
|
poste = request.data
|
|
self.logger.debug('------------------------- Modification Unitaire de Poste verification ---------------------')
|
|
self.logger.debug('Request data : %s', poste)
|
|
|
|
if 'annee_pam' in poste:
|
|
annee_pam = poste.pop('annee_pam')
|
|
|
|
fields_not_updated = ['p_id', 'p_poids_filiere', 'p_poids_nf', 'p_poids_competences']
|
|
fields = [key for key in poste.keys() if key not in fields_not_updated]
|
|
poste['p_id'] = pk
|
|
|
|
|
|
|
|
if 'competence' in fields:
|
|
pos=Poste(pk=pk)
|
|
if poste['competence']:
|
|
pos.competences.set(poste['competence'].split(','))
|
|
else:
|
|
pos.competences.set("")
|
|
|
|
elif 'sous_vivier_id' in fields:
|
|
pos=Poste(pk=pk)
|
|
pos.sous_viviers.add(poste['sous_vivier_id'])
|
|
|
|
elif 'p_avis_fe_pam' in fields:
|
|
poste_pam = Postes_Pams.objects.get(id = str(pk)+str(annee_pam))
|
|
poste_pam.p_avis_pam = poste['p_avis_fe_pam']
|
|
poste_pam.p_avis_fe_pam = poste['p_avis_fe_pam']
|
|
poste_pam.save()
|
|
|
|
elif 'p_avis_pam' in fields:
|
|
poste_pam = Postes_Pams.objects.get(id = str(pk)+str(annee_pam))
|
|
poste_pam.p_avis_pam = poste['p_avis_pam']
|
|
poste_pam.save()
|
|
|
|
elif 'p_direct_commissionne_pam' in fields:
|
|
poste_pam = Postes_Pams.objects.get(id = str(pk)+str(annee_pam))
|
|
poste_pam.p_direct_commissionne_pam = poste['p_direct_commissionne_pam']
|
|
poste_pam.save()
|
|
|
|
elif 'p_priorisation_pcp_pam' in fields:
|
|
poste_pam = Postes_Pams.objects.get(id = str(pk)+str(annee_pam))
|
|
poste_pam.p_priorisation_pcp_pam = poste['p_priorisation_pcp_pam']
|
|
poste_pam.save()
|
|
|
|
elif 'p_notes_gestionnaire_pam' in fields:
|
|
poste_pam = Postes_Pams.objects.get(id = str(pk)+str(annee_pam))
|
|
poste_pam.p_notes_gestionnaire_pam = poste['p_notes_gestionnaire_pam']
|
|
poste_pam.save()
|
|
|
|
else:
|
|
copy = {k: v for k, v in poste.items() if k != 'competence'}
|
|
pos = Poste(**copy)
|
|
|
|
# l'orde des if est tres important
|
|
if 'p_specifique' in fields and poste['p_specifique'] == SpecifiqueChoices.ITD:
|
|
pos.p_itd_affecte = False
|
|
fields += ['p_itd_affecte']
|
|
|
|
elif 'p_itd_cellule' in fields:
|
|
sous_viviers = sous_viviers_du_cellule(poste['p_itd_cellule'])
|
|
if sous_viviers:
|
|
pos.sous_viviers.set(sous_viviers)
|
|
pos.p_itd_affecte = True
|
|
fields += ['p_itd_affecte']
|
|
else :
|
|
self.logger.debug(f"La mise à jour n'a pas réussi, La cellule '{poste['p_itd_cellule']}' n'a pas de sous viviers enregistrés dans l'application.")
|
|
return JsonResponse({'info': f"La mise à jour n'a pas réussi : la cellule '{poste['p_itd_cellule']}' n'a pas de sous viviers enregistrés dans l'application."})
|
|
|
|
if fields:
|
|
Poste.objects.bulk_update([pos], fields=fields)
|
|
|
|
|
|
|
|
return Response({'msg': 'updated'})
|
|
|
|
@execution_time_viewset
|
|
@query_count_viewset
|
|
@class_logger
|
|
class PosteView(viewsets.ModelViewSet):
|
|
"""
|
|
Cette classe est dédiée au vue des postes.
|
|
"""
|
|
permission_classes = [IsAuthenticated, GestionnairePermission]
|
|
lookup_value_regex = r"[\w.]+"
|
|
serializer_class = PosteSerializer
|
|
pagination_class = HeavyDataPagination
|
|
filter_backends = [DjangoFilterBackend, RelatedOrderingFilter]
|
|
filterset_class = PosteFilter
|
|
ordering_fields = '__all_related__'
|
|
ordering = ['p_id']
|
|
|
|
# important : mettre à jour quand le serializer change
|
|
def get_queryset(self):
|
|
"""Cette fonction permet d'ajouter plus de logique à l'attribut queryset."""
|
|
|
|
Cols = Poste.Cols
|
|
|
|
queryset = Poste.objects.select_related(
|
|
Cols.REL_FONCTION
|
|
).prefetch_related(
|
|
Cols.M2M_COMPETENCES,
|
|
Cols.M2M_SOUS_VIVIERS,
|
|
Prefetch(Cols.M2M_PAM, queryset=Postes_Pams.objects.select_related(Postes_Pams.Cols.O2M_DECISION)),
|
|
Prefetch(Cols.O2M_DECISION, queryset=Decision.objects.select_related(f'{Decision.Cols.REL_ADMINISTRE}__{Administre.Cols.REL_GRADE}')),
|
|
Prefetch(Cols.REL_FORMATION_EMPLOI, queryset=FormationEmploi.objects.select_related(FormationEmploi.Cols.REL_MERE)),
|
|
).annotate(
|
|
p_nb_prepositionne=Sum(
|
|
Case(When(decisions__de_decision=DecisionChoices.PREPOSITIONNE, then=1), default=0,
|
|
output_field=IntegerField())),
|
|
p_nb_positionne=Sum(Case(When(decisions__de_decision=DecisionChoices.POSITIONNE, then=1), default=0,
|
|
output_field=IntegerField())),
|
|
p_nb_omi_en_cours=Sum(Case(When(decisions__de_decision=DecisionChoices.OMI_EN_COURS, then=1), default=0,
|
|
output_field=IntegerField())),
|
|
p_nb_omi_active=Sum(Case(When(decisions__de_decision=DecisionChoices.OMI_ACTIVE, then=1), default=0,
|
|
output_field=IntegerField())),
|
|
)
|
|
|
|
sous_viviers_name = self.request.query_params.get('sous_vivier')
|
|
if sous_viviers_name is not None:
|
|
queryset = queryset.filter(sous_viviers=sous_viviers_name)
|
|
|
|
|
|
return queryset
|
|
|
|
|
|
def put(self, request):
|
|
"""La fonction put met à jour une liste des postes.
|
|
|
|
:type request: rest_framework.request.Request
|
|
:param request: Request contenant la liste des postes.
|
|
|
|
:return: - **Response** (*Response*): Reponse contient un message de la réussite de met à jour des postes .
|
|
"""
|
|
data = request.data
|
|
self.logger.debug('------------------------- Modification Multiple de Poste verification ---------------------')
|
|
self.logger.debug('Request data : %s', data)
|
|
serialized = self.serializer_class(data=data, many=isinstance(data, list), partial=True)
|
|
serialized.is_valid(raise_exception=True)
|
|
if isinstance(data, list): # Update multiple elements
|
|
try:
|
|
fields = [key for key in data[0].keys() if key != 'p_id' ]
|
|
|
|
if 'p_itd_cellule' in fields:
|
|
sous_viviers = sous_viviers_du_cellule(data[0]['p_itd_cellule'])
|
|
self.logger.debug('Modification Multiple de p_itd_cellule, les sous_viviers de la cellule sont : %s', sous_viviers)
|
|
if sous_viviers:
|
|
objs = [Poste(**data[i]) for i in range(len(data))]
|
|
Poste.objects.bulk_update(objs, fields=fields)
|
|
objs_w_comp = [Poste(**without_keys(data[i],['p_itd_cellule'])).sous_viviers.set(sous_viviers) for i in range(len(data))]
|
|
else :
|
|
return JsonResponse({'info': f"La mise à jour n'a pas réussi, La cellule '{data[0]['p_itd_cellule']}' n'a pas de sous viviers enregistrés dans l'application."})
|
|
|
|
|
|
elif 'competence_id' not in fields:
|
|
objs = [Poste(**data[i]) for i in range(len(data))]
|
|
Poste.objects.bulk_update(objs, fields=fields)
|
|
else:
|
|
objs_w_comp = [Poste(**without_keys(data[i],['competence_id'])).competences.set(data[i]['competence_id'].split(',')) for i in range(len(data))]
|
|
except:
|
|
raise Exception("bulk update error")
|
|
else: # Update one element
|
|
a_id_sap = Poste.objects.update(serialized.validated_data)
|
|
db_instance = Poste.objects.filter(
|
|
a_id_sap=a_id_sap).first()
|
|
db_instance.tag.clear()
|
|
|
|
return Response({'msg': 'updated'})
|
|
|
|
def partial_update(self, request, pk=None):
|
|
""" La fonction put met à jour un poste.
|
|
|
|
:type request: rest_framework.request.Request
|
|
:param request: Request contenant le poste.
|
|
|
|
:type pk: integer
|
|
:param pk: Primary Key du poste.
|
|
:return: - **Response** (*Response*): Reponse contient un message de la réussite de met à jour du poste .
|
|
"""
|
|
p = get_object_or_404(Poste.objects, p_id=pk) # Permet de déclancher la vérification des droits au niveau de l'objet
|
|
self.check_object_permissions(self.request, p)
|
|
poste = request.data
|
|
self.logger.debug('------------------------- Modification Unitaire de Poste verification ---------------------')
|
|
self.logger.debug('Request data : %s', poste)
|
|
fields_not_updated = ['p_id', 'p_poids_filiere', 'p_poids_nf', 'p_poids_competences']
|
|
fields = [key for key in poste.keys() if key not in fields_not_updated]
|
|
poste['p_id'] = pk
|
|
|
|
if 'competence' in fields:
|
|
pos=Poste(pk=pk)
|
|
if poste['competence']:
|
|
pos.competences.set(poste['competence'].split(','))
|
|
else:
|
|
pos.competences.set("")
|
|
elif 'sous_vivier_id' in fields:
|
|
pos=Poste(pk=pk)
|
|
pos.sous_viviers.add(poste['sous_vivier_id'])
|
|
else:
|
|
copy = { k: v for k, v in poste.items() if k != 'competence'}
|
|
pos = Poste(**copy)
|
|
|
|
if 'p_avis_fe' in fields:
|
|
pos.p_avis = poste['p_avis_fe']
|
|
fields += ['p_avis']
|
|
|
|
# l'orde des if est tres important
|
|
if 'p_specifique' in fields and poste['p_specifique'] == SpecifiqueChoices.ITD:
|
|
pos.p_itd_affecte = False
|
|
fields += ['p_itd_affecte']
|
|
|
|
|
|
elif 'p_itd_cellule' in fields:
|
|
sous_viviers = sous_viviers_du_cellule(poste['p_itd_cellule'])
|
|
if sous_viviers:
|
|
pos.sous_viviers.set(sous_viviers)
|
|
pos.p_itd_affecte = True
|
|
fields += ['p_itd_affecte']
|
|
else :
|
|
self.logger.debug(f"La mise à jour n'a pas réussi, La cellule '{poste['p_itd_cellule']}' n'a pas de sous viviers enregistrés dans l'application.")
|
|
return JsonResponse({'info': f"La mise à jour n'a pas réussi, La cellule '{poste['p_itd_cellule']}' n'a pas de sous viviers enregistrés dans l'application."})
|
|
|
|
if fields:
|
|
Poste.objects.bulk_update([pos], fields=fields)
|
|
|
|
|
|
return Response({'msg': 'updated'})
|
|
|
|
|
|
@execution_time_viewset
|
|
@query_count_viewset
|
|
class ListesPreferencesView(viewsets.ModelViewSet):
|
|
"""
|
|
Cette classe est dédiée au vue des ListesPreferences.
|
|
"""
|
|
permission_classes = [IsAuthenticated, GestionnairePermission]
|
|
serializer_class = PreferencesListe
|
|
queryset = PreferencesListe.objects.all()
|
|
|
|
|
|
@execution_time_viewset
|
|
@query_count_viewset
|
|
class MarqueView(viewsets.ModelViewSet):
|
|
"""
|
|
Cette classe est dédiée au vue des marques.
|
|
"""
|
|
permission_classes = [IsAuthenticated, GestionnairePermission]
|
|
serializer_class = MarqueSerializer
|
|
queryset = Marque.objects.all()
|
|
|
|
|
|
@execution_time_viewset
|
|
@query_count_viewset
|
|
class MarquesGroupeView(viewsets.ModelViewSet):
|
|
"""
|
|
Cette classe est dédiée au vue des marquegroupes.
|
|
"""
|
|
permission_classes = [IsAuthenticated, GestionnairePermission]
|
|
serializer_class = MarquesGroupeSerializer
|
|
queryset = MarquesGroupe.objects.all()
|
|
|
|
|
|
@execution_time_viewset
|
|
@query_count_viewset
|
|
class FmobView(viewsets.ModelViewSet):
|
|
"""
|
|
Cette classe est dédiée au vue des Fmob.
|
|
"""
|
|
permission_classes = [IsAuthenticated, GestionnairePermission]
|
|
serializer_class = FmobSerializer
|
|
queryset = FMOB.objects.all()
|
|
|
|
|
|
@execution_time_viewset
|
|
@query_count_viewset
|
|
class FiliereView(viewsets.ModelViewSet):
|
|
"""
|
|
Cette classe est dédiée au vue des filieres.
|
|
"""
|
|
permission_classes = [IsAuthenticated, GestionnairePermission]
|
|
serializer_class = FiliereSerializer
|
|
queryset = Filiere.objects.all()
|
|
|
|
|
|
@execution_time_viewset
|
|
@query_count_viewset
|
|
class DomaineView(viewsets.ModelViewSet):
|
|
"""
|
|
Cette classe est dédiée au vue des domaines.
|
|
"""
|
|
permission_classes = [IsAuthenticated, GestionnairePermission]
|
|
serializer_class = DomaineSerializer
|
|
queryset = Domaine.objects.all()
|
|
|
|
|
|
@execution_time_viewset
|
|
@query_count_viewset
|
|
class SousVivierAssociationView(viewsets.ModelViewSet):
|
|
"""
|
|
Cette classe est dédiée au vue du SousVivierAssociation.
|
|
"""
|
|
permission_classes = [IsAuthenticated, GestionnairePermission]
|
|
serializer_class = SousVivierAssociationSerializer
|
|
queryset = SousVivierAssociation.objects.all()
|
|
|
|
|
|
@execution_time_viewset
|
|
@query_count_viewset
|
|
class PcpFeGroupeView(viewsets.ModelViewSet):
|
|
"""
|
|
Cette classe est dédiée au vue du PcpFeGroupe.
|
|
"""
|
|
permission_classes = [IsAuthenticated, GestionnairePermission]
|
|
serializer_class = PcpFeGroupeSerializer
|
|
queryset = PcpFeGroupe.objects.all()
|