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