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