Commit | Line | Data |
---|---|---|
df59fcab | 1 | # -*- encoding: utf-8 -*- |
2 | ||
1b4c8020 | 3 | import textwrap |
4ba84959 | 4 | |
75f0e87b | 5 | from django.conf import settings |
df59fcab | 6 | from django.contrib import admin |
75f0e87b | 7 | from django.core.urlresolvers import reverse |
97b168d6 | 8 | from django.db.models import Avg |
75f0e87b DB |
9 | from django.forms.models import BaseInlineFormSet |
10 | from django.http import HttpResponseRedirect | |
b31ce2d7 | 11 | from django.shortcuts import redirect |
6067184b | 12 | from reversion.admin import VersionAdmin |
7d9736ba | 13 | |
e949324b | 14 | from auf.django.emploi.models import OffreEmploi, Candidat, CandidatPiece |
4c17e518 | 15 | from auf.django.references.models import Region, Bureau |
7d9736ba | 16 | |
afd3be54 | 17 | from project.groups import get_employe_from_user as get_emp |
17c90428 | 18 | from project.rh import models as rh |
7d9736ba | 19 | |
b31ce2d7 | 20 | from project.recrutement.forms import OffreEmploiForm |
86e4bb65 DB |
21 | from project.recrutement.groups import \ |
22 | grp_drh, grp_drh2, \ | |
23 | grp_directeurs_bureau, \ | |
24 | grp_administrateurs, \ | |
25 | grp_correspondants_rh, \ | |
26 | grp_haute_direction | |
b31ce2d7 | 27 | from project.recrutement.models import \ |
4ba84959 EMS |
28 | Evaluateur, CandidatEvaluation, \ |
29 | ProxyOffreEmploi, ProxyCandidat, MesCandidatEvaluation, \ | |
b31ce2d7 | 30 | CourrielTemplate |
8bf241db | 31 | |
df59fcab | 32 | |
7d9736ba | 33 | ### CONSTANTES |
d333c690 NBV |
34 | IMPLANTATIONS_CENTRALES = [15, 19] |
35 | ||
b31ce2d7 | 36 | |
08a9b6fc EMS |
37 | class BaseAdmin(admin.ModelAdmin): |
38 | ||
39 | class Media: | |
40 | css = {'screen': ('css/admin_custom.css',)} | |
41 | ||
42 | ||
97b168d6 OL |
43 | class OrderedChangeList(admin.views.main.ChangeList): |
44 | """ | |
45 | Surcharge pour appliquer le order_by d'un annotate | |
46 | """ | |
47 | def get_query_set(self): | |
48 | qs = super(OrderedChangeList, self).get_query_set() | |
49 | qs = qs.order_by('-moyenne') | |
50 | return qs | |
51 | ||
b31ce2d7 | 52 | |
08a9b6fc | 53 | class OffreEmploiAdmin(BaseAdmin, VersionAdmin): |
7f9e891e | 54 | date_hierarchy = 'date_creation' |
b31ce2d7 EMS |
55 | list_display = ( |
56 | 'nom', 'date_limite', 'region', 'statut', 'est_affiche', | |
57 | '_candidatsList' | |
58 | ) | |
7d0ae1ba NBV |
59 | exclude = ('actif', 'poste_nom', 'resume',) |
60 | list_filter = ('statut',) | |
c4874d66 | 61 | actions = ['affecter_evaluateurs_offre_emploi', ] |
a084e988 | 62 | form = OffreEmploiForm |
2c3c54ee | 63 | |
7d9736ba | 64 | ### Actions à afficher |
a029f641 NBV |
65 | def get_actions(self, request): |
66 | actions = super(OffreEmploiAdmin, self).get_actions(request) | |
67 | del actions['delete_selected'] | |
540dfae4 | 68 | return actions |
a029f641 | 69 | |
7d9736ba | 70 | ### Affecter un évaluateurs à des offres d'emploi |
b31ce2d7 | 71 | def affecter_evaluateurs_offre_emploi(modeladmin, obj, candidats): |
c4874d66 NBV |
72 | selected = obj.POST.getlist(admin.ACTION_CHECKBOX_NAME) |
73 | ||
b31ce2d7 EMS |
74 | return HttpResponseRedirect( |
75 | reverse('affecter_evaluateurs_offre_emploi') + | |
76 | "?ids=%s" % (",".join(selected)) | |
77 | ) | |
78 | ||
79 | affecter_evaluateurs_offre_emploi.short_description = \ | |
80 | u'Affecter évaluateur(s)' | |
c4874d66 | 81 | |
7d9736ba | 82 | ### Afficher la liste des candidats pour l'offre d'emploi |
b31ce2d7 | 83 | def _candidatsList(self, obj): |
8ea41642 | 84 | return "<a href='%s?offre_emploi__id__exact=%s'>Voir les candidats \ |
85 | </a>" % (reverse('admin:recrutement_candidat_changelist'), obj.id) | |
b31ce2d7 | 86 | _candidatsList.allow_tags = True |
f6724c20 | 87 | _candidatsList.short_description = "Afficher la liste des candidats" |
362a3534 | 88 | |
7d9736ba | 89 | ### Formulaire |
3a542b85 NBV |
90 | def get_form(self, request, obj=None, **kwargs): |
91 | form = super(OffreEmploiAdmin, self).get_form(request, obj, **kwargs) | |
92 | employe = get_emp(request.user) | |
3a542b85 | 93 | user_groupes = request.user.groups.all() |
b31ce2d7 | 94 | |
7d9736ba | 95 | # Region |
b31ce2d7 | 96 | if 'region' in form.declared_fields: |
d333c690 NBV |
97 | region_field = form.declared_fields['region'] |
98 | else: | |
99 | region_field = form.base_fields['region'] | |
100 | ||
86e4bb65 DB |
101 | if grp_drh in user_groupes or \ |
102 | grp_drh2 in user_groupes or \ | |
103 | grp_haute_direction in user_groupes: | |
d333c690 NBV |
104 | region_field.queryset = Region.objects.all() |
105 | else: | |
106 | region_field.queryset = Region.objects.\ | |
107 | filter(id=employe.implantation.region.id) | |
b31ce2d7 | 108 | |
7d9736ba | 109 | # Poste |
b31ce2d7 | 110 | if 'poste' in form.declared_fields: |
d333c690 NBV |
111 | poste_field = form.declared_fields['poste'] |
112 | else: | |
113 | poste_field = form.base_fields['poste'] | |
114 | ||
86e4bb65 DB |
115 | if grp_drh in user_groupes or \ |
116 | grp_drh2 in user_groupes or \ | |
117 | grp_haute_direction in user_groupes: | |
d333c690 NBV |
118 | poste_field.queryset = rh.Poste.objects.all() |
119 | else: | |
7d9736ba NBV |
120 | poste_field.queryset = rh.Poste.objects.\ |
121 | filter(implantation__region=employe.implantation.region).\ | |
122 | exclude(implantation__in=IMPLANTATIONS_CENTRALES) | |
b31ce2d7 | 123 | |
7d9736ba | 124 | # Bureau |
b31ce2d7 | 125 | if 'bureau' in form.declared_fields: |
d333c690 NBV |
126 | bureau_field = form.declared_fields['bureau'] |
127 | else: | |
128 | bureau_field = form.base_fields['bureau'] | |
129 | ||
86e4bb65 DB |
130 | if grp_drh in user_groupes or \ |
131 | grp_drh2 in user_groupes or \ | |
132 | grp_haute_direction in user_groupes: | |
d333c690 NBV |
133 | bureau_field.queryset = Bureau.objects.all() |
134 | else: | |
b31ce2d7 EMS |
135 | bureau_field.queryset = \ |
136 | Bureau.objects.filter(region=employe.implantation.region) | |
137 | ||
3a542b85 | 138 | return form |
b31ce2d7 | 139 | |
7d9736ba | 140 | ### Queryset |
b31ce2d7 | 141 | |
2f78949d | 142 | def queryset(self, request): |
b31ce2d7 EMS |
143 | qs = self.model._default_manager.get_query_set() \ |
144 | .select_related('offre_emploi') | |
f6724c20 | 145 | user_groupes = request.user.groups.all() |
86e4bb65 DB |
146 | if grp_drh in user_groupes or \ |
147 | grp_drh2 in user_groupes or \ | |
148 | grp_haute_direction in user_groupes: | |
940c9dd8 | 149 | return qs |
f6724c20 | 150 | |
86e4bb65 DB |
151 | if grp_directeurs_bureau in user_groupes or \ |
152 | grp_correspondants_rh in user_groupes or \ | |
153 | grp_administrateurs in user_groupes: | |
7d9736ba | 154 | employe = get_emp(request.user) |
940c9dd8 | 155 | return qs.filter(region=employe.implantation.region) |
7d9736ba | 156 | |
c69ecb4f | 157 | if Evaluateur.objects.filter(user=request.user).exists(): |
940c9dd8 | 158 | evaluateur = Evaluateur.objects.get(user=request.user) |
b31ce2d7 EMS |
159 | offre_ids = [ |
160 | e.candidat.offre_emploi_id | |
161 | for e in CandidatEvaluation.objects | |
162 | .select_related('candidat') | |
163 | .filter(evaluateur=evaluateur) | |
164 | ] | |
940c9dd8 OL |
165 | return qs.filter(id__in=offre_ids) |
166 | ||
7d9736ba NBV |
167 | return qs.none() |
168 | ||
169 | ### Permission add, delete, change | |
3a542b85 NBV |
170 | def has_add_permission(self, request): |
171 | user_groupes = request.user.groups.all() | |
26add0fd | 172 | if request.user.is_superuser is True or \ |
86e4bb65 DB |
173 | grp_drh in user_groupes or \ |
174 | grp_drh2 in user_groupes or \ | |
175 | grp_directeurs_bureau in user_groupes or \ | |
176 | grp_administrateurs in user_groupes or \ | |
177 | grp_haute_direction in user_groupes: | |
3a542b85 | 178 | return True |
b31ce2d7 | 179 | return False |
3a542b85 | 180 | |
7d9736ba NBV |
181 | def has_delete_permission(self, request, obj=None): |
182 | user_groupes = request.user.groups.all() | |
26add0fd | 183 | if request.user.is_superuser is True or \ |
86e4bb65 DB |
184 | grp_drh in user_groupes or \ |
185 | grp_drh2 in user_groupes or \ | |
186 | grp_directeurs_bureau in user_groupes or \ | |
187 | grp_administrateurs in user_groupes or \ | |
188 | grp_haute_direction in user_groupes: | |
7d9736ba | 189 | return True |
b31ce2d7 | 190 | return False |
7d9736ba | 191 | |
f6724c20 NBV |
192 | def has_change_permission(self, request, obj=None): |
193 | user_groupes = request.user.groups.all() | |
26add0fd | 194 | if request.user.is_superuser is True or \ |
86e4bb65 DB |
195 | grp_drh in user_groupes or \ |
196 | grp_drh2 in user_groupes or \ | |
197 | grp_directeurs_bureau in user_groupes or \ | |
198 | grp_administrateurs in user_groupes or \ | |
199 | grp_haute_direction in user_groupes: | |
f6724c20 | 200 | return True |
b31ce2d7 EMS |
201 | return False |
202 | ||
f6724c20 NBV |
203 | |
204 | class ProxyOffreEmploiAdmin(OffreEmploiAdmin): | |
b31ce2d7 EMS |
205 | list_display = ( |
206 | 'nom', 'date_limite', 'region', 'statut', 'est_affiche' | |
207 | ) | |
208 | readonly_fields = ( | |
209 | 'description', 'bureau', 'duree_affectation', 'renumeration', | |
210 | 'debut_affectation', 'lieu_affectation', 'nom', 'resume', | |
211 | 'date_limite', 'region', 'poste' | |
212 | ) | |
f6724c20 | 213 | fieldsets = ( |
720c3ad5 | 214 | ('Nom', { |
b31ce2d7 | 215 | 'fields': ('nom',) |
f6724c20 | 216 | }), |
720c3ad5 | 217 | ('Description générale', { |
b31ce2d7 | 218 | 'fields': ('description', 'date_limite',) |
f6724c20 | 219 | }), |
720c3ad5 | 220 | ('Coordonnées', { |
13389dae | 221 | 'fields': ('lieu_affectation', 'bureau', 'region', 'poste',) |
f6724c20 | 222 | }), |
720c3ad5 | 223 | ('Autre', { |
b31ce2d7 EMS |
224 | 'fields': ( |
225 | 'debut_affectation', 'duree_affectation', 'renumeration', | |
226 | ) | |
f6724c20 | 227 | }), |
b31ce2d7 | 228 | ) |
464e5825 | 229 | inlines = [] |
7d9736ba | 230 | |
b31ce2d7 | 231 | ### Lieu de redirection après le change |
a029f641 | 232 | def response_change(self, request, obj): |
b31ce2d7 | 233 | return redirect('admin:recrutement_proxyoffreemploi_changelist') |
a029f641 | 234 | |
be343ed2 NBV |
235 | ### Formulaire |
236 | def get_form(self, request, obj=None, **kwargs): | |
237 | form = super(OffreEmploiAdmin, self).get_form(request, obj, **kwargs) | |
238 | return form | |
239 | ||
7d9736ba | 240 | ### Permissions add, delete, change |
f6724c20 NBV |
241 | def has_add_permission(self, request): |
242 | return False | |
243 | ||
244 | def has_delete_permission(self, request, obj=None): | |
245 | return False | |
246 | ||
2d083449 | 247 | def has_change_permission(self, request, obj=None): |
71aec2c3 OL |
248 | user_groupes = request.user.groups.all() |
249 | if request.user.is_superuser is True or \ | |
86e4bb65 DB |
250 | grp_correspondants_rh in user_groupes or \ |
251 | grp_drh in user_groupes or \ | |
252 | grp_drh2 in user_groupes or \ | |
253 | grp_directeurs_bureau in user_groupes or \ | |
254 | grp_administrateurs in user_groupes or \ | |
255 | grp_haute_direction in user_groupes: | |
71aec2c3 | 256 | return True |
46c508f5 OL |
257 | |
258 | if obj is not None: | |
259 | return True | |
260 | ||
71aec2c3 | 261 | return False |
2d083449 | 262 | |
b31ce2d7 | 263 | |
572c8d08 NBV |
264 | class CandidatPieceInline(admin.TabularInline): |
265 | model = CandidatPiece | |
266 | fields = ('candidat', 'nom', 'path',) | |
267 | extra = 1 | |
268 | max_num = 3 | |
269 | ||
b31ce2d7 | 270 | |
c69ecb4f OL |
271 | class ReadOnlyCandidatPieceInline(CandidatPieceInline): |
272 | readonly_fields = ('candidat', 'nom', 'path', ) | |
273 | cand_delete = False | |
274 | ||
275 | ||
572c8d08 NBV |
276 | class CandidatEvaluationInlineFormSet(BaseInlineFormSet): |
277 | """ | |
278 | Empêche la suppression d'une évaluation pour le CandidatEvaluationInline | |
279 | """ | |
280 | def __init__(self, *args, **kwargs): | |
281 | super(CandidatEvaluationInlineFormSet, self).__init__(*args, **kwargs) | |
b31ce2d7 EMS |
282 | self.can_delete = False |
283 | ||
572c8d08 NBV |
284 | |
285 | class CandidatEvaluationInline(admin.TabularInline): | |
286 | model = CandidatEvaluation | |
287 | fields = ('evaluateur', 'note', 'commentaire') | |
288 | max_num = 0 | |
289 | extra = 0 | |
290 | formset = CandidatEvaluationInlineFormSet | |
7d9736ba | 291 | |
b31ce2d7 | 292 | ### Fields readonly |
572c8d08 NBV |
293 | def get_readonly_fields(self, request, obj=None): |
294 | """ | |
295 | Empêche la modification des évaluations | |
296 | """ | |
297 | if obj: | |
b31ce2d7 | 298 | return self.readonly_fields + ('evaluateur', 'note', 'commentaire') |
572c8d08 NBV |
299 | return self.readonly_fields |
300 | ||
b31ce2d7 | 301 | |
08a9b6fc | 302 | class CandidatAdmin(BaseAdmin, VersionAdmin): |
b31ce2d7 | 303 | search_fields = ('nom', 'prenom') |
7d0ae1ba | 304 | exclude = ('actif', ) |
940c9dd8 | 305 | list_editable = ('statut', ) |
1b4c8020 | 306 | list_display = ('_candidat', 'offre_emploi', |
940c9dd8 OL |
307 | 'voir_offre_emploi', 'calculer_moyenne', |
308 | 'afficher_candidat', '_date_creation', 'statut', ) | |
309 | list_filter = ('offre_emploi', 'offre_emploi__region', 'statut', ) | |
7d0ae1ba | 310 | |
7f9e891e | 311 | fieldsets = ( |
4896b661 | 312 | ("Offre d'emploi", { |
313 | 'fields': ('offre_emploi', ) | |
314 | }), | |
7f9e891e | 315 | ('Informations personnelles', { |
b31ce2d7 EMS |
316 | 'fields': ( |
317 | 'prenom', 'nom', 'genre', 'nationalite', | |
318 | 'situation_famille', 'nombre_dependant' | |
319 | ) | |
7f9e891e | 320 | }), |
ec517164 | 321 | ('Coordonnées', { |
b31ce2d7 EMS |
322 | 'fields': ( |
323 | 'telephone', 'email', 'adresse', 'ville', 'etat_province', | |
324 | 'code_postal', 'pays' | |
325 | ) | |
7f9e891e | 326 | }), |
327 | ('Informations professionnelles', { | |
b31ce2d7 EMS |
328 | 'fields': ( |
329 | 'niveau_diplome', 'employeur_actuel', 'poste_actuel', | |
330 | 'domaine_professionnel' | |
331 | ) | |
332 | }), | |
65c4cbd9 NBV |
333 | ('Traitement', { |
334 | 'fields': ('statut', ) | |
7f9e891e | 335 | }), |
336 | ) | |
170c9aa2 | 337 | inlines = [ |
338 | CandidatPieceInline, | |
572c8d08 | 339 | CandidatEvaluationInline, |
170c9aa2 | 340 | ] |
540dfae4 | 341 | actions = ['envoyer_courriel_candidats'] |
a029f641 | 342 | |
1b4c8020 | 343 | def _candidat(self, obj): |
b31ce2d7 | 344 | txt = u"%s %s (%s)" % (obj.nom.upper(), obj.prenom, obj.genre) |
1b4c8020 OL |
345 | txt = textwrap.wrap(txt, 30) |
346 | return "<br/>".join(txt) | |
347 | _candidat.short_description = "Candidat" | |
348 | _candidat.admin_order_field = "nom" | |
349 | _candidat.allow_tags = True | |
350 | ||
940c9dd8 OL |
351 | def _date_creation(self, obj): |
352 | return obj.date_creation | |
1b4c8020 OL |
353 | _date_creation.admin_order_field = "date_creation" |
354 | _date_creation.short_description = "Date de réception" | |
940c9dd8 | 355 | |
7d9736ba | 356 | ### Actions à afficher |
a029f641 NBV |
357 | def get_actions(self, request): |
358 | actions = super(CandidatAdmin, self).get_actions(request) | |
359 | del actions['delete_selected'] | |
540dfae4 | 360 | return actions |
362a3534 | 361 | |
7d9736ba | 362 | ### Envoyer un courriel à des candidats |
b31ce2d7 | 363 | def envoyer_courriel_candidats(modeladmin, obj, candidats): |
52765380 | 364 | selected = obj.POST.getlist(admin.ACTION_CHECKBOX_NAME) |
365 | ||
b31ce2d7 EMS |
366 | return HttpResponseRedirect( |
367 | reverse('selectionner_template') + "?ids=%s" % (",".join(selected)) | |
368 | ) | |
52765380 | 369 | envoyer_courriel_candidats.short_description = u'Envoyer courriel' |
370 | ||
7d9736ba | 371 | ### Évaluer un candidat |
596fe324 | 372 | def evaluer_candidat(self, obj): |
b31ce2d7 EMS |
373 | return "<a href='%s?candidat__id__exact=%s'>" \ |
374 | "Évaluer le candidat</a>" % ( | |
375 | reverse('admin:recrutement_candidatevaluation_changelist'), | |
376 | obj.id | |
377 | ) | |
378 | evaluer_candidat.allow_tags = True | |
beef7690 | 379 | evaluer_candidat.short_description = 'Évaluation' |
596fe324 | 380 | |
7d9736ba | 381 | ### Afficher un candidat |
7d82fd33 | 382 | def afficher_candidat(self, obj): |
d2cbe75d OL |
383 | items = [u"<li><a href='%s%s'>%s</li>" % \ |
384 | (settings.OE_PRIVE_MEDIA_URL, pj.path, pj.get_nom_display()) \ | |
385 | for pj in obj.pieces_jointes()] | |
b31ce2d7 EMS |
386 | html = "<a href='%s'>Voir le candidat</a>" % ( |
387 | reverse('admin:recrutement_proxycandidat_change', args=(obj.id,)) | |
388 | ) | |
d2cbe75d | 389 | return "%s<ul>%s</ul>" % (html, "\n".join(items)) |
b31ce2d7 | 390 | afficher_candidat.allow_tags = True |
8e0d552d | 391 | afficher_candidat.short_description = u'Détails du candidat' |
7d82fd33 | 392 | |
7d9736ba | 393 | ### Voir l'offre d'emploi |
8941aee7 | 394 | def voir_offre_emploi(self, obj): |
b31ce2d7 EMS |
395 | return "<a href='%s'>Voir l'offre d'emploi</a>" % (reverse( |
396 | 'admin:recrutement_proxyoffreemploi_change', | |
397 | args=(obj.offre_emploi.id,) | |
398 | )) | |
8941aee7 | 399 | voir_offre_emploi.allow_tags = True |
400 | voir_offre_emploi.short_description = "Afficher l'offre d'emploi" | |
401 | ||
7d9736ba | 402 | ### Calculer la moyenne des notes |
8941aee7 | 403 | def calculer_moyenne(self, obj): |
404 | evaluations = CandidatEvaluation.objects.filter(candidat=obj) | |
8941aee7 | 405 | |
940c9dd8 | 406 | notes = [evaluation.note for evaluation in evaluations \ |
f6724c20 | 407 | if evaluation.note is not None] |
b31ce2d7 | 408 | |
7d0ae1ba | 409 | if len(notes) > 0: |
d6790a12 | 410 | moyenne_votes = round(float(sum(notes)) / len(notes), 2) |
8941aee7 | 411 | else: |
412 | moyenne_votes = "Non disponible" | |
940c9dd8 OL |
413 | |
414 | totales = len(evaluations) | |
415 | faites = len(notes) | |
416 | ||
b31ce2d7 | 417 | if obj.statut == 'REC': |
940c9dd8 OL |
418 | if totales == faites: |
419 | color = "green" | |
420 | elif faites > 0 and float(totales) / float(faites) >= 2: | |
421 | color = "orange" | |
422 | else: | |
423 | color = "red" | |
424 | else: | |
425 | color = "black" | |
426 | ||
b31ce2d7 EMS |
427 | return """<span style="color: %s;">%s (%s/%s)</span>""" % ( |
428 | color, moyenne_votes, faites, totales | |
429 | ) | |
8941aee7 | 430 | calculer_moyenne.allow_tags = True |
3eb0be91 | 431 | calculer_moyenne.short_description = "Moyenne" |
d6790a12 | 432 | calculer_moyenne.admin_order_field = "" |
8941aee7 | 433 | |
7d9736ba | 434 | ### Permissions add, delete, change |
3a542b85 | 435 | def has_add_permission(self, request): |
f6724c20 | 436 | user_groupes = request.user.groups.all() |
26add0fd | 437 | if request.user.is_superuser is True or \ |
86e4bb65 DB |
438 | grp_correspondants_rh in user_groupes or \ |
439 | grp_drh in user_groupes or \ | |
440 | grp_drh2 in user_groupes or \ | |
441 | grp_directeurs_bureau in user_groupes or \ | |
442 | grp_administrateurs in user_groupes or \ | |
443 | grp_haute_direction in user_groupes: | |
f6724c20 | 444 | return True |
b31ce2d7 | 445 | return False |
4896b661 | 446 | |
f6724c20 | 447 | def has_delete_permission(self, request, obj=None): |
3a542b85 | 448 | user_groupes = request.user.groups.all() |
26add0fd | 449 | if request.user.is_superuser is True or \ |
86e4bb65 DB |
450 | grp_correspondants_rh in user_groupes or \ |
451 | grp_drh in user_groupes or \ | |
452 | grp_drh2 in user_groupes or \ | |
453 | grp_directeurs_bureau in user_groupes or \ | |
454 | grp_administrateurs in user_groupes or \ | |
455 | grp_haute_direction in user_groupes: | |
3a542b85 | 456 | return True |
b31ce2d7 | 457 | return False |
f6724c20 NBV |
458 | |
459 | def has_change_permission(self, request, obj=None): | |
460 | user_groupes = request.user.groups.all() | |
26add0fd | 461 | if request.user.is_superuser is True or \ |
86e4bb65 DB |
462 | grp_correspondants_rh in user_groupes or \ |
463 | grp_drh in user_groupes or \ | |
464 | grp_drh2 in user_groupes or \ | |
465 | grp_directeurs_bureau in user_groupes or \ | |
466 | grp_administrateurs in user_groupes or \ | |
467 | grp_haute_direction in user_groupes: | |
f6724c20 | 468 | return True |
97b168d6 OL |
469 | return False |
470 | ||
471 | def get_changelist(self, request, **kwargs): | |
472 | return OrderedChangeList | |
4896b661 | 473 | |
d46075cb | 474 | def queryset(self, request): |
f9983b5a | 475 | """ |
b31ce2d7 EMS |
476 | Spécifie un queryset limité, autrement Django exécute un |
477 | select_related() sans paramètre, ce qui a pour effet de charger tous | |
478 | les objets FK, sans limite de profondeur. Dès qu'on arrive, dans les | |
479 | modèles de Region, il existe plusieurs boucles, ce qui conduit à la | |
8ea41642 | 480 | génération d'une requête infinie. |
f9983b5a | 481 | """ |
b31ce2d7 EMS |
482 | qs = self.model._default_manager.get_query_set() \ |
483 | .select_related('offre_emploi') \ | |
484 | .annotate(moyenne=Avg('evaluations__note')) | |
97b168d6 | 485 | |
d46075cb | 486 | user_groupes = request.user.groups.all() |
86e4bb65 DB |
487 | if grp_drh in user_groupes or \ |
488 | grp_drh2 in user_groupes or \ | |
489 | grp_haute_direction in user_groupes: | |
d6790a12 | 490 | return qs |
7d9736ba | 491 | |
86e4bb65 DB |
492 | if grp_directeurs_bureau in user_groupes or \ |
493 | grp_correspondants_rh in user_groupes or \ | |
494 | grp_administrateurs in user_groupes: | |
7d9736ba | 495 | employe = get_emp(request.user) |
d6790a12 | 496 | return qs.filter(offre_emploi__region=employe.implantation.region) |
7d9736ba | 497 | |
c69ecb4f | 498 | if Evaluateur.objects.filter(user=request.user).exists(): |
940c9dd8 OL |
499 | evaluateur = Evaluateur.objects.get(user=request.user) |
500 | candidat_ids = [e.candidat.id for e in | |
501 | CandidatEvaluation.objects.filter(evaluateur=evaluateur)] | |
d6790a12 | 502 | return qs.filter(id__in=candidat_ids) |
b31ce2d7 | 503 | return qs.none() |
f6724c20 | 504 | |
613e8dfe | 505 | |
f6724c20 | 506 | class ProxyCandidatAdmin(CandidatAdmin): |
940c9dd8 | 507 | list_editable = () |
b31ce2d7 EMS |
508 | readonly_fields = ( |
509 | 'statut', 'offre_emploi', 'prenom', 'nom', 'genre', 'nationalite', | |
510 | 'situation_famille', 'nombre_dependant', 'telephone', 'email', | |
511 | 'adresse', 'ville', 'etat_province', 'code_postal', 'pays', | |
512 | 'niveau_diplome', 'employeur_actuel', 'poste_actuel', | |
513 | 'domaine_professionnel', 'pieces_jointes' | |
514 | ) | |
2d083449 NBV |
515 | fieldsets = ( |
516 | ("Offre d'emploi", { | |
517 | 'fields': ('offre_emploi', ) | |
518 | }), | |
519 | ('Informations personnelles', { | |
b31ce2d7 EMS |
520 | 'fields': ( |
521 | 'prenom', 'nom', 'genre', 'nationalite', 'situation_famille', | |
522 | 'nombre_dependant' | |
523 | ) | |
2d083449 NBV |
524 | }), |
525 | ('Coordonnées', { | |
b31ce2d7 EMS |
526 | 'fields': ( |
527 | 'telephone', 'email', 'adresse', 'ville', 'etat_province', | |
528 | 'code_postal', 'pays' | |
529 | ) | |
2d083449 NBV |
530 | }), |
531 | ('Informations professionnelles', { | |
b31ce2d7 EMS |
532 | 'fields': ( |
533 | 'niveau_diplome', 'employeur_actuel', 'poste_actuel', | |
534 | 'domaine_professionnel' | |
535 | ) | |
536 | }), | |
2d083449 | 537 | ) |
c69ecb4f | 538 | inlines = (CandidatEvaluationInline, ) |
2d083449 | 539 | |
f6724c20 NBV |
540 | def has_add_permission(self, request): |
541 | return False | |
542 | ||
543 | def has_delete_permission(self, request, obj=None): | |
544 | return False | |
2adf9e0c | 545 | |
2d083449 | 546 | def has_change_permission(self, request, obj=None): |
71aec2c3 OL |
547 | user_groupes = request.user.groups.all() |
548 | if request.user.is_superuser is True or \ | |
86e4bb65 DB |
549 | grp_correspondants_rh in user_groupes or \ |
550 | grp_drh in user_groupes or \ | |
551 | grp_drh2 in user_groupes or \ | |
552 | grp_directeurs_bureau in user_groupes or \ | |
553 | grp_administrateurs in user_groupes or \ | |
554 | grp_haute_direction in user_groupes: | |
71aec2c3 | 555 | return True |
b44ee2a0 OL |
556 | |
557 | if obj is not None: | |
558 | evaluateur = Evaluateur.objects.get(user=request.user) | |
559 | for e in obj.evaluations.all(): | |
560 | if e.evaluateur == evaluateur: | |
561 | return True | |
562 | ||
71aec2c3 | 563 | return False |
2d083449 | 564 | |
fe6fe6bb OL |
565 | def get_actions(self, request): |
566 | return None | |
567 | ||
b31ce2d7 | 568 | |
2e9ee615 | 569 | class CandidatPieceAdmin(admin.ModelAdmin): |
170c9aa2 | 570 | list_display = ('nom', 'candidat', ) |
571 | ||
7d9736ba | 572 | ### Queryset |
170c9aa2 | 573 | def queryset(self, request): |
574 | """ | |
b31ce2d7 EMS |
575 | Spécifie un queryset limité, autrement Django exécute un |
576 | select_related() sans paramètre, ce qui a pour effet de charger tous | |
577 | les objets FK, sans limite de profondeur. Dès qu'on arrive, dans les | |
578 | modèles de Region, il existe plusieurs boucles, ce qui conduit à la | |
579 | génération d'une requête infinie. Affiche la liste de candidats que | |
580 | si le user connecté possède un Evaluateur | |
170c9aa2 | 581 | """ |
582 | qs = self.model._default_manager.get_query_set() | |
583 | return qs.select_related('candidat') | |
2e9ee615 | 584 | |
b31ce2d7 | 585 | |
08a9b6fc | 586 | class EvaluateurAdmin(BaseAdmin, VersionAdmin): |
eb579d40 | 587 | fieldsets = ( |
540dfae4 NBV |
588 | ("Utilisateur", { |
589 | 'fields': ('user',) | |
590 | }), | |
eb579d40 | 591 | ) |
4418c732 | 592 | |
7d9736ba | 593 | ### Actions à afficher |
a029f641 NBV |
594 | def get_actions(self, request): |
595 | actions = super(EvaluateurAdmin, self).get_actions(request) | |
596 | del actions['delete_selected'] | |
540dfae4 | 597 | return actions |
a029f641 | 598 | |
7d9736ba NBV |
599 | ### Permissions add, delete, change |
600 | def has_add_permission(self, request): | |
601 | user_groupes = request.user.groups.all() | |
26add0fd | 602 | if request.user.is_superuser is True or \ |
86e4bb65 DB |
603 | grp_drh in user_groupes or \ |
604 | grp_drh2 in user_groupes or \ | |
605 | grp_haute_direction in user_groupes: | |
7d9736ba | 606 | return True |
b31ce2d7 | 607 | return False |
7d9736ba NBV |
608 | |
609 | def has_delete_permission(self, request, obj=None): | |
610 | user_groupes = request.user.groups.all() | |
26add0fd | 611 | if request.user.is_superuser is True or \ |
86e4bb65 DB |
612 | grp_drh in user_groupes or \ |
613 | grp_drh2 in user_groupes or \ | |
614 | grp_haute_direction in user_groupes: | |
7d9736ba | 615 | return True |
b31ce2d7 | 616 | return False |
7d9736ba NBV |
617 | |
618 | def has_change_permission(self, request, obj=None): | |
619 | user_groupes = request.user.groups.all() | |
26add0fd | 620 | if request.user.is_superuser is True or \ |
86e4bb65 DB |
621 | grp_drh in user_groupes or \ |
622 | grp_drh2 in user_groupes or \ | |
623 | grp_haute_direction in user_groupes: | |
7d9736ba | 624 | return True |
b31ce2d7 EMS |
625 | return False |
626 | ||
27c81d11 | 627 | |
08a9b6fc | 628 | class CandidatEvaluationAdmin(BaseAdmin): |
b31ce2d7 EMS |
629 | search_fields = ('candidat__nom', 'candidat__prenom') |
630 | list_display = ( | |
631 | '_candidat', '_statut', '_offre_emploi', 'evaluateur', '_note', | |
632 | '_commentaire' | |
633 | ) | |
940c9dd8 OL |
634 | readonly_fields = ('candidat', 'evaluateur') |
635 | list_filter = ('candidat__statut', 'candidat__offre_emploi',) | |
beef7690 NBV |
636 | fieldsets = ( |
637 | ('Évaluation du candidat', { | |
b31ce2d7 | 638 | 'fields': ('candidat', 'evaluateur', 'note', 'commentaire', ) |
beef7690 NBV |
639 | }), |
640 | ) | |
641 | ||
a029f641 | 642 | def get_actions(self, request): |
5fe6986f OL |
643 | # on stocke l'evaluateur connecté (pas forcément la meilleure place...) |
644 | try: | |
645 | self.evaluateur = Evaluateur.objects.get(user=request.user) | |
646 | except: | |
647 | self.evaluateur = None | |
648 | ||
a029f641 NBV |
649 | actions = super(CandidatEvaluationAdmin, self).get_actions(request) |
650 | del actions['delete_selected'] | |
540dfae4 | 651 | return actions |
a029f641 | 652 | |
7d9736ba | 653 | ### Afficher la note |
beef7690 NBV |
654 | def _note(self, obj): |
655 | """ | |
656 | Si l'évaluateur n'a pas encore donné de note au candidat, indiquer | |
657 | un lien pour Évaluer le candidat. | |
658 | Sinon afficher la note. | |
659 | """ | |
c44cb3de OL |
660 | page = self.model.__name__.lower() |
661 | redirect_url = 'admin:recrutement_%s_change' % page | |
b31ce2d7 | 662 | |
beef7690 | 663 | if obj.note is None: |
5fe6986f OL |
664 | label = "Candidat non évalué" |
665 | else: | |
666 | label = obj.note | |
667 | ||
668 | if self.evaluateur == obj.evaluateur: | |
b31ce2d7 EMS |
669 | return "<a href='%s'>%s</a>" % ( |
670 | reverse(redirect_url, args=(obj.id,)), label | |
671 | ) | |
5fe6986f OL |
672 | else: |
673 | return label | |
beef7690 | 674 | _note.allow_tags = True |
b31ce2d7 EMS |
675 | _note.short_description = "Note" |
676 | _note.admin_order_field = 'note' | |
beef7690 | 677 | |
940c9dd8 OL |
678 | def _statut(self, obj): |
679 | return obj.candidat.get_statut_display() | |
680 | _statut.order_field = 'candidat__statut' | |
681 | _statut.short_description = 'Statut' | |
682 | ||
7d9736ba | 683 | ### Lien en lecture seule vers le candidat |
beef7690 NBV |
684 | def _candidat(self, obj): |
685 | return "<a href='%s'>%s</a>" \ | |
b31ce2d7 | 686 | % (reverse('admin:recrutement_proxycandidat_change', |
beef7690 | 687 | args=(obj.candidat.id,)), obj.candidat) |
b31ce2d7 | 688 | _candidat.allow_tags = True |
beef7690 NBV |
689 | _candidat.short_description = 'Candidat' |
690 | ||
7d9736ba | 691 | ### Afficher commentaire |
beef7690 NBV |
692 | def _commentaire(self, obj): |
693 | """ | |
694 | Si l'évaluateur n'a pas encore donné de note au candidat, indiquer | |
695 | dans le champ commentaire, Aucun au lieu de (None) | |
696 | Sinon afficher la note. | |
697 | """ | |
698 | if obj.commentaire is None: | |
699 | return "Aucun" | |
700 | return obj.commentaire | |
701 | _commentaire.allow_tags = True | |
b31ce2d7 | 702 | _commentaire.short_description = "Commentaire" |
720c3ad5 | 703 | |
7d9736ba | 704 | ### Afficher offre d'emploi |
beef7690 NBV |
705 | def _offre_emploi(self, obj): |
706 | return "<a href='%s'>%s</a>" % \ | |
b31ce2d7 | 707 | (reverse('admin:recrutement_proxyoffreemploi_change', |
dc7faf2b | 708 | args=(obj.candidat.offre_emploi.id,)), obj.candidat.offre_emploi) |
beef7690 NBV |
709 | _offre_emploi.allow_tags = True |
710 | _offre_emploi.short_description = "Voir offre d'emploi" | |
b31ce2d7 | 711 | |
7d9736ba | 712 | def has_add_permission(self, request): |
940c9dd8 OL |
713 | return False |
714 | ||
715 | def has_delete_permission(self, request, obj=None): | |
716 | return False | |
7d9736ba | 717 | |
21b02da5 NBV |
718 | def has_change_permission(self, request, obj=None): |
719 | """ | |
720 | Permettre la visualisation dans la changelist | |
721 | mais interdire l'accès à modifier l'objet si l'évaluateur n'est pas | |
722 | le request.user | |
723 | """ | |
f133459f OL |
724 | user_groupes = request.user.groups.all() |
725 | ||
3bc5ea42 | 726 | if request.user.is_superuser or \ |
86e4bb65 DB |
727 | grp_drh in user_groupes or \ |
728 | grp_drh2 in user_groupes or \ | |
729 | grp_correspondants_rh in user_groupes or \ | |
730 | grp_directeurs_bureau in user_groupes or \ | |
731 | grp_administrateurs in user_groupes or \ | |
732 | grp_haute_direction in user_groupes: | |
c5a263d6 | 733 | is_recrutement = True |
f133459f | 734 | else: |
6c6c51bb | 735 | is_recrutement = False |
f133459f | 736 | |
f6996aa3 | 737 | return is_recrutement |
f133459f | 738 | |
720c3ad5 | 739 | def queryset(self, request): |
beef7690 | 740 | """ |
b31ce2d7 | 741 | Afficher uniquement les évaluations de l'évaluateur, sauf si |
7d9736ba | 742 | l'utilisateur est dans les groupes suivants. |
beef7690 | 743 | """ |
b31ce2d7 EMS |
744 | qs = self.model._default_manager.get_query_set() \ |
745 | .select_related('offre_emploi') | |
beef7690 | 746 | user_groupes = request.user.groups.all() |
940c9dd8 | 747 | |
86e4bb65 DB |
748 | if grp_drh in user_groupes or \ |
749 | grp_drh2 in user_groupes or \ | |
750 | grp_correspondants_rh in user_groupes or \ | |
751 | grp_directeurs_bureau in user_groupes or \ | |
752 | grp_administrateurs in user_groupes or \ | |
753 | grp_haute_direction in user_groupes: | |
940c9dd8 OL |
754 | return qs |
755 | ||
b31ce2d7 | 756 | evaluateur = Evaluateur.objects.get(user=request.user) |
940c9dd8 OL |
757 | candidats_evaluations = \ |
758 | CandidatEvaluation.objects.filter(evaluateur=evaluateur, | |
759 | candidat__statut__in=('REC', )) | |
760 | candidats_evaluations_ids = [ce.id for ce in candidats_evaluations] | |
761 | return qs.filter(id__in=candidats_evaluations_ids) | |
596fe324 | 762 | |
3bc5ea42 OL |
763 | |
764 | class MesCandidatEvaluationAdmin(CandidatEvaluationAdmin): | |
765 | ||
766 | def has_change_permission(self, request, obj=None): | |
767 | try: | |
768 | Evaluateur.objects.get(user=request.user) | |
769 | is_evaluateur = True | |
770 | except: | |
771 | is_evaluateur = False | |
772 | ||
5fe6986f | 773 | if obj is None and is_evaluateur: |
3bc5ea42 OL |
774 | return True |
775 | ||
776 | try: | |
777 | return request.user == obj.evaluateur.user | |
778 | except: | |
779 | return False | |
780 | ||
781 | def queryset(self, request): | |
b31ce2d7 EMS |
782 | qs = self.model._default_manager.get_query_set() \ |
783 | .select_related('offre_emploi') | |
784 | evaluateur = Evaluateur.objects.get(user=request.user) | |
3bc5ea42 OL |
785 | candidats_evaluations = \ |
786 | CandidatEvaluation.objects.filter(evaluateur=evaluateur, | |
787 | candidat__statut__in=('REC', )) | |
788 | candidats_evaluations_ids = [ce.id for ce in candidats_evaluations] | |
789 | return qs.filter(id__in=candidats_evaluations_ids) | |
790 | ||
791 | ||
08a9b6fc | 792 | class CourrielTemplateAdmin(BaseAdmin, VersionAdmin): |
7d9736ba | 793 | ### Actions à afficher |
a029f641 NBV |
794 | def get_actions(self, request): |
795 | actions = super(CourrielTemplateAdmin, self).get_actions(request) | |
796 | del actions['delete_selected'] | |
540dfae4 | 797 | return actions |
4e8340cf | 798 | |
df59fcab | 799 | admin.site.register(OffreEmploi, OffreEmploiAdmin) |
382501c1 | 800 | admin.site.register(ProxyOffreEmploi, ProxyOffreEmploiAdmin) |
df59fcab | 801 | admin.site.register(Candidat, CandidatAdmin) |
382501c1 | 802 | admin.site.register(ProxyCandidat, ProxyCandidatAdmin) |
720c3ad5 | 803 | admin.site.register(CandidatEvaluation, CandidatEvaluationAdmin) |
3bc5ea42 | 804 | admin.site.register(MesCandidatEvaluation, MesCandidatEvaluationAdmin) |
27c81d11 | 805 | admin.site.register(Evaluateur, EvaluateurAdmin) |
32834000 | 806 | admin.site.register(CourrielTemplate, CourrielTemplateAdmin) |