Commit | Line | Data |
---|---|---|
df59fcab | 1 | # -*- encoding: utf-8 -*- |
2 | ||
6067184b | 3 | from django.core.urlresolvers import reverse |
4 | from django.http import HttpResponseRedirect | |
df59fcab | 5 | from django.contrib import admin |
38df74bb | 6 | from django.shortcuts import get_object_or_404 |
7 | ||
6067184b | 8 | from reversion.admin import VersionAdmin |
38df74bb | 9 | from datamaster_modeles.models import Employe, Implantation, Region |
6067184b | 10 | |
df59fcab | 11 | from recrutement.models import * |
f6724c20 NBV |
12 | from recrutement.workflow import grp_administrateurs_recrutement,\ |
13 | grp_evaluateurs_recrutement, grp_drh_recrutement | |
df59fcab | 14 | |
d2b30f5f | 15 | class OffreEmploiAdmin(VersionAdmin): |
7f9e891e | 16 | date_hierarchy = 'date_creation' |
ec517164 | 17 | list_display = ('nom', 'resume', 'date_limite', 'region', '_candidatsList') |
f6724c20 | 18 | |
8941aee7 | 19 | # Afficher la liste des candidats pour l'offre d'emploi |
596fe324 | 20 | def _candidatsList(self, obj): |
8ea41642 | 21 | return "<a href='%s?offre_emploi__id__exact=%s'>Voir les candidats \ |
22 | </a>" % (reverse('admin:recrutement_candidat_changelist'), obj.id) | |
2f78949d | 23 | _candidatsList.allow_tags = True |
f6724c20 | 24 | _candidatsList.short_description = "Afficher la liste des candidats" |
362a3534 | 25 | |
2f78949d | 26 | def queryset(self, request): |
beef7690 | 27 | query = self.model._default_manager.get_query_set() |
f6724c20 NBV |
28 | # Si user est superuser afficher toutes les offres d'emploi |
29 | user_groupes = request.user.groups.all() | |
30 | if not grp_drh_recrutement in user_groupes: | |
beef7690 NBV |
31 | """ |
32 | Filtrer les offre d'emploi pour afficher seulement les offres | |
33 | d'emploi actives | |
34 | """ | |
35 | qs = query.filter(date_limite__gte=datetime.date.today()) | |
36 | """ | |
37 | Si le user n'est ni un évaluateur ni un administrateur régional, | |
38 | retourner none | |
39 | Vérifier groupes | |
40 | """ | |
f6724c20 | 41 | if grp_evaluateurs_recrutement in user_groupes: |
ca73c3c6 NBV |
42 | try: |
43 | user = Evaluateur.objects.get(user=request.user) | |
44 | except Evaluateur.DoesNotExist: | |
45 | return qs.none() | |
f6724c20 | 46 | elif grp_administrateurs_recrutement in user_groupes: |
ca73c3c6 NBV |
47 | try: |
48 | user = AdministrateurRegional.objects.get(user=request.user) | |
49 | except AdministrateurRegional.DoesNotExist: | |
50 | return qs.none() | |
f6724c20 NBV |
51 | else: |
52 | return qs.none() | |
53 | ||
54 | if type(user) is AdministrateurRegional: | |
55 | region_ids = [g.id for g in user.regions.all()] | |
56 | return qs.select_related('offre_emploi').\ | |
57 | filter(region__in=region_ids) | |
beef7690 | 58 | if type(user) is Evaluateur: |
f6724c20 | 59 | candidats = [g for g in user.candidats.all()] |
beef7690 | 60 | offre_emploi_ids = [c.offre_emploi.id for c in candidats] |
f6724c20 | 61 | return qs.select_related('offre_emploi').\ |
beef7690 | 62 | filter(id__in=offre_emploi_ids) |
3bcef02d | 63 | return qs.none() |
beef7690 | 64 | return query.select_related('offre_emploi') |
f6724c20 NBV |
65 | |
66 | def has_change_permission(self, request, obj=None): | |
67 | user_groupes = request.user.groups.all() | |
68 | if grp_drh_recrutement in user_groupes or \ | |
69 | grp_administrateurs_recrutement in user_groupes: | |
70 | return True | |
71 | return False | |
72 | ||
73 | class ProxyOffreEmploiAdmin(OffreEmploiAdmin): | |
beef7690 | 74 | list_display = ('nom', 'resume', 'date_limite', 'region', ) |
f6724c20 NBV |
75 | readonly_fields = ('actif', 'description', 'poste', 'bureau', |
76 | 'duree_affectation', 'renumeration', | |
77 | 'debut_affectation', 'lieu_affectation', 'nom', | |
78 | 'resume', 'date_limite', 'region') | |
79 | fieldsets = ( | |
720c3ad5 | 80 | ('Nom', { |
f6724c20 NBV |
81 | 'fields': ('nom', ) |
82 | }), | |
720c3ad5 | 83 | ('Description générale', { |
f6724c20 NBV |
84 | 'fields': ('poste', 'resume','description', 'date_limite', ) |
85 | }), | |
720c3ad5 | 86 | ('Coordonnées', { |
f6724c20 NBV |
87 | 'fields': ('lieu_affectation', 'bureau', 'region', ) |
88 | }), | |
720c3ad5 | 89 | ('Autre', { |
f6724c20 NBV |
90 | 'fields': ('debut_affectation', 'duree_affectation', |
91 | 'renumeration', ) | |
92 | }), | |
93 | ) | |
94 | def has_add_permission(self, request): | |
95 | return False | |
96 | ||
97 | def has_delete_permission(self, request, obj=None): | |
98 | return False | |
99 | ||
2d083449 NBV |
100 | def has_change_permission(self, request, obj=None): |
101 | user_groupes = request.user.groups.all() | |
beef7690 NBV |
102 | if grp_evaluateurs_recrutement in user_groupes or \ |
103 | grp_drh_recrutement in user_groupes: | |
2d083449 NBV |
104 | return True |
105 | return False | |
106 | ||
cced6a23 | 107 | class ProxyCandidatPiece(CandidatPiece): |
108 | """ | |
109 | Ce proxy sert uniquement dans l'admin à disposer d'un libellé | |
110 | plus ergonomique. | |
111 | """ | |
112 | class Meta: | |
113 | proxy = True | |
114 | verbose_name = "pièce jointe" | |
74cbc7a7 | 115 | verbose_name_plural = "pièces jointes" |
cced6a23 | 116 | |
170c9aa2 | 117 | class CandidatPieceInline(admin.TabularInline): |
cced6a23 | 118 | model = ProxyCandidatPiece |
119 | fields = ('candidat', 'nom', 'path', ) | |
170c9aa2 | 120 | extra = 1 |
121 | ||
27c81d11 | 122 | class ProxyEvaluateur(Evaluateur.candidats.through): |
cced6a23 | 123 | """ |
124 | Ce proxy sert uniquement dans l'admin à disposer d'un libellé | |
125 | plus ergonomique. | |
126 | """ | |
127 | class Meta: | |
128 | proxy = True | |
129 | verbose_name = "évaluateur" | |
130 | ||
eb579d40 | 131 | class EvaluateurInline(admin.TabularInline): |
cced6a23 | 132 | model = ProxyEvaluateur |
720c3ad5 | 133 | fields = ('evaluateur',) |
eb579d40 | 134 | extra = 1 |
135 | ||
d2b30f5f | 136 | class CandidatAdmin(VersionAdmin): |
7f9e891e | 137 | date_hierarchy = 'date_creation' |
0fd8a26d | 138 | list_display = ('nom', 'prenom', 'offre_emploi','statut', |
720c3ad5 | 139 | 'voir_offre_emploi', #'note_evaluateur', |
8941aee7 | 140 | 'calculer_moyenne', 'afficher_candidat',) |
8ea41642 | 141 | list_filter = ('offre_emploi', ) |
7f9e891e | 142 | fieldsets = ( |
4896b661 | 143 | ("Offre d'emploi", { |
144 | 'fields': ('offre_emploi', ) | |
145 | }), | |
7f9e891e | 146 | ('Informations personnelles', { |
147 | 'fields': ('prenom','nom','genre', 'nationalite', 'date_naissance', | |
148 | 'situation_famille', 'nombre_dependant',) | |
149 | }), | |
ec517164 | 150 | ('Coordonnées', { |
151 | 'fields': ('telephone', 'email', 'adresse', 'ville', | |
152 | 'etat_province', 'code_postal', 'pays', ) | |
7f9e891e | 153 | }), |
154 | ('Informations professionnelles', { | |
4896b661 | 155 | 'fields': ('niveau_diplome','employeur_actuel', |
8ea41642 | 156 | 'poste_actuel', 'domaine_professionnel',) |
7f9e891e | 157 | }), |
158 | ('Options avancées', { | |
159 | 'classes': ('collapse',), | |
160 | 'fields': ('actif', 'statut', ) | |
161 | }), | |
162 | ) | |
170c9aa2 | 163 | inlines = [ |
164 | CandidatPieceInline, | |
eb579d40 | 165 | EvaluateurInline, |
170c9aa2 | 166 | ] |
f9983b5a | 167 | |
4e8340cf | 168 | actions = ['affecter_candidats_evaluateur', 'envoyer_courriel_candidats'] |
362a3534 | 169 | # Affecter un évaluateurs à des candidats |
7061f835 | 170 | def affecter_candidats_evaluateur(modeladmin, obj, candidats): |
596fe324 | 171 | selected = obj.POST.getlist(admin.ACTION_CHECKBOX_NAME) |
2adf9e0c | 172 | |
8ea41642 | 173 | return HttpResponseRedirect(reverse('affecter_evaluateurs_candidats')+ |
174 | "?ids=%s" % (",".join(selected))) | |
d835c9f3 | 175 | affecter_candidats_evaluateur.short_description = u'Affecter évaluateur' |
362a3534 | 176 | |
4e8340cf | 177 | # Envoyer un courriel à des candidats |
52765380 | 178 | def envoyer_courriel_candidats(modeladmin, obj, candidats): |
179 | selected = obj.POST.getlist(admin.ACTION_CHECKBOX_NAME) | |
180 | ||
181 | return HttpResponseRedirect(reverse('envoyer_courriel_candidats')+ | |
182 | "?ids=%s" % (",".join(selected))) | |
183 | envoyer_courriel_candidats.short_description = u'Envoyer courriel' | |
184 | ||
05503d56 | 185 | # Évaluer un candidat |
beef7690 NBV |
186 | # TODO: Revérifier, si c'est mieux de rediriger vers Évaluation candidat et ensuite |
187 | # permettre l'évaluation ou laisser le reverse(evaluer_candidat) | |
596fe324 | 188 | def evaluer_candidat(self, obj): |
beef7690 NBV |
189 | return "<a href='%s?candidat__id__exact=%s'>Évaluer le candidat </a>" % \ |
190 | (reverse('admin:recrutement_candidatevaluation_changelist'), | |
191 | obj.id) | |
596fe324 | 192 | evaluer_candidat.allow_tags = True |
beef7690 | 193 | evaluer_candidat.short_description = 'Évaluation' |
596fe324 | 194 | |
7d82fd33 | 195 | # Afficher un candidat |
196 | def afficher_candidat(self, obj): | |
beef7690 | 197 | return "<a href='%s'>Voir le candidat</a>" % (reverse('admin:recrutement_proxycandidat_change', args=(obj.id,))) |
7d82fd33 | 198 | afficher_candidat.allow_tags = True |
f6724c20 | 199 | afficher_candidat.short_description = u'Afficher les détails du candidat' |
7d82fd33 | 200 | |
8941aee7 | 201 | # Voir l'offre d'emploi |
202 | def voir_offre_emploi(self, obj): | |
720c3ad5 NBV |
203 | return "<a href='%s'>Voir l'offre d'emploi</a>" % \ |
204 | (reverse('admin:recrutement_proxyoffreemploi_change', | |
205 | args=(obj.offre_emploi.id,))) | |
8941aee7 | 206 | voir_offre_emploi.allow_tags = True |
207 | voir_offre_emploi.short_description = "Afficher l'offre d'emploi" | |
208 | ||
8941aee7 | 209 | # Calculer la moyenne des notes |
210 | def calculer_moyenne(self, obj): | |
211 | evaluations = CandidatEvaluation.objects.filter(candidat=obj) | |
212 | offre_emploi = obj.offre_emploi | |
213 | ||
f6724c20 NBV |
214 | notes = [evaluation.note for evaluation in evaluations.all() \ |
215 | if evaluation.note is not None] | |
8941aee7 | 216 | |
217 | if len(notes) > 0 and offre_emploi.date_limite <= datetime.date.today(): | |
218 | moyenne_votes = float(sum(notes)) / len(notes) | |
219 | else: | |
220 | moyenne_votes = "Non disponible" | |
221 | return moyenne_votes | |
222 | calculer_moyenne.allow_tags = True | |
223 | calculer_moyenne.short_description = "Moyenne des notes" | |
224 | ||
f6724c20 NBV |
225 | def add_delete_permission(self, request, obj=None) : |
226 | user_groupes = request.user.groups.all() | |
227 | if grp_drh_recrutement in user_groupes or \ | |
228 | grp_administrateurs_recrutement in user_groupes: | |
229 | return True | |
230 | return False | |
4896b661 | 231 | |
f6724c20 NBV |
232 | def has_add_permission(self, request): |
233 | return self.add_delete_permission(request, request) | |
4896b661 | 234 | |
f6724c20 NBV |
235 | def has_delete_permission(self, request, obj=None): |
236 | return self.add_delete_permission(request, request) | |
237 | ||
238 | def has_change_permission(self, request, obj=None): | |
239 | user_groupes = request.user.groups.all() | |
240 | if grp_drh_recrutement in user_groupes or \ | |
2d083449 | 241 | grp_administrateurs_recrutement in user_groupes: |
f6724c20 NBV |
242 | return True |
243 | return False | |
4896b661 | 244 | |
596fe324 | 245 | def queryset(self, obj): |
f9983b5a | 246 | """ |
8ea41642 | 247 | Spécifie un queryset limité, autrement Django exécute un |
248 | select_related() sans paramètre, ce qui a pour effet de charger tous | |
249 | les objets FK, sans limite de profondeur. Dès qu'on arrive, dans les | |
250 | modèles de Region, il existe plusieurs boucles, ce qui conduit à la | |
251 | génération d'une requête infinie. | |
d835c9f3 | 252 | |
f9983b5a | 253 | """ |
f6724c20 NBV |
254 | qs = self.model._default_manager.get_query_set() |
255 | # Si user est superuser afficher tous les candidats | |
256 | user_groupes = obj.user.groups.all() | |
257 | if not grp_drh_recrutement in user_groupes: | |
258 | # Si le user n'est ni un évaluateur ni un administrateur régional, | |
259 | # retourner none | |
260 | ||
261 | # Vérifier groupes | |
262 | if grp_evaluateurs_recrutement in user_groupes: | |
ca73c3c6 NBV |
263 | try: |
264 | user = Evaluateur.objects.get(user=obj.user) | |
265 | except Evaluateur.DoesNotExist: | |
266 | return qs.none() | |
efedc086 NBV |
267 | """ |
268 | elif grp_administrateurs_recrutement in user_groupes: | |
269 | try: | |
270 | user = AdministrateurRegional.objects.get(user=obj.user) | |
271 | except AdministrateurRegional.DoesNotExist: | |
272 | return qs.none() | |
273 | """ | |
f6724c20 NBV |
274 | else: |
275 | return qs.none() | |
f6724c20 NBV |
276 | ids = [c.id for c in user.candidats.all()] |
277 | return qs.select_related('candidats').filter(id__in=ids) | |
278 | return qs.select_related('candidats') | |
279 | ||
280 | class ProxyCandidatAdmin(CandidatAdmin): | |
f6724c20 NBV |
281 | readonly_fields = ('statut', 'offre_emploi', 'prenom', 'nom', |
282 | 'genre', 'nationalite', 'date_naissance', | |
283 | 'situation_famille', 'nombre_dependant', 'telephone', | |
284 | 'email', 'adresse', 'ville', 'etat_province', | |
285 | 'code_postal', 'pays', 'niveau_diplome', | |
286 | 'employeur_actuel', 'poste_actuel', | |
287 | 'domaine_professionnel',) | |
2d083449 NBV |
288 | fieldsets = ( |
289 | ("Offre d'emploi", { | |
290 | 'fields': ('offre_emploi', ) | |
291 | }), | |
292 | ('Informations personnelles', { | |
293 | 'fields': ('prenom','nom','genre', 'nationalite', 'date_naissance', | |
294 | 'situation_famille', 'nombre_dependant',) | |
295 | }), | |
296 | ('Coordonnées', { | |
297 | 'fields': ('telephone', 'email', 'adresse', 'ville', | |
298 | 'etat_province', 'code_postal', 'pays', ) | |
299 | }), | |
300 | ('Informations professionnelles', { | |
301 | 'fields': ('niveau_diplome','employeur_actuel', | |
302 | 'poste_actuel', 'domaine_professionnel',) | |
303 | }), | |
304 | ) | |
f6724c20 | 305 | inlines = [] |
2d083449 | 306 | |
f6724c20 NBV |
307 | def has_add_permission(self, request): |
308 | return False | |
309 | ||
310 | def has_delete_permission(self, request, obj=None): | |
311 | return False | |
2adf9e0c | 312 | |
2d083449 NBV |
313 | def has_change_permission(self, request, obj=None): |
314 | user_groupes = request.user.groups.all() | |
beef7690 NBV |
315 | if grp_drh_recrutement in user_groupes or \ |
316 | grp_administrateurs_recrutement in user_groupes or \ | |
317 | grp_evaluateurs_recrutement in user_groupes: | |
2d083449 NBV |
318 | return True |
319 | return False | |
320 | ||
2e9ee615 | 321 | class CandidatPieceAdmin(admin.ModelAdmin): |
170c9aa2 | 322 | list_display = ('nom', 'candidat', ) |
323 | ||
324 | def queryset(self, request): | |
325 | """ | |
326 | Spécifie un queryset limité, autrement Django exécute un | |
327 | select_related() sans paramètre, ce qui a pour effet de charger tous | |
328 | les objets FK, sans limite de profondeur. Dès qu'on arrive, dans les | |
329 | modèles de Region, il existe plusieurs boucles, ce qui conduit à la | |
330 | génération d'une requête infinie. | |
d835c9f3 | 331 | Affiche la liste de candidats que si le user connecté |
27c81d11 | 332 | possède un Evaluateur |
170c9aa2 | 333 | """ |
334 | qs = self.model._default_manager.get_query_set() | |
335 | return qs.select_related('candidat') | |
2e9ee615 | 336 | |
d2b30f5f | 337 | class EvaluateurAdmin(VersionAdmin): |
eb579d40 | 338 | fieldsets = ( |
f6724c20 | 339 | (None, {'fields': ('user', )}), |
720c3ad5 | 340 | #(None, {'fields': ('candidats',)}), |
eb579d40 | 341 | ) |
4418c732 | 342 | |
b89fef74 | 343 | class AdministrateurRegionalAdmin(VersionAdmin): |
27c81d11 | 344 | pass |
345 | ||
d2b30f5f | 346 | class CandidatEvaluationAdmin(VersionAdmin): |
beef7690 NBV |
347 | list_display = ('_offre_emploi', '_candidat', '_note', '_commentaire', |
348 | 'evaluateur',) | |
349 | readonly_fields = ('candidat', 'evaluateur') | |
350 | fieldsets = ( | |
351 | ('Évaluation du candidat', { | |
352 | 'fields': ('candidat', 'evaluateur', 'note', 'commentaire', ) | |
353 | }), | |
354 | ) | |
355 | ||
356 | def _note(self, obj): | |
357 | """ | |
358 | Si l'évaluateur n'a pas encore donné de note au candidat, indiquer | |
359 | un lien pour Évaluer le candidat. | |
360 | Sinon afficher la note. | |
361 | """ | |
362 | if obj.note is None: | |
363 | return "<a href='%s'>Évaluer le candidat </a>" % \ | |
364 | (reverse('admin:recrutement_candidatevaluation_change', | |
365 | args=(obj.candidat.id,))) | |
366 | return obj.note | |
367 | _note.allow_tags = True | |
368 | _note.short_description = "Votre note" | |
369 | _note.admin_order_field = 'note' | |
370 | ||
371 | def _candidat(self, obj): | |
372 | return "<a href='%s'>%s</a>" \ | |
373 | % (reverse('admin:recrutement_proxycandidat_change', | |
374 | args=(obj.candidat.id,)), obj.candidat) | |
375 | _candidat.allow_tags = True | |
376 | _candidat.short_description = 'Candidat' | |
377 | ||
378 | def _commentaire(self, obj): | |
379 | """ | |
380 | Si l'évaluateur n'a pas encore donné de note au candidat, indiquer | |
381 | dans le champ commentaire, Aucun au lieu de (None) | |
382 | Sinon afficher la note. | |
383 | """ | |
384 | if obj.commentaire is None: | |
385 | return "Aucun" | |
386 | return obj.commentaire | |
387 | _commentaire.allow_tags = True | |
388 | _commentaire.short_description = "Commentaire" | |
720c3ad5 | 389 | |
720c3ad5 | 390 | |
beef7690 NBV |
391 | def _offre_emploi(self, obj): |
392 | return "<a href='%s'>%s</a>" % \ | |
393 | (reverse('admin:recrutement_proxyoffreemploi_change', | |
394 | args=(obj.candidat.offre_emploi.id,)), obj.candidat.offre_emploi) | |
395 | _offre_emploi.allow_tags = True | |
396 | _offre_emploi.short_description = "Voir offre d'emploi" | |
397 | _offre_emploi.admin_order_field = 'offre_emploi' | |
398 | ||
720c3ad5 | 399 | def queryset(self, request): |
beef7690 NBV |
400 | """ |
401 | Afficher uniquement les évaluations de l'évaluateur, sauf si | |
402 | l'utilisateur est super admin. | |
403 | """ | |
720c3ad5 | 404 | qs = self.model._default_manager.get_query_set() |
beef7690 NBV |
405 | user_groupes = request.user.groups.all() |
406 | if grp_drh_recrutement in user_groupes: | |
407 | return qs.select_related('offre_emploi') | |
408 | ||
ca73c3c6 | 409 | try: |
d069cdf1 | 410 | evaluateur = Evaluateur.objects.get(user=request.user) |
ca73c3c6 NBV |
411 | except Evaluateur.DoesNotExist: |
412 | return qs.none() | |
413 | ||
414 | candidats_evaluations = CandidatEvaluation.objects.\ | |
415 | filter(evaluateur=evaluateur) | |
416 | candidats_evaluations_ids = [ce.id for ce in \ | |
417 | candidats_evaluations.all()] | |
418 | return qs.select_related('offre_emploi').\ | |
419 | filter(id__in=candidats_evaluations_ids) | |
596fe324 | 420 | |
4e8340cf | 421 | class CourrielTemplateAdmin(VersionAdmin): |
422 | pass | |
423 | ||
df59fcab | 424 | admin.site.register(OffreEmploi, OffreEmploiAdmin) |
425 | admin.site.register(Candidat, CandidatAdmin) | |
720c3ad5 | 426 | admin.site.register(CandidatEvaluation, CandidatEvaluationAdmin) |
beef7690 | 427 | #admin.site.register(CourrielTemplate, CourrielTemplateAdmin) |
27c81d11 | 428 | admin.site.register(Evaluateur, EvaluateurAdmin) |
beef7690 | 429 | #admin.site.register(AdministrateurRegional, AdministrateurRegionalAdmin) |
f6724c20 NBV |
430 | admin.site.register(ProxyOffreEmploi, ProxyOffreEmploiAdmin) |
431 | admin.site.register(ProxyCandidat, ProxyCandidatAdmin) |