[#3217] Corriger l'emplacement des filtres dans l'admin
[auf_rh_dae.git] / project / rh / admin.py
1 # -*- encoding: utf-8 -*-
2
3 import datetime
4
5 from ajax_select import make_ajax_form
6 from auf.django.metadata.admin import \
7 AUFMetadataAdminMixin, AUFMetadataInlineAdminMixin, \
8 AUF_METADATA_READONLY_FIELDS
9 from django.core.urlresolvers import reverse
10 from django.contrib import admin
11 from django.conf import settings
12 from django.db.models import Q, Count
13 from django.template.defaultfilters import date
14
15 import auf.django.references.models as ref
16 import models as rh
17 from forms import \
18 ContratForm, AyantDroitForm, EmployeAdminForm, AjaxSelect, DossierForm
19 from dae.utils import get_employe_from_user
20 from change_list import ChangeList
21 from groups import grp_correspondants_rh
22 from decorators import in_drh_or_admin
23
24
25 class BaseAdmin(admin.ModelAdmin):
26
27 class Media:
28 css = {'screen': ('css/admin_custom.css',)}
29
30
31 class ArchiveMixin(object):
32 """
33 Archive Mixin pour gérer le queryset et le display
34 NON COMPRIS : list_filter, et list_display, field à setter dans la classe.
35 """
36
37 def queryset(self, request):
38 return self.model._base_manager
39
40 def _archive(self, obj):
41 if obj.archive:
42 return "oui"
43 else:
44 return "non"
45 _archive.short_description = u'Archivé'
46 _archive.admin_order_field = 'archive'
47
48
49 class RegionProxy(ref.Region):
50 """ Proxy utilisé pour les organigrammes par région """
51 class Meta:
52 proxy = True
53 verbose_name = u"Organigramme par région"
54 verbose_name_plural = u"Organigramme par région"
55
56
57 class ImplantationProxy(ref.Implantation):
58 """ Proxy utilisé pour les organigrammes par implantation """
59 class Meta:
60 proxy = True
61 verbose_name = u"Organigramme par implantations"
62 verbose_name_plural = u"Organigramme par implantations"
63
64
65 class ServiceProxy(rh.Service):
66 """ Proxy utilisé pour les organigrammes opar service """
67
68 class Meta:
69 proxy = True
70 verbose_name = u"Organigramme par services"
71 verbose_name_plural = u"Organigramme par services"
72
73
74 class EmployeProxy(rh.Employe):
75 """ Proxy utilisé pour les organigrammes des employés """
76 class Meta:
77 proxy = True
78 verbose_name = u"Organigramme des employés"
79 verbose_name_plural = u"Organigramme des employés"
80
81
82 class DateRangeMixin(object):
83 prefixe_recherche_temporelle = ""
84
85 def get_changelist(self, request, **kwargs):
86 if 'HTTP_REFERER' in request.META.keys():
87 referer = request.META['HTTP_REFERER']
88 referer = "/".join(referer.split('/')[3:])
89 referer = "/%s" % referer.split('?')[0]
90 change_list_view = 'admin:%s_%s_changelist' % (
91 self.model._meta.app_label,
92 self.model.__name__.lower(),)
93 if referer != reverse(change_list_view):
94 params = request.GET.copy()
95 params.update({'statut': 'Actif'})
96 request.GET = params
97 return ChangeList
98
99
100 # Override of the InlineModelAdmin to support the link in the tabular inline
101 class LinkedInline(admin.options.InlineModelAdmin):
102 template = "admin/linked.html"
103 admin_model_path = None
104
105 def __init__(self, *args):
106 super(LinkedInline, self).__init__(*args)
107 if self.admin_model_path is None:
108 self.admin_model_path = self.model.__name__.lower()
109
110
111 class ProtectRegionMixin(object):
112
113 def queryset(self, request):
114 qs = super(ProtectRegionMixin, self).queryset(request)
115
116 user_groups = request.user.groups.all()
117 if in_drh_or_admin(request.user):
118 return qs
119
120 if grp_correspondants_rh in user_groups:
121 employe = get_employe_from_user(request.user)
122 q = Q(**{self.model.prefix_implantation: \
123 employe.implantation.region})
124 qs = qs.filter(q).distinct()
125 return qs
126 return qs.none()
127
128 def has_add_permission(self, request):
129 if not in_drh_or_admin(request.user):
130 return False
131 else:
132 return True
133
134 def has_change_permission(self, request, obj=None):
135 user_groups = request.user.groups.all()
136
137 # Lock pour autoriser uniquement les DRH à utiliser RH
138 if not in_drh_or_admin(request.user):
139 return False
140
141 if len(user_groups) == 0 and not request.user.is_superuser:
142 return False
143
144 if obj is None:
145 return True
146 ids = [o.id for o in self.queryset(request)]
147 return obj.id in ids
148
149
150 # Inlines
151
152 class ReadOnlyInlineMixin(object):
153
154 def get_readonly_fields(self, request, obj=None):
155 return [f.name for f in self.model._meta.fields \
156 if f.name not in AUF_METADATA_READONLY_FIELDS]
157
158
159 class AyantDroitInline(AUFMetadataInlineAdminMixin, admin.StackedInline):
160 model = rh.AyantDroit
161 form = AyantDroitForm
162 extra = 0
163
164 fieldsets = (
165 (None, {
166 'fields': (
167 ('nom', 'prenom'),
168 ('nom_affichage', 'genre'),
169 'nationalite',
170 'date_naissance',
171 'lien_parente',
172 )}),
173 )
174
175
176 class AyantDroitCommentaireInline(AUFMetadataInlineAdminMixin, \
177 admin.TabularInline):
178 readonly_fields = ('owner', )
179 model = rh.AyantDroitCommentaire
180 extra = 1
181
182
183 class ContratInline(AUFMetadataInlineAdminMixin, admin.TabularInline):
184 form = ContratForm
185 model = rh.Contrat
186 extra = 1
187
188
189 class DossierROInline(ReadOnlyInlineMixin, LinkedInline):
190 template = "admin/rh/dossier/linked.html"
191 exclude = AUF_METADATA_READONLY_FIELDS
192 model = rh.Dossier
193 extra = 0
194 can_delete = False
195
196 def has_add_permission(self, request=None):
197 return False
198
199 def has_change_permission(self, request, obj=None):
200 return False
201
202 def has_delete_permission(self, request, obj=None):
203 return False
204
205
206 class DossierCommentaireInline(AUFMetadataInlineAdminMixin, \
207 admin.TabularInline):
208 readonly_fields = ('owner', )
209 model = rh.DossierCommentaire
210 extra = 1
211
212
213 class DossierPieceInline(admin.TabularInline):
214 model = rh.DossierPiece
215 extra = 4
216
217
218 class EmployeInline(admin.TabularInline):
219 model = rh.Employe
220
221
222 class EmployeCommentaireInline(AUFMetadataInlineAdminMixin, \
223 admin.TabularInline):
224 readonly_fields = ('owner', )
225 model = rh.EmployeCommentaire
226 extra = 1
227
228
229 class EmployePieceInline(admin.TabularInline):
230 model = rh.EmployePiece
231 extra = 4
232
233
234 class PosteCommentaireInline(AUFMetadataInlineAdminMixin, admin.TabularInline):
235 readonly_fields = ('owner', )
236 model = rh.PosteCommentaire
237 extra = 1
238
239
240 class PosteFinancementInline(admin.TabularInline):
241 model = rh.PosteFinancement
242
243
244 class PostePieceInline(admin.TabularInline):
245 model = rh.PostePiece
246
247
248 class RemunerationInline(AUFMetadataInlineAdminMixin, admin.TabularInline):
249 model = rh.Remuneration
250 extra = 1
251
252
253 class RemunerationROInline(ReadOnlyInlineMixin, RemunerationInline):
254 pass
255
256
257 class TypePosteInline(AUFMetadataInlineAdminMixin, admin.TabularInline):
258 model = rh.TypePoste
259
260
261 class PosteComparaisonInline(AUFMetadataInlineAdminMixin, admin.TabularInline):
262 model = rh.PosteComparaison
263
264
265 class ClassementAdmin(AUFMetadataAdminMixin, BaseAdmin):
266 list_display = ('_classement', '_date_modification', 'user_modification', )
267 fieldsets = AUFMetadataAdminMixin.fieldsets + (
268 (None, {
269 'fields': ('type', 'echelon', 'degre', 'coefficient',)}),
270 )
271
272 def _classement(self, obj):
273 return unicode(obj)
274 _classement.short_description = u"Classement"
275
276 def _date_modification(self, obj):
277 return date(obj.date_modification) \
278 if obj.date_modification is not None else "(aucune)"
279 _date_modification.short_description = u'date modification'
280 _date_modification.admin_order_field = 'date_modification'
281
282
283 class DeviseAdmin(AUFMetadataAdminMixin, BaseAdmin, ArchiveMixin):
284 list_display = (
285 'code',
286 'nom',
287 '_archive',
288 '_date_modification',
289 'user_modification',
290 )
291 list_filter = ('archive', )
292 fieldsets = AUFMetadataAdminMixin.fieldsets + (
293 (None, {
294 'fields': ('code', 'nom', 'archive', ),
295 }),
296 )
297
298 def _date_modification(self, obj):
299 return date(obj.date_modification) \
300 if obj.date_modification is not None else "(aucune)"
301 _date_modification.short_description = u'date modification'
302 _date_modification.admin_order_field = 'date_modification'
303
304
305 class DossierAdmin(DateRangeMixin, AUFMetadataAdminMixin,
306 ProtectRegionMixin, BaseAdmin, AjaxSelect):
307 alphabet_filter = 'employe__nom'
308 search_fields = (
309 'id',
310 'employe__id',
311 'poste__id',
312 'employe__nom',
313 'employe__prenom',
314 'poste__nom',
315 'poste__nom_feminin',
316 'poste__implantation__nom',
317 )
318 list_display = (
319 '_id',
320 '_apercu',
321 '_nom',
322 '_poste',
323 '_employe',
324 '_date_debut',
325 '_date_fin',
326 '_date_modification',
327 'user_modification',
328 '_dae',
329 )
330 list_display_links = ('_nom',)
331 list_filter = (
332 'poste__implantation__region',
333 'poste__implantation',
334 'poste__type_poste__categorie_emploi',
335 'poste__type_poste',
336 'rh_contrats__type_contrat',
337 'principal',
338 )
339 inlines = (DossierPieceInline, ContratInline,
340 RemunerationInline,
341 DossierCommentaireInline,
342 )
343 fieldsets = AUFMetadataAdminMixin.fieldsets + (
344 (None, {
345 'fields': (
346 'employe',
347 'poste',
348 'principal',
349 'statut',
350 'organisme_bstg',)}),
351 ('Recrutement', {
352 'fields': (
353 'statut_residence',
354 'remplacement',
355 'remplacement_de', )}),
356 ('Rémunération', {
357 'fields': (
358 'classement',
359 ('regime_travail', 'regime_travail_nb_heure_semaine'),)}),
360 ('Occupation du Poste par cet Employe', {
361 'fields': (('date_debut', 'date_fin'), )}
362 ),
363 )
364 form = make_ajax_form(rh.Dossier, {
365 'employe': 'employes',
366 'poste': 'postes',
367 'remplacement_de': 'dossiers',
368 }, superclass=DossierForm)
369
370 def lookup_allowed(self, key, value):
371 if key in (
372 'employe__nom__istartswith',
373 'poste__implantation__region__id__exact',
374 'poste__implantation__id__exact',
375 'poste__type_poste__id__exact',
376 'poste__type_poste__categorie_emploi__id__exact',
377 'rh_contrats__type_contrat__id__exact',
378 'principal__exact',
379 'principal__isnull',
380 ):
381 return True
382
383 def _id(self, obj):
384 return obj.id
385 _id.short_description = u"#"
386 _id.admin_order_field = "id"
387
388 def _nom(self, obj):
389 return "%d : %s %s" % (
390 obj.date_debut.year,
391 obj.employe.nom.upper(),
392 obj.employe.prenom)
393 _nom.allow_tags = True
394 _nom.short_description = u"Dossier"
395
396 def _apercu(self, d):
397 apercu_link = u"""<a title="Aperçu du dossier"
398 onclick="return showAddAnotherPopup(this);"
399 href='%s'>
400 <img src="%simg/loupe.png" />
401 </a>""" % \
402 (reverse('dossier_apercu', args=(d.id,)),
403 settings.STATIC_URL,
404 )
405 return apercu_link
406 _apercu.allow_tags = True
407 _apercu.short_description = u""
408
409 def _dae(self, d):
410 apercu_link = ""
411 dossiers_dae = d.dossiers_dae.all()
412 if len(dossiers_dae) > 0:
413 dossier_dae = dossiers_dae[0]
414 apercu_link = u"""<a title="Aperçu du dossier"
415 onclick="return showAddAnotherPopup(this);"
416 href='%s'>
417 <img src="%simg/loupe.png" />
418 </a>""" % \
419 (reverse('embauche_consulter', args=(dossier_dae.id,)),
420 settings.STATIC_URL,
421 )
422 return apercu_link
423 _dae.allow_tags = True
424 _dae.short_description = u"DAE"
425
426 def _date_debut(self, obj):
427 return date(obj.date_debut)
428
429 _date_debut.short_description = u'Occupation début'
430 _date_debut.admin_order_field = 'date_debut'
431
432 def _date_fin(self, obj):
433 return date(obj.date_fin)
434 _date_fin.short_description = u'Occupation fin'
435 _date_fin.admin_order_field = 'date_fin'
436
437 def _date_modification(self, obj):
438 return date(obj.date_modification) \
439 if obj.date_modification is not None else "(aucune)"
440 _date_modification.short_description = u'date modification'
441 _date_modification.admin_order_field = 'date_modification'
442
443 def _poste(self, dossier):
444 link = u"""<a title="Aperçu du poste"
445 onclick="return showAddAnotherPopup(this);"
446 href='%s'><img src="%simg/loupe.png" />
447 </a>
448 <a href="%s" title="Modifier le poste">%s</a>""" % \
449 (reverse('poste_apercu', args=(dossier.poste.id,)),
450 settings.STATIC_URL,
451 reverse('admin:rh_poste_change', args=(dossier.poste.id,)),
452 dossier.poste,
453 )
454 return link
455 _poste.allow_tags = True
456 _poste.short_description = u'Poste'
457 _poste.admin_order_field = 'poste__nom'
458
459 def _employe(self, obj):
460 employe = obj.employe
461 view_link = reverse('employe_apercu', args=(employe.id,))
462 edit_link = reverse('admin:rh_employe_change', args=(employe.id,))
463
464 style = ""
465 view = u"""<a href="%s"
466 title="Aperçu l'employé"
467 onclick="return showAddAnotherPopup(this);">
468 <img src="%simg/loupe.png" />
469 </a>""" % (view_link, settings.STATIC_URL,)
470 return u"""%s<a href='%s' style="%s;">%s</a>""" % \
471 (view, edit_link, style, employe)
472 _employe.allow_tags = True
473 _employe.short_description = u"Employé"
474 _employe.admin_order_field = "employe__nom"
475
476 def save_formset(self, request, form, formset, change):
477 instances = formset.save(commit=False)
478 for instance in instances:
479 if instance.__class__ == rh.DossierCommentaire:
480 instance.owner = request.user
481 instance.date_creation = datetime.datetime.now()
482 instance.save()
483
484
485 class EmployeAdmin(DateRangeMixin, AUFMetadataAdminMixin,
486 ProtectRegionMixin, BaseAdmin):
487 prefixe_recherche_temporelle = "rh_dossiers__"
488 alphabet_filter = 'nom'
489 DEFAULT_ALPHABET = u'ABCDEFGHIJKLMNOPQRSTUVWXYZ'
490 search_fields = (
491 'id', 'nom', 'prenom', 'nom_affichage',
492 'rh_dossiers__poste__nom',
493 'rh_dossiers__poste__nom_feminin'
494 )
495 ordering = ('nom', )
496 form = EmployeAdminForm
497 list_display = (
498 '_id',
499 '_apercu',
500 '_nom',
501 '_dossiers_postes',
502 '_date_modification',
503 'user_modification',
504 )
505 list_display_links = ('_nom',)
506 list_filter = (
507 'rh_dossiers__poste__implantation__region',
508 'rh_dossiers__poste__implantation',
509 'nb_postes',
510 )
511 inlines = (AyantDroitInline,
512 DossierROInline,
513 EmployePieceInline,
514 EmployeCommentaireInline)
515 fieldsets = AUFMetadataAdminMixin.fieldsets + (
516 ('Identification', {
517 'fields': (
518 ('nom', 'prenom'),
519 ('nom_affichage', 'genre'),
520 'nationalite',
521 'date_naissance',
522 )}
523 ),
524 ('Informations personnelles', {
525 'fields': ('situation_famille', 'date_entree', )}
526 ),
527 ('Coordonnées personnelles', {
528 'fields': (
529 ('tel_domicile', 'tel_cellulaire'),
530 ('adresse', 'ville'),
531 ('code_postal', 'province'),
532 'pays',
533 'courriel_perso'
534 )}
535 ),
536 )
537
538 def _apercu(self, obj):
539 return u"""<a title="Aperçu de l'employé"
540 onclick="return showAddAnotherPopup(this);"
541 href='%s'>
542 <img src="%simg/loupe.png" />
543 </a>""" % \
544 (reverse('employe_apercu', args=(obj.id,)), settings.STATIC_URL)
545 _apercu.allow_tags = True
546 _apercu.short_description = u""
547
548 def _nom(self, obj):
549 edit_link = reverse('admin:rh_employe_change', args=(obj.id,))
550 return u"""<a href='%s'><strong>%s</strong></a>""" % \
551 (edit_link, "%s %s" % (obj.nom.upper(), obj.prenom))
552 _nom.allow_tags = True
553 _nom.short_description = u"Employé"
554 _nom.admin_order_field = "nom"
555
556 def _id(self, obj):
557 return obj.id
558 _id.short_description = u"#"
559 _id.admin_order_field = "id"
560
561 def _date_modification(self, obj):
562 return date(obj.date_modification) \
563 if obj.date_modification is not None else "(aucune)"
564 _date_modification.short_description = u'date modification'
565 _date_modification.admin_order_field = 'date_modification'
566
567 def _dossiers_postes(self, obj):
568 l = []
569 for d in obj.rh_dossiers.all().order_by('-date_debut'):
570 dossier = u"""<a title="Aperçu du dossier"
571 href="%s"
572 onclick="return showAddAnotherPopup(this);"
573 title="Aperçu du dossier">
574 <img src="%simg/loupe.png" />
575 </a>
576 <a href="%s">Dossier</a>
577 &nbsp;""" % \
578 (reverse('dossier_apercu', args=(d.id,)),
579 settings.STATIC_URL,
580 reverse('admin:rh_dossier_change', args=(d.id,)))
581
582 poste = u"""<a title="Aperçu du poste"
583 href="%s"
584 onclick="return showAddAnotherPopup(this);"
585 title="Aperçu du poste">
586 <img src="%simg/loupe.png" />
587 </a>
588 <a href="%s">Poste</a>
589 &nbsp;""" % \
590 (reverse('poste_apercu', args=(d.poste.id,)),
591 settings.STATIC_URL,
592 reverse('admin:rh_poste_change', args=(d.poste.id,)))
593 link = u"""<li>%s %s - %s : [%s] %s</li>""" % \
594 (dossier, poste,
595 d.date_debut.year,
596 d.poste.id,
597 d.poste.nom,
598 )
599
600 # Dossier terminé en gris non cliquable
601 if d.date_fin is not None and d.date_fin < datetime.date.today():
602 link = u"""<li style="color: grey">%s : [%s] %s</li>""" % \
603 (d.date_debut.year,
604 d.poste.id,
605 d.poste.nom,
606 )
607
608 l.append(link)
609 return "<ul>%s</ul>" % "\n".join(l)
610 _dossiers_postes.allow_tags = True
611 _dossiers_postes.short_description = u"Dossiers et postes"
612
613 def queryset(self, request):
614 qs = super(EmployeAdmin, self).queryset(request)
615 return qs.select_related(depth=1).order_by('nom')
616
617 def save_formset(self, request, form, formset, change):
618 instances = formset.save(commit=False)
619 for instance in instances:
620 if instance.__class__ == rh.EmployeCommentaire:
621 instance.owner = request.user
622 instance.date_creation = datetime.datetime.now()
623 instance.save()
624
625
626 class EmployeProxyAdmin(EmployeAdmin):
627 list_display = ('_id', '_apercu', '_nom', '_organigramme')
628 actions = None
629
630 def __init__(self, *args, **kwargs):
631 super(EmployeProxyAdmin, self).__init__(*args, **kwargs)
632 self.list_display_links = (None, )
633
634 def has_add_permission(self, obj):
635 return False
636
637 def _organigramme(self, obj):
638 l = []
639 for d in rh.Dossier.objects.filter(
640 Q(date_fin__gt=datetime.date.today()) | Q(date_fin=None),
641 Q(date_debut__lt=datetime.date.today()) | Q(date_debut=None),
642 employe=obj.id
643 ):
644 organigramme = \
645 u'Organigramme, niveau: ' \
646 u'<input type="text" id="level_%s" ' \
647 u'style="width:30px;height:15px;" /> ' \
648 u'<input type="button" value="Générer" ' \
649 u"""onclick="window.location='%s' + """ \
650 u"""document.getElementById('level_%s').value" />""" % (
651 d.poste.id,
652 reverse('rho_employe_sans_niveau', args=(d.poste.id,)),
653 d.poste.id
654 )
655 link = u"""<li>%s - [%s] %s : %s</li>""" % (
656 d.date_debut.year,
657 d.poste.id,
658 d.poste.nom,
659 organigramme
660 )
661 l.append(link)
662 return "<ul>%s</ul>" % "\n".join(l)
663
664 _organigramme.allow_tags = True
665 _organigramme.short_description = "Organigramme"
666
667
668 class CategorieEmploiAdmin(AUFMetadataAdminMixin, BaseAdmin):
669 list_display = ('nom', '_date_modification', 'user_modification', )
670 inlines = (TypePosteInline,)
671 fieldsets = AUFMetadataAdminMixin.fieldsets + (
672 (None, {'fields': ('nom', )}),)
673
674 def _date_modification(self, obj):
675 return date(obj.date_modification) \
676 if obj.date_modification is not None else "(aucune)"
677 _date_modification.short_description = u'date modification'
678 _date_modification.admin_order_field = 'date_modification'
679
680
681 class OrganismeBstgAdmin(AUFMetadataAdminMixin, BaseAdmin):
682 search_fields = ('nom',)
683 list_display = (
684 'nom',
685 'type',
686 'pays',
687 '_date_modification',
688 'user_modification',
689 )
690 list_filter = ('type', )
691 inlines = (DossierROInline,)
692 fieldsets = AUFMetadataAdminMixin.fieldsets + (
693 (None, {'fields': ('nom', 'type', 'pays',)}),
694 )
695
696 def _date_modification(self, obj):
697 return date(obj.date_modification) \
698 if obj.date_modification is not None else "(aucune)"
699 _date_modification.short_description = u'date modification'
700 _date_modification.admin_order_field = 'date_modification'
701
702
703 class PosteAdmin(DateRangeMixin, AUFMetadataAdminMixin,
704 ProtectRegionMixin, BaseAdmin, AjaxSelect):
705 form = make_ajax_form(rh.Poste, {
706 'implantation': 'implantations',
707 'type_poste': 'typepostes',
708 'responsable': 'postes',
709 'valeur_point_min': 'valeurpoints',
710 'valeur_point_max': 'valeurpoints',
711 })
712 alphabet_filter = 'nom'
713 search_fields = (
714 'id',
715 'nom',
716 'implantation__nom',
717 'implantation__region__code',
718 'implantation__region__nom',
719 'rh_dossiers__employe__nom',
720 'rh_dossiers__employe__prenom',
721 )
722 list_display = (
723 '_id',
724 '_apercu',
725 '_nom',
726 '_occupe_par',
727 '_implantation',
728 '_service',
729 '_responsable',
730 'date_debut',
731 'date_fin',
732 '_date_modification',
733 'user_modification',
734 '_dae',
735 )
736 list_filter = (
737 'implantation__region',
738 'implantation',
739 'service',
740 'type_poste',
741 'type_poste__categorie_emploi',
742 'type_poste__famille_professionnelle',
743 'vacant',
744 )
745 list_display_links = ('_nom',)
746 fieldsets = AUFMetadataAdminMixin.fieldsets + (
747 (None, {'fields': (
748 ('nom', 'nom_feminin'),
749 'implantation',
750 'type_poste',
751 'service',
752 'responsable',
753 )}
754 ),
755 ('Contrat', {
756 'fields': ((
757 'regime_travail',
758 'regime_travail_nb_heure_semaine'),
759 )}
760 ),
761 ('Recrutement', {
762 'fields': (('local', 'expatrie', 'mise_a_disposition', 'appel'),)}
763 ),
764 ('Rémunération', {
765 'fields': (('classement_min',
766 'valeur_point_min',
767 'devise_min',
768 'salaire_min',
769 'indemn_min',
770 'autre_min',),
771 ('classement_max',
772 'valeur_point_max',
773 'devise_max',
774 'salaire_max',
775 'indemn_max',
776 'autre_max',),
777 )}),
778 ('Comparatifs de rémunération', {
779 'fields': ('devise_comparaison',
780 ('comp_locale_min', 'comp_locale_max'),
781 ('comp_universite_min', 'comp_universite_max'),
782 ('comp_fonctionpub_min', 'comp_fonctionpub_max'),
783 ('comp_ong_min', 'comp_ong_max'),
784 ('comp_autre_min', 'comp_autre_max'))}
785 ),
786 ('Justification', {
787 'fields': ('justification',)}
788 ),
789 ('Autres Méta-données', {
790 'fields': ('date_debut', 'date_fin')}
791 ),
792 )
793
794 inlines = (PosteFinancementInline,
795 PostePieceInline,
796 DossierROInline,
797 PosteComparaisonInline,
798 PosteCommentaireInline, )
799
800 def lookup_allowed(self, key, value):
801 return key in (
802 'date_debut__gte', 'date_debut__isnull', 'date_fin__lte',
803 'date_fin__isnull', 'implantation__region__id__exact',
804 'implantation__id__exact', 'type_poste__id__exact',
805 'type_poste__categorie_emploi__id__exact', 'service__id__exact',
806 'service__isnull', 'vacant__exact', 'vacant__isnull',
807 ) or super(PosteAdmin, self).lookup_allowed(key, value)
808
809 def _apercu(self, poste):
810 view_link = u"""<a onclick="return showAddAnotherPopup(this);"
811 title="Aperçu du poste"
812 href='%s'>
813 <img src="%simg/loupe.png" />
814 </a>""" % \
815 (reverse('poste_apercu', args=(poste.id,)),
816 settings.STATIC_URL,)
817 return view_link
818 _apercu.allow_tags = True
819 _apercu.short_description = ''
820
821 def _dae(self, poste):
822 apercu_link = ""
823 postes_dae = poste.postes_dae.all()
824 if len(postes_dae) > 0:
825 poste_dae = postes_dae[0]
826 apercu_link = \
827 u'<a title="Aperçu du dossier" href="%s" ' \
828 u'onclick="return showAddAnotherPopup(this);">' \
829 u'<img src="%simg/loupe.png" /></a>' % (reverse(
830 'poste_consulter', args=("dae-%s" % poste_dae.id,)
831 ), settings.STATIC_URL)
832 return apercu_link
833 _dae.allow_tags = True
834 _dae.short_description = u"DAE"
835
836 def _id(self, obj):
837 return "%s" % obj.id
838 _id.short_description = '#'
839 _id.admin_order_field = 'id'
840
841 def _service(self, obj):
842 if obj.service.supprime:
843 return """<span style="color:red">%s</span>""" % obj.service
844 else:
845 return obj.service
846 _service.short_description = 'Service'
847 _service.allow_tags = True
848
849 def _responsable(self, obj):
850 try:
851 responsable = u"""<a href="%s"
852 onclick="return showAddAnotherPopup(this)">
853 <img src="%simg/loupe.png"
854 title="Aperçu du poste" />
855 </a>
856 <a href="%s">%s</a>
857 <br />""" % \
858 (reverse('poste_apercu', args=(obj.responsable.id,)),
859 settings.STATIC_URL,
860 reverse('admin:rh_poste_change', args=(obj.responsable.id,)),
861 obj.responsable.nom)
862 except:
863 responsable = ''
864
865 try:
866 employe = obj.responsable.rh_dossiers.all()[0]
867 employe_id = obj.responsable.rh_dossiers.all()[0].id
868 employe_html = u"""<br />
869 <a href="%s"
870 onclick="return showAddAnotherPopup(this)">
871 <img src="%simg/loupe.png"
872 title="Aperçu de l'employé">
873 </a>
874 <a href="%s">%s</a>""" % \
875 (reverse('employe_apercu', args=(employe_id,)),
876 settings.STATIC_URL,
877 reverse('admin:rh_employe_change', args=(employe_id,)),
878 employe)
879 except:
880 employe_html = ""
881
882 return "%s %s" % (responsable, employe_html)
883 _responsable.short_description = 'Responsable'
884 _responsable.allow_tags = True
885
886 def _implantation(self, poste):
887 return poste.implantation.nom
888 _implantation.short_description = 'Implantation'
889 _implantation.admin_order_field = 'implantation'
890
891 def _nom(self, poste):
892 return """<a href="%s">%s</a>""" % \
893 (reverse('admin:rh_poste_change', args=(poste.id,)),
894 poste.nom)
895 _nom.allow_tags = True
896 _nom.short_description = u'Poste'
897 _nom.admin_order_field = 'nom'
898
899 def _date_modification(self, obj):
900 return date(obj.date_modification)
901 _date_modification.short_description = u'date modification'
902 _date_modification.admin_order_field = 'date_modification'
903
904 def _occupe_par(self, obj):
905 """Formatte la méthode Poste.occupe_par() pour l'admin"""
906 output = u"Vacant"
907 if obj.date_fin is not None and obj.date_fin < datetime.date.today():
908 return u"s/o"
909 employes = obj.occupe_par()
910 if employes:
911 l = []
912 for e in employes:
913 link = u"""<a href='%s'
914 title='Aperçu de l\'employer'
915 onclick='return showAddAnotherPopup(this)'>
916 <img src='%simg/loupe.png' />
917 </a>
918 <a href='%s'>%s</a>""" % \
919 (reverse('employe_apercu', args=(e.id,)),
920 settings.STATIC_URL,
921 reverse('admin:rh_employe_change', args=(e.id,)),
922 e)
923 l.append(link)
924 output = "\n<br />".join(l)
925 return output
926 _occupe_par.allow_tags = True
927 _occupe_par.short_description = "Occupé par"
928
929 def save_formset(self, request, form, formset, change):
930 instances = formset.save(commit=False)
931 for instance in instances:
932 if instance.__class__ == rh.PosteCommentaire:
933 instance.owner = request.user
934 instance.date_creation = datetime.datetime.now()
935 instance.save()
936 formset.save_m2m()
937
938
939 class ResponsableInline(admin.TabularInline):
940 model = rh.ResponsableImplantation
941 extra = 0
942 fk_name = "implantation"
943
944
945 class ResponsableImplantationAdmin(BaseAdmin):
946 actions = None
947 list_filter = ('region', 'statut', )
948 list_display = ('nom', 'statut', '_responsable', )
949 readonly_fields = ('nom', )
950 fields = ('nom', )
951 inlines = (ResponsableInline, )
952
953 def _responsable(self, obj):
954 try:
955 employe = obj.responsable.employe
956 dossiers = employe.dossiers_encours()
957 if len(dossiers) == 0:
958 return u"<span style='color: red;'>%s %s </span>" % (
959 employe, u"sans dossier actif")
960 else:
961 return employe
962 except Exception:
963 if obj.statut in (1, 2): # ouverte, ouverture imminente
964 css = "style='color: red;'"
965 else:
966 css = ""
967 return u"<span %s>Pas de responsable</span>" % css
968 _responsable.allow_tags = True
969 _responsable.short_description = u"Responsable"
970
971 def has_add_permission(self, request=None):
972 return False
973
974 def has_change_permission(self, request, obj=None):
975 return in_drh_or_admin(request.user)
976
977 def has_delete_permission(self, request, obj=None):
978 return False
979
980
981 class ServiceAdmin(AUFMetadataAdminMixin, BaseAdmin, ArchiveMixin):
982 list_display = (
983 'nom',
984 '_archive',
985 '_date_modification',
986 'user_modification',
987 )
988 list_filter = ('archive', )
989 fieldsets = AUFMetadataAdminMixin.fieldsets + (
990 (None, {
991 'fields': ('nom', 'archive', ),
992 }),
993 )
994
995 def _date_modification(self, obj):
996 return date(obj.date_modification) \
997 if obj.date_modification is not None else "(aucune)"
998 _date_modification.short_description = u'date modification'
999 _date_modification.admin_order_field = 'date_modification'
1000
1001
1002 class ServiceProxyAdmin(ServiceAdmin):
1003 list_display = ('nom', '_organigramme', '_archive', )
1004 actions = None
1005
1006 def __init__(self, *args, **kwargs):
1007 super(ServiceProxyAdmin, self).__init__(*args, **kwargs)
1008 self.list_display_links = (None, )
1009
1010 def queryset(self, request):
1011 return super(ServiceProxyAdmin, self).queryset(request) \
1012 .annotate(num_postes=Count('rh_postes')) \
1013 .filter(num_postes__gt=0)
1014
1015 def has_add_permission(self, obj):
1016 return False
1017
1018 def has_change_permission(self, request, obj=None):
1019 return in_drh_or_admin(request.user)
1020
1021 def _organigramme(self, obj):
1022 return """<a href="%s"><strong>Organigramme</strong></a>""" % \
1023 (reverse('rho_service', args=(obj.id,)))
1024 _organigramme.allow_tags = True
1025 _organigramme.short_description = "Organigramme"
1026
1027
1028 class StatutAdmin(AUFMetadataAdminMixin, BaseAdmin):
1029 list_display = ('code', 'nom', '_date_modification', 'user_modification', )
1030 fieldsets = AUFMetadataAdminMixin.fieldsets + (
1031 (None, {
1032 'fields': ('code', 'nom', ),
1033 }),
1034 )
1035
1036 def _date_modification(self, obj):
1037 return date(obj.date_modification) \
1038 if obj.date_modification is not None else "(aucune)"
1039 _date_modification.short_description = u'date modification'
1040 _date_modification.admin_order_field = 'date_modification'
1041
1042
1043 class TauxChangeAdmin(BaseAdmin):
1044 list_display = (
1045 'taux',
1046 'devise',
1047 'annee',
1048 '_date_modification',
1049 'user_modification',
1050 )
1051 list_filter = ('devise', )
1052 fieldsets = AUFMetadataAdminMixin.fieldsets + (
1053 (None, {
1054 'fields': ('taux', 'devise', 'annee', ),
1055 }),
1056 )
1057
1058 def _date_modification(self, obj):
1059 return date(obj.date_modification) \
1060 if obj.date_modification is not None else "(aucune)"
1061 _date_modification.short_description = u'date modification'
1062 _date_modification.admin_order_field = 'date_modification'
1063
1064
1065 class TypeContratAdmin(BaseAdmin):
1066 list_display = (
1067 'nom',
1068 'nom_long',
1069 '_date_modification',
1070 'user_modification',
1071 )
1072 fieldsets = AUFMetadataAdminMixin.fieldsets + (
1073 (None, {
1074 'fields': ('nom', 'nom_long', ),
1075 }),
1076 )
1077
1078 def _date_modification(self, obj):
1079 return date(obj.date_modification) \
1080 if obj.date_modification is not None else "(aucune)"
1081 _date_modification.short_description = u'date modification'
1082 _date_modification.admin_order_field = 'date_modification'
1083
1084
1085 class TypePosteAdmin(AUFMetadataAdminMixin, BaseAdmin):
1086 search_fields = ('nom', 'nom_feminin', )
1087 list_display = (
1088 'nom',
1089 'categorie_emploi',
1090 '_date_modification',
1091 'user_modification',
1092 )
1093 list_filter = ('categorie_emploi', 'famille_professionnelle')
1094 fieldsets = AUFMetadataAdminMixin.fieldsets + (
1095 (None, {
1096 'fields': (
1097 'nom',
1098 'nom_feminin',
1099 'is_responsable',
1100 'categorie_emploi',
1101 'famille_professionnelle',
1102 )}
1103 ),
1104 )
1105
1106 def _date_modification(self, obj):
1107 return date(obj.date_modification) \
1108 if obj.date_modification is not None else "(aucune)"
1109 _date_modification.short_description = u'date modification'
1110 _date_modification.admin_order_field = 'date_modification'
1111
1112
1113 class TypeRemunerationAdmin(AUFMetadataAdminMixin, BaseAdmin,
1114 ArchiveMixin):
1115 list_display = (
1116 'nom',
1117 'type_paiement',
1118 'nature_remuneration',
1119 '_archive',
1120 '_date_modification',
1121 'user_modification',)
1122 list_filter = ('archive', )
1123 fieldsets = AUFMetadataAdminMixin.fieldsets + (
1124 (None, {'fields': ('nom', 'type_paiement', 'nature_remuneration',
1125 'archive')}),
1126 )
1127
1128 def _date_modification(self, obj):
1129 return date(obj.date_modification) \
1130 if obj.date_modification is not None else "(aucune)"
1131 _date_modification.short_description = u'date modification'
1132 _date_modification.admin_order_field = 'date_modification'
1133
1134
1135 class TypeRevalorisationAdmin(AUFMetadataAdminMixin, BaseAdmin):
1136 list_display = ('nom', '_date_modification', 'user_modification', )
1137 fieldsets = AUFMetadataAdminMixin.fieldsets + (
1138 (None, {'fields': ('nom', )}),
1139 )
1140
1141 def _date_modification(self, obj):
1142 return date(obj.date_modification) \
1143 if obj.date_modification is not None else "(aucune)"
1144 _date_modification.short_description = u'date modification'
1145 _date_modification.admin_order_field = 'date_modification'
1146
1147
1148 class ValeurPointAdmin(AUFMetadataAdminMixin, BaseAdmin):
1149 list_display = (
1150 '_devise_code',
1151 '_devise_nom',
1152 'annee',
1153 'implantation',
1154 'valeur',
1155 '_date_modification',
1156 'user_modification',
1157 )
1158 list_filter = ('annee', 'devise', 'implantation__region', )
1159 fieldsets = AUFMetadataAdminMixin.fieldsets + (
1160 (None, {'fields': ('valeur', 'devise', 'implantation', 'annee', )}),
1161 )
1162
1163 def _date_modification(self, obj):
1164 return date(obj.date_modification) \
1165 if obj.date_modification is not None else "(aucune)"
1166 _date_modification.short_description = u'date modification'
1167 _date_modification.admin_order_field = 'date_modification'
1168
1169 def _devise_code(self, obj):
1170 return obj.devise.code
1171 _devise_code.short_description = "Code de la devise"
1172
1173 def _devise_nom(self, obj):
1174 return obj.devise.nom
1175 _devise_nom.short_description = "Nom de la devise"
1176
1177
1178 class ImplantationProxyAdmin(BaseAdmin):
1179 list_display = ('nom', '_organigramme')
1180 actions = None
1181
1182 def __init__(self, *args, **kwargs):
1183 super(ImplantationProxyAdmin, self).__init__(*args, **kwargs)
1184 self.list_display_links = (None, )
1185
1186 def has_add_permission(self, obj):
1187 return False
1188
1189 def has_change_permission(self, request, obj=None):
1190 return in_drh_or_admin(request.user)
1191
1192 def _organigramme(self, obj):
1193 return '<a href="%s"><strong>Organigramme</strong></a>' % (
1194 reverse('rho_implantation', args=(obj.id,))
1195 )
1196 _organigramme.allow_tags = True
1197 _organigramme.short_description = "Organigramme"
1198
1199
1200 class RegionProxyAdmin(BaseAdmin):
1201 list_display = ('nom', '_organigramme')
1202 actions = None
1203
1204 def __init__(self, *args, **kwargs):
1205 super(RegionProxyAdmin, self).__init__(*args, **kwargs)
1206 self.list_display_links = (None, )
1207
1208 def has_add_permission(self, obj):
1209 return False
1210
1211 def has_change_permission(self, request, obj=None):
1212 return in_drh_or_admin(request.user)
1213
1214 def _organigramme(self, obj):
1215 return """<a href="%s"><strong>Organigramme</strong></a>""" % (
1216 reverse('rho_region', args=(obj.id,))
1217 )
1218 _organigramme.allow_tags = True
1219 _organigramme.short_description = "Organigramme"
1220
1221
1222 admin.site.register(rh.Classement, ClassementAdmin)
1223 admin.site.register(rh.Devise, DeviseAdmin)
1224 admin.site.register(rh.Dossier, DossierAdmin)
1225 admin.site.register(EmployeProxy, EmployeProxyAdmin)
1226 admin.site.register(ServiceProxy, ServiceProxyAdmin)
1227 admin.site.register(rh.Employe, EmployeAdmin)
1228 admin.site.register(rh.CategorieEmploi, CategorieEmploiAdmin)
1229 admin.site.register(rh.FamilleProfessionnelle)
1230 admin.site.register(rh.OrganismeBstg, OrganismeBstgAdmin)
1231 admin.site.register(rh.Poste, PosteAdmin)
1232 admin.site.register(
1233 rh.ResponsableImplantationProxy, ResponsableImplantationAdmin
1234 )
1235 admin.site.register(rh.Service, ServiceAdmin)
1236 admin.site.register(rh.Statut, StatutAdmin)
1237 admin.site.register(rh.TauxChange, TauxChangeAdmin)
1238 admin.site.register(rh.TypeContrat, TypeContratAdmin)
1239 admin.site.register(rh.TypePoste, TypePosteAdmin)
1240 admin.site.register(rh.TypeRemuneration, TypeRemunerationAdmin)
1241 admin.site.register(rh.TypeRevalorisation, TypeRevalorisationAdmin)
1242 admin.site.register(rh.ValeurPoint, ValeurPointAdmin)
1243 admin.site.register(ImplantationProxy, ImplantationProxyAdmin)
1244 admin.site.register(RegionProxy, RegionProxyAdmin)