6052
[auf_rh_dae.git] / project / rh / admin.py
1 # -*- encoding: utf-8 -*-
2
3 import datetime
4 import reversion
5 import itertools
6 from ajax_select import make_ajax_form
7 from auf.django.references import models as ref
8 from django.core.mail import send_mail, EmailMessage
9 from django.contrib.auth.admin import UserAdmin
10 from django.contrib.auth.models import User
11 from django import forms
12 from django.core.urlresolvers import reverse
13 from django.contrib import admin
14 from django.contrib.contenttypes.models import ContentType
15 from django.conf import settings
16 from django.db.models import Q, Count
17 from django.template.defaultfilters import date
18 from django.template import Context, loader
19 from django.utils.formats import date_format
20
21 from project import groups
22 from project.decorators import in_drh_or_admin
23 from project.rh import models as rh
24 from project.permissions import user_gere_obj_de_sa_region, \
25 user_can_list_obj, \
26 user_can_add_obj, \
27 user_can_change_obj, \
28 user_can_delete_obj
29
30 from project.rh.forms import ContratForm, AyantDroitForm, EmployeAdminForm, \
31 AjaxSelect, DossierForm, ResponsableInlineForm, \
32 ClassementHistoriqueForm
33
34 from project.rh.change_list import ChangeList
35
36
37 def listing_par_defaut(model, request):
38 """
39 Teste si la requete provient de la même page.
40 """
41 if not 'HTTP_REFERER' in request.META.keys():
42 return False
43 referer = request.META['HTTP_REFERER']
44 referer = "/".join(referer.split('/')[3:])
45 referer = "/%s" % referer.split('?')[0]
46 change_list_view = 'admin:%s_%s_changelist' % (
47 model._meta.app_label,
48 model.__name__.lower(),)
49 return referer != reverse(change_list_view)
50
51
52 class BaseAdmin(admin.ModelAdmin):
53
54 class Media:
55 css = {'screen': (
56 'css/admin_custom.css',
57 'jquery-autocomplete/jquery.autocomplete.css',
58 )}
59 js = (
60 'https://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js',
61 'jquery-autocomplete/jquery.autocomplete.min.js',
62 )
63
64
65 # Admin pour reversion
66
67 class ArchivableAdmin(admin.ModelAdmin):
68 """
69 Admin pour les modèles archivables
70 """
71 list_filter = ('archive', )
72
73 def queryset(self, request):
74 return self.model.avec_archives.all()
75
76 def _archive(self, obj):
77 if obj.archive:
78 return "oui"
79 else:
80 return "non"
81 _archive.short_description = u'Archivé'
82 _archive.admin_order_field = 'archive'
83
84
85 class RegionProxy(ref.Region):
86 """ Proxy utilisé pour les organigrammes par région """
87 class Meta:
88 managed = False
89 proxy = True
90 verbose_name = u"Organigramme par région"
91 verbose_name_plural = u"Organigramme par région"
92
93
94 class ImplantationProxy(ref.Implantation):
95 """ Proxy utilisé pour les organigrammes par implantation """
96 class Meta:
97 managed = False
98 proxy = True
99 verbose_name = u"Organigramme par implantations"
100 verbose_name_plural = u"Organigramme par implantations"
101
102
103 class ServiceProxy(rh.Service):
104 """ Proxy utilisé pour les organigrammes par service """
105
106 class Meta:
107 managed = False
108 proxy = True
109 verbose_name = u"Organigramme par services"
110 verbose_name_plural = u"Organigramme par services"
111
112
113 class EmployeProxy(rh.Employe):
114 """ Proxy utilisé pour les organigrammes des employés """
115 class Meta:
116 managed = False
117 proxy = True
118 verbose_name = u"Organigramme des employés"
119 verbose_name_plural = u"Organigramme des employés"
120
121
122 class DateRangeMixin(object):
123 prefixe_recherche_temporelle = ""
124
125 def get_changelist(self, request, **kwargs):
126 """
127 On filtre par défaut sur les items 'actifs'.
128 Le changelist plug le filtrage temporel.
129 """
130 if listing_par_defaut(self.model, request):
131 params = request.GET.copy()
132 params.update({'statut': 'Actif'})
133 request.GET = params
134 return ChangeList
135
136
137 # Override of the InlineModelAdmin to support the link in the tabular inline
138 class LinkedInline(admin.options.InlineModelAdmin):
139 template = "admin/linked.html"
140 admin_model_path = None
141
142 def __init__(self, *args):
143 super(LinkedInline, self).__init__(*args)
144 if self.admin_model_path is None:
145 self.admin_model_path = self.model.__name__.lower()
146
147
148 class ProtectRegionMixin(object):
149
150 def changelist_view(self, request, extra_context=None):
151 """
152 On filtre par défaut sur la ZA du user connecté
153 """
154 if listing_par_defaut(self.model, request):
155 if user_gere_obj_de_sa_region(request.user):
156 params = request.GET.copy()
157 zones = groups.get_zones_from_user(request.user)
158 prefix_za = "%s__in" % self.model.prefix_implantation
159 params.update({prefix_za: zones})
160 request.GET = params
161 return super(ProtectRegionMixin, self) \
162 .changelist_view(request, extra_context)
163
164 def queryset(self, request):
165 qs = super(ProtectRegionMixin, self).queryset(request)
166
167 if in_drh_or_admin(request.user):
168 return qs
169
170 if user_gere_obj_de_sa_region(request.user):
171 zones = groups.get_zones_from_user(request.user)
172 qkey = '%s__in' % self.model.prefix_implantation
173 q = Q(**{qkey: zones})
174 qs = qs.filter(q).distinct()
175 return qs
176 return qs.none()
177
178 def has_add_permission(self, request):
179 return user_can_add_obj(request.user)
180
181 def has_change_permission(self, request, obj=None):
182 if obj is None:
183 return user_can_list_obj(request.user)
184 else:
185 return user_can_change_obj(request.user, obj)
186
187 def has_delete_permission(self, request, obj=None):
188 return user_can_delete_obj(request.user, obj) if obj else True
189
190
191 class DerniereModificationAdmin(admin.ModelAdmin):
192
193 def queryset(self, request):
194 qs = super(DerniereModificationAdmin, self).queryset(request)
195 ct = ContentType.objects.get_for_model(self.model)
196 db_table = self.model._meta.db_table
197 pk = self.model._meta.pk.column
198 return qs.extra(select={
199 'date_modification':
200 "SELECT action_time FROM django_admin_log "
201 "WHERE content_type_id = %d AND object_id = %s.%s "
202 "ORDER BY action_time DESC "
203 "LIMIT 1" % (ct.id, db_table, pk),
204 'user_modification':
205 "SELECT u.username "
206 "FROM auth_user u "
207 "INNER JOIN django_admin_log l ON l.user_id = u.id "
208 "WHERE l.content_type_id = %d AND object_id = %s.%s "
209 "ORDER BY action_time DESC "
210 "LIMIT 1" % (ct.id, db_table, pk),
211 })
212
213 def derniere_modification(self, obj):
214 text = ''
215 if obj.date_modification:
216 text += obj.date_modification.strftime('%d-%m-%Y %H:%M')
217 if obj.user_modification:
218 text += ' par ' + obj.user_modification
219 return text
220 derniere_modification.short_description = u'dernière modification'
221 derniere_modification.admin_order_field = 'date_modification'
222
223
224 # Inlines
225
226 class CommentaireInlineForm(forms.ModelForm):
227
228 def save(self, commit=True):
229
230 # Hack: reversion.VersionAdmin ne sauvegarde pas les champs qui ne
231 # sont pas explicitement dans le formulaire. Il plante cependant
232 # leur valeur dans `self.initial`. Ceci est un peu fragile. Si
233 # c'est possible, il serait plus approprié que Reversion se rende
234 # compte qu'il manque des champs.
235 instance = super(CommentaireInlineForm, self).save(commit=False)
236 if instance.owner_id is None and 'owner' in self.initial:
237 instance.owner_id = self.initial['owner']
238 if instance.date_creation is None and 'date_creation' in self.initial:
239 instance.date_creation = self.initial['date_creation']
240 if commit:
241 instance.save()
242 self.save_m2m()
243 return instance
244
245
246 class ReadOnlyInlineMixin(object):
247
248 def get_readonly_fields(self, request, obj=None):
249 return [f.name for f in self.model._meta.fields]
250
251
252 class AyantDroitInline(admin.StackedInline):
253 model = rh.AyantDroit
254 form = AyantDroitForm
255 extra = 0
256
257 fieldsets = (
258 (None, {
259 'fields': (
260 ('nom', 'prenom'),
261 ('nom_affichage', 'genre'),
262 'nationalite',
263 'date_naissance',
264 'lien_parente',
265 )}),
266 )
267
268
269 class AyantDroitCommentaireInline(admin.TabularInline):
270 readonly_fields = ('owner',)
271 model = rh.AyantDroitCommentaire
272 extra = 1
273 form = CommentaireInlineForm
274
275
276 class ContratInline(admin.TabularInline):
277 form = ContratForm
278 model = rh.Contrat
279 extra = 1
280
281
282 class DossierROInline(ReadOnlyInlineMixin, LinkedInline):
283 template = "admin/rh/dossier/linked.html"
284 model = rh.Dossier
285 extra = 0
286 can_delete = False
287 fields = ('poste', 'date_debut', 'date_fin', )
288
289 def has_add_permission(self, request=None):
290 return False
291
292 def has_change_permission(self, request, obj=None):
293 return False
294
295 def has_delete_permission(self, request, obj=None):
296 return False
297
298
299 class DossierClassementRecordInline(admin.TabularInline):
300 def queryset(self, request):
301 return (super(DossierClassementRecordInline, self)
302 .queryset(request).order_by('-date_debut', '-id'))
303 model = rh.RHDossierClassementRecord
304 form = ClassementHistoriqueForm
305 extra = 0
306
307
308 class DossierCommentaireInline(admin.TabularInline):
309 readonly_fields = ('owner',)
310 model = rh.DossierCommentaire
311 extra = 1
312 form = CommentaireInlineForm
313
314
315 class DossierPieceInline(admin.TabularInline):
316 model = rh.DossierPiece
317 extra = 4
318
319
320 class EmployeInline(admin.TabularInline):
321 model = rh.Employe
322
323
324 class EmployeCommentaireInline(admin.TabularInline):
325 readonly_fields = ('owner',)
326 model = rh.EmployeCommentaire
327 extra = 1
328 form = CommentaireInlineForm
329
330
331 class EmployePieceInline(admin.TabularInline):
332 model = rh.EmployePiece
333 extra = 4
334
335
336 class PosteCommentaireInline(admin.TabularInline):
337 readonly_fields = ('owner',)
338 model = rh.PosteCommentaire
339 extra = 1
340 form = CommentaireInlineForm
341
342
343 class PosteFinancementInline(admin.TabularInline):
344 model = rh.PosteFinancement
345
346
347 class PostePieceInline(admin.TabularInline):
348 model = rh.PostePiece
349
350
351 class RemunerationInline(admin.TabularInline):
352 model = rh.Remuneration
353 extra = 1
354
355
356 class RemunerationROInline(ReadOnlyInlineMixin, RemunerationInline):
357 pass
358
359
360 class TypePosteInline(admin.TabularInline):
361 model = rh.TypePoste
362
363
364 class PosteComparaisonInline(admin.TabularInline):
365 model = rh.PosteComparaison
366
367
368 class ClassementAdmin(reversion.VersionAdmin,
369 ArchivableAdmin,
370 DerniereModificationAdmin,
371 BaseAdmin):
372 ignore_duplicate_revisions = True
373 list_display = ('_classement', 'derniere_modification', '_archive')
374 list_filter = ('archive', )
375 fieldsets = (
376 (None, {'fields': (
377 'type', 'echelon',
378 'degre', 'coefficient', 'archive')}),
379 )
380
381 def _classement(self, obj):
382 return unicode(obj)
383 _classement.short_description = u"Classement"
384
385
386 class DeviseAdmin(reversion.VersionAdmin, ArchivableAdmin,
387 DerniereModificationAdmin, BaseAdmin):
388 ignore_duplicate_revisions = True
389 list_display = (
390 'code', 'nom', 'derniere_modification', '_archive',
391 )
392 list_filter = ('archive', )
393 fieldsets = (
394 (None, {'fields': ('code', 'nom', 'archive', )}),
395 )
396
397
398 class DossierAdmin(DateRangeMixin, ProtectRegionMixin, reversion.VersionAdmin,
399 AjaxSelect, DerniereModificationAdmin, BaseAdmin):
400 change_list_template = "admin/rh/dossier/change_list.html"
401 ignore_duplicate_revisions = True
402 alphabet_filter = 'employe__nom'
403 search_fields = (
404 'id',
405 'employe__id',
406 'poste__id',
407 'employe__nom',
408 'employe__prenom',
409 'poste__nom',
410 'poste__nom_feminin',
411 'poste__implantation__nom',
412 )
413 list_display = (
414 '_id',
415 '_apercu',
416 '_nom',
417 '_employe',
418 '_poste',
419 '_zone_administrative',
420 '_implantation',
421 '_date_debut',
422 '_date_fin',
423 'derniere_modification',
424 '_dae',
425 )
426 list_display_links = ('_nom',)
427 list_filter = (
428 'poste__implantation__zone_administrative',
429 'poste__implantation',
430 'poste__type_poste__categorie_emploi',
431 'poste__type_poste',
432 'rh_contrats__type_contrat',
433 'principal',
434 )
435 inlines = (DossierPieceInline,
436 DossierClassementRecordInline,
437 ContratInline,
438 RemunerationInline,
439 DossierCommentaireInline,
440 )
441 fieldsets = (
442 (None, {
443 'fields': (
444 'employe',
445 'poste',
446 'principal',
447 'est_cadre',
448 'statut',
449 'organisme_bstg',)}),
450 ('Recrutement', {
451 'fields': (
452 'statut_residence',
453 'remplacement',
454 'remplacement_de', )}),
455 ('Rémunération', {
456 'fields': (
457 'classement',
458 ('regime_travail',
459 'regime_travail_nb_heure_semaine'),)}),
460 ('Comptes', {
461 'fields': (
462 'compte_compta', 'compte_courriel',
463 )
464 }),
465 ('Occupation du Poste par cet Employe', {
466 'fields': (('date_debut', 'date_fin'), )}
467 ),
468 )
469 form = make_ajax_form(rh.Dossier, {
470 'employe': 'employes',
471 'poste': 'postes',
472 'remplacement_de': 'dossiers',
473 }, superclass=DossierForm)
474
475 def lookup_allowed(self, key, value):
476 if key in (
477 'employe__nom__istartswith',
478 'poste__implantation__zone_administrative__code__exact',
479 'poste__implantation__zone_administrative__in',
480 'poste__implantation__id__exact',
481 'poste__type_poste__id__exact',
482 'poste__type_poste__categorie_emploi__id__exact',
483 'rh_contrats__type_contrat__id__exact',
484 'principal__exact',
485 'principal__isnull',
486 ):
487 return True
488
489 def _id(self, obj):
490 return obj.id
491 _id.short_description = u"#"
492 _id.admin_order_field = "id"
493
494 def _apercu(self, d):
495 apercu_link = u"""<a title="Aperçu du dossier"
496 onclick="return showAddAnotherPopup(this);"
497 href='%s'>
498 <img src="%simg/dossier-apercu.png" />
499 </a>""" % \
500 (reverse('dossier_apercu', args=(d.id,)),
501 settings.STATIC_URL,
502 )
503 return apercu_link
504 _apercu.allow_tags = True
505 _apercu.short_description = u""
506
507 def _nom(self, obj):
508 return "Dossier"
509 _nom.allow_tags = True
510 _nom.short_description = u"Dossier"
511
512 def _employe(self, obj):
513 employe = obj.employe
514 view_link = reverse('employe_apercu', args=(employe.id,))
515 edit_link = reverse('admin:rh_employe_change', args=(employe.id,))
516 style = ""
517 view = u"""<a href="%s"
518 title="Aperçu l'employé"
519 onclick="return showAddAnotherPopup(this);">
520 <img src="%simg/employe-apercu.png" />
521 </a>""" % (view_link, settings.STATIC_URL,)
522 return u"""%s<a href='%s' style="%s;">%s</a>""" % \
523 (view, edit_link, style, employe)
524 _employe.allow_tags = True
525 _employe.short_description = u"Employé"
526 _employe.admin_order_field = "employe__nom"
527
528 def _poste(self, dossier):
529 link = u"""<a title="Aperçu du poste"
530 onclick="return showAddAnotherPopup(this);"
531 href='%s'><img src="%simg/poste-apercu.png" />
532 </a>
533 <a href="%s" title="Modifier le poste">%s [%d]</a>""" % \
534 (reverse('poste_apercu', args=(dossier.poste.id,)),
535 settings.STATIC_URL,
536 reverse('admin:rh_poste_change', args=(dossier.poste.id,)),
537 dossier.poste.nom,
538 dossier.poste.id,
539 )
540 return link
541 _poste.allow_tags = True
542 _poste.short_description = u'Poste'
543 _poste.admin_order_field = 'poste__nom'
544
545 def _zone_administrative(self, obj):
546 return obj.poste.implantation.zone_administrative.code
547 _zone_administrative.short_description = u"Zone administrative"
548 _zone_administrative.admin_order_field = \
549 'poste__implantation__zone_administrative__code'
550
551 def _implantation(self, obj):
552 return obj.poste.implantation.nom
553 _implantation.short_description = u"Implantation"
554 _implantation.admin_order_field = 'poste__implantation__nom'
555
556 def _date_debut(self, obj):
557 return date(obj.date_debut)
558
559 _date_debut.short_description = u'Début'
560 _date_debut.admin_order_field = 'date_debut'
561
562 def _date_fin(self, obj):
563 return date(obj.date_fin)
564 _date_fin.short_description = u'Fin'
565 _date_fin.admin_order_field = 'date_fin'
566
567 def _date_modification(self, obj):
568 return date(obj.date_modification) \
569 if obj.date_modification is not None else "(aucune)"
570 _date_modification.short_description = u'date modification'
571 _date_modification.admin_order_field = 'date_modification'
572
573 def _dae(self, d):
574 apercu_link = ""
575 dossiers_dae = d.dossiers_dae.all()
576 if len(dossiers_dae) > 0:
577 dossier_dae = dossiers_dae[0]
578 apercu_link = u"""<a title="Aperçu du dossier"
579 onclick="return showAddAnotherPopup(this);"
580 href='%s'>
581 <img src="%simg/loupe.png" />
582 </a>""" % \
583 (reverse('embauche_consulter', args=(dossier_dae.id,)),
584 settings.STATIC_URL,
585 )
586 return apercu_link
587 _dae.allow_tags = True
588 _dae.short_description = u"DAE"
589
590 def save_formset(self, request, form, formset, change):
591 instances = formset.save(commit=False)
592 for instance in instances:
593 if instance.__class__ == rh.DossierCommentaire:
594 instance.owner = request.user
595 instance.date_creation = datetime.datetime.now()
596 instance.save()
597
598
599 class EmployeAdminBase(DateRangeMixin, ProtectRegionMixin,
600 DerniereModificationAdmin, BaseAdmin):
601 prefixe_recherche_temporelle = "rh_dossiers__"
602 alphabet_filter = 'nom'
603 DEFAULT_ALPHABET = u'ABCDEFGHIJKLMNOPQRSTUVWXYZ'
604 search_fields = (
605 'id', 'nom', 'prenom', 'nom_affichage',
606 'rh_dossiers__poste__nom',
607 'rh_dossiers__poste__nom_feminin'
608 )
609 ordering = ('nom', )
610 form = EmployeAdminForm
611 list_display = (
612 '_id', '_apercu', '_nom', '_dossiers_postes',
613 #'_zone_administrative',
614 #'_implantation',
615 'date_entree',
616 'derniere_modification'
617 )
618 list_display_links = ('_nom',)
619 list_filter = (
620 'rh_dossiers__poste__implantation__zone_administrative',
621 'rh_dossiers__poste__implantation', 'nb_postes'
622 )
623 inlines = (
624 AyantDroitInline, DossierROInline, EmployePieceInline,
625 EmployeCommentaireInline
626 )
627 fieldsets = (
628 ('Identification', {
629 'fields': (
630 ('nom', 'prenom'),
631 ('nom_affichage', 'genre'),
632 'nationalite',
633 'date_naissance',
634 )
635 }),
636 ('Informations personnelles', {
637 'fields': ('situation_famille', 'date_entree', )
638 }),
639 ('Coordonnées personnelles', {
640 'fields': (
641 ('tel_domicile', 'tel_cellulaire'),
642 ('adresse', 'ville'),
643 ('code_postal', 'province'),
644 'pays',
645 'courriel_perso'
646 )
647 }),
648 )
649
650 def _id(self, obj):
651 return obj.id
652 _id.short_description = u"#"
653 _id.admin_order_field = "id"
654
655 def _apercu(self, obj):
656 return u"""<a title="Aperçu de l'employé"
657 onclick="return showAddAnotherPopup(this);"
658 href='%s'>
659 <img src="%simg/employe-apercu.png" />
660 </a>""" % \
661 (reverse('employe_apercu', args=(obj.id,)), settings.STATIC_URL)
662 _apercu.allow_tags = True
663 _apercu.short_description = u""
664
665 def _nom(self, obj):
666 edit_link = reverse('admin:rh_employe_change', args=(obj.id,))
667 return u"""<a href='%s'><strong>%s</strong></a>""" % \
668 (edit_link, "%s %s" % (obj.nom.upper(), obj.prenom))
669 _nom.allow_tags = True
670 _nom.short_description = u"Employé"
671 _nom.admin_order_field = "nom"
672
673 def _zone_administrative(self, obj):
674 try:
675 d = rh.Dossier.objects.filter(employe=obj.id, principal=True)[0]
676 zone = d.poste.implantation.zone_administrative.code
677 except:
678 zone = None
679 return zone
680 _zone_administrative.short_description = u"Zone administrative"
681
682 def _implantation(self, obj):
683 try:
684 d = rh.Dossier.objects.filter(employe=obj.id, principal=True)[0]
685 implantation = d.poste.implantation.nom
686 except:
687 implantation = None
688 return implantation
689 _implantation.short_description = u"Implantation"
690
691 def _dossiers_postes(self, obj):
692 l = []
693 for d in obj.rh_dossiers.all().order_by('-date_debut'):
694 link_style = u''
695 list_style = u''
696 if d.date_fin is not None and d.date_fin < datetime.date.today():
697 link_style = u' style="color:#666;"'
698 list_style = u' style="color:grey;"'
699
700 dossier = u"""<a title="Aperçu du dossier"
701 href="%s"
702 onclick="return showAddAnotherPopup(this);"
703 title="Aperçu du dossier">
704 <img src="%simg/dossier-apercu.png" />
705 </a>
706 <a href="%s"%s>Dossier</a>
707 &nbsp;""" % \
708 (reverse('dossier_apercu', args=(d.id,)),
709 settings.STATIC_URL,
710 reverse('admin:rh_dossier_change', args=(d.id,)),
711 link_style,)
712
713 poste = u"""<a title="Aperçu du poste"
714 href="%s"
715 onclick="return showAddAnotherPopup(this);"
716 title="Aperçu du poste">
717 <img src="%simg/poste-apercu.png" />
718 </a>
719 <a href="%s"%s>%s [%d]</a>
720 &nbsp;""" % \
721 (reverse('poste_apercu', args=(d.poste.id,)),
722 settings.STATIC_URL,
723 reverse('admin:rh_poste_change', args=(d.poste.id,)),
724 link_style,
725 d.poste.nom,
726 d.poste.id)
727
728 link = u"""<li%s>%s %s</li>""" % \
729 (list_style, dossier, poste)
730
731 l.append(link)
732 return "<ul>%s</ul>" % "\n".join(l)
733 _dossiers_postes.allow_tags = True
734 _dossiers_postes.short_description = u"Dossiers et postes"
735
736 def _date_modification(self, obj):
737 return date(obj.date_modification) \
738 if obj.date_modification is not None else "(aucune)"
739 _date_modification.short_description = u'date modification'
740 _date_modification.admin_order_field = 'date_modification'
741
742 def queryset(self, request):
743 qs = super(EmployeAdminBase, self).queryset(request)
744 return qs.select_related(depth=1).order_by('nom')
745
746 def save_formset(self, request, form, formset, change):
747 instances = formset.save(commit=False)
748 for instance in instances:
749 if instance.__class__ == rh.EmployeCommentaire:
750 instance.owner = request.user
751 instance.date_creation = datetime.datetime.now()
752 instance.save()
753
754
755 class EmployeAdmin(reversion.VersionAdmin, EmployeAdminBase):
756 change_list_template = "admin/rh/employe/change_list.html"
757 ignore_duplicate_revisions = True
758
759
760 class EmployeProxyAdmin(EmployeAdminBase):
761 list_display = ('_id', '_apercu', '_nom', '_organigramme')
762 list_per_page = 500
763 actions = None
764
765 def __init__(self, *args, **kwargs):
766 super(EmployeProxyAdmin, self).__init__(*args, **kwargs)
767 self.list_display_links = (None, )
768
769 def queryset(self, request):
770 qs = super(ProtectRegionMixin, self).queryset(request)
771
772 if in_drh_or_admin(request.user) or \
773 user_gere_obj_de_sa_region(request.user):
774 return qs
775
776 return qs.none()
777
778 def has_add_permission(self, obj):
779 return False
780
781 def has_change_permission(self, request, obj=None):
782 user_groups = [g.name for g in request.user.groups.all()]
783 if groups.CORRESPONDANT_RH in user_groups or \
784 groups.ADMINISTRATEURS in user_groups or \
785 groups.DIRECTEUR_DE_BUREAU in user_groups or \
786 in_drh_or_admin(request.user):
787 return True
788 return False
789
790 def _organigramme(self, obj):
791 l = []
792 for d in rh.Dossier.objects.filter(
793 Q(date_fin__gt=datetime.date.today()) | Q(date_fin=None),
794 Q(date_debut__lt=datetime.date.today()) | Q(date_debut=None),
795 employe=obj.id
796 ):
797 organigramme = \
798 u'Organigramme, niveau: ' \
799 u'<input type="text" id="level_%s" ' \
800 u'style="width:30px;height:15px;" /> ' \
801 u'<input type="button" value="Générer" ' \
802 u"""onclick="window.location='%s' + """ \
803 u"""document.getElementById('level_%s').value" />""" % (
804 d.poste.id,
805 reverse('rho_employe_sans_niveau', args=(d.poste.id,)),
806 d.poste.id
807 )
808 link = u"""<li>%s [%s]:<br />%s</li>""" % (
809 d.poste.nom,
810 d.poste.id,
811 organigramme
812 )
813 l.append(link)
814 return "<ul>%s</ul>" % "\n".join(l)
815
816 _organigramme.allow_tags = True
817 _organigramme.short_description = "Organigramme"
818
819
820 class CategorieEmploiAdmin(reversion.VersionAdmin,
821 DerniereModificationAdmin, BaseAdmin):
822 ignore_duplicate_revisions = True
823 list_display = ('nom', 'derniere_modification')
824 inlines = (TypePosteInline,)
825 fieldsets = (
826 (None, {'fields': ('nom', )}),
827 )
828
829
830 class OrganismeBstgAdmin(reversion.VersionAdmin, DerniereModificationAdmin,
831 BaseAdmin):
832 ignore_duplicate_revisions = True
833 search_fields = ('nom',)
834 list_display = ('nom', 'type', 'pays', 'derniere_modification')
835 list_filter = ('type', )
836 inlines = (DossierROInline,)
837 fieldsets = (
838 (None, {'fields': ('nom', 'type', 'pays',)}),
839 )
840
841
842 class PosteAdmin(DateRangeMixin, ProtectRegionMixin, reversion.VersionAdmin,
843 AjaxSelect, DerniereModificationAdmin, BaseAdmin):
844 change_list_template = "admin/rh/poste/change_list.html"
845 ignore_duplicate_revisions = True
846 form = make_ajax_form(rh.Poste, {
847 'implantation': 'implantations',
848 'type_poste': 'typepostes',
849 'responsable': 'postes',
850 'valeur_point_min': 'valeurpoints',
851 'valeur_point_max': 'valeurpoints',
852 })
853 alphabet_filter = 'nom'
854 search_fields = (
855 'id',
856 'nom',
857 'implantation__nom',
858 'implantation__zone_administrative__code',
859 'implantation__zone_administrative__nom',
860 'rh_dossiers__employe__id',
861 'rh_dossiers__employe__nom',
862 'rh_dossiers__employe__prenom',
863 )
864 list_display = (
865 '_id', '_apercu', '_nom', '_occupe_par', 'implantation', '_service',
866 '_responsable', 'date_debut', 'date_fin', 'derniere_modification',
867 '_dae'
868 )
869 list_filter = (
870 'implantation__zone_administrative',
871 'implantation',
872 'service',
873 'type_poste',
874 'type_poste__categorie_emploi',
875 'type_poste__famille_professionnelle',
876 'vacant',
877 )
878 list_display_links = ('_nom',)
879 fieldsets = (
880 (None, {'fields': (
881 ('nom', 'nom_feminin'),
882 'implantation',
883 'type_poste',
884 'service',
885 'responsable',
886 )}
887 ),
888 ('Contrat', {
889 'fields': ((
890 'regime_travail',
891 'regime_travail_nb_heure_semaine'),
892 )}
893 ),
894 ('Recrutement', {
895 'fields': (('local', 'expatrie', 'mise_a_disposition', 'appel'),)}
896 ),
897 ('Rémunération', {
898 'fields': (('classement_min',
899 'valeur_point_min',
900 'devise_min',
901 'salaire_min',
902 'indemn_min',
903 'autre_min',),
904 ('classement_max',
905 'valeur_point_max',
906 'devise_max',
907 'salaire_max',
908 'indemn_max',
909 'autre_max',),
910 )}),
911 ('Comparatifs de rémunération', {
912 'fields': ('devise_comparaison',
913 ('comp_locale_min', 'comp_locale_max'),
914 ('comp_universite_min', 'comp_universite_max'),
915 ('comp_fonctionpub_min', 'comp_fonctionpub_max'),
916 ('comp_ong_min', 'comp_ong_max'),
917 ('comp_autre_min', 'comp_autre_max'))}
918 ),
919 ('Justification', {
920 'fields': ('justification',)}
921 ),
922 ('Autres Méta-données', {
923 'fields': ('date_debut', 'date_fin')}
924 ),
925 )
926
927 inlines = (PosteFinancementInline,
928 PostePieceInline,
929 DossierROInline,
930 PosteComparaisonInline,
931 PosteCommentaireInline, )
932
933 def lookup_allowed(self, key, value):
934 return key in (
935 'date_debut__gte', 'date_debut__isnull', 'date_fin__lte',
936 'date_fin__isnull',
937 'implantation__zone_administrative__code__exact',
938 'implantation__id__exact', 'type_poste__id__exact',
939 'type_poste__categorie_emploi__id__exact', 'service__id__exact',
940 'service__isnull', 'vacant__exact', 'vacant__isnull'
941 ) or super(PosteAdmin, self).lookup_allowed(key, value)
942
943 def _id(self, obj):
944 return "%s" % obj.id
945 _id.short_description = '#'
946 _id.admin_order_field = 'id'
947
948 def _apercu(self, poste):
949 view_link = u"""<a onclick="return showAddAnotherPopup(this);"
950 title="Aperçu du poste"
951 href='%s'>
952 <img src="%simg/poste-apercu.png" />
953 </a>""" % \
954 (reverse('poste_apercu', args=(poste.id,)),
955 settings.STATIC_URL,)
956 return view_link
957 _apercu.allow_tags = True
958 _apercu.short_description = ''
959
960 def _nom(self, poste):
961 return """<a href="%s">%s</a>""" % \
962 (reverse('admin:rh_poste_change', args=(poste.id,)),
963 poste.nom)
964 _nom.allow_tags = True
965 _nom.short_description = u'Poste'
966 _nom.admin_order_field = 'nom'
967
968 def _occupe_par(self, obj):
969 """Formatte la méthode Poste.occupe_par() pour l'admin"""
970 output = u"Vacant"
971 if obj.date_fin is not None and obj.date_fin < datetime.date.today():
972 return u"s/o"
973 employes = obj.occupe_par()
974 if employes:
975 l = []
976 for e in employes:
977 link = u"""<a href='%s'
978 title='Aperçu de l\'employé'
979 onclick='return showAddAnotherPopup(this)'>
980 <img src='%simg/employe-apercu.png' />
981 </a>
982 <a href='%s'>%s</a>""" % \
983 (reverse('employe_apercu', args=(e.id,)),
984 settings.STATIC_URL,
985 reverse('admin:rh_employe_change', args=(e.id,)),
986 e)
987 l.append(link)
988 output = "\n<br />".join(l)
989 return output
990 _occupe_par.allow_tags = True
991 _occupe_par.short_description = "Occupé par"
992
993 def _zone_administrative(self, poste):
994 return poste.implantation.zone_administrative.code
995 _zone_administrative.short_description = 'Zone administrative'
996 _zone_administrative.admin_order_field = \
997 'implantation__zone_administrative__code'
998
999 def _implantation(self, poste):
1000 return poste.implantation.nom
1001 _implantation.short_description = 'Implantation'
1002 _implantation.admin_order_field = 'implantation'
1003
1004 def _service(self, obj):
1005 return obj.service
1006 _service.short_description = 'Service'
1007 _service.allow_tags = True
1008
1009 def _responsable(self, obj):
1010 try:
1011 responsable = u"""<a href="%s"
1012 onclick="return showAddAnotherPopup(this)">
1013 <img src="%simg/poste-apercu.png"
1014 title="Aperçu du poste" />
1015 </a>
1016 <a href="%s">%s [%d]</a>
1017 <br />""" % \
1018 (reverse('poste_apercu', args=(obj.responsable.id,)),
1019 settings.STATIC_URL,
1020 reverse('admin:rh_poste_change', args=(obj.responsable.id,)),
1021 obj.responsable.nom,
1022 obj.responsable.id)
1023 except:
1024 responsable = ''
1025
1026 try:
1027 dossier = obj.responsable.rh_dossiers.all() \
1028 .order_by('-date_debut')[0]
1029 employe_id = dossier.employe.id
1030 employe_html = u"""<br />
1031 <a href="%s"
1032 onclick="return showAddAnotherPopup(this)">
1033 <img src="%simg/employe-apercu.png"
1034 title="Aperçu de l'employé">
1035 </a>
1036 <a href="%s">%s</a>""" % \
1037 (reverse('employe_apercu', args=(employe_id,)),
1038 settings.STATIC_URL,
1039 reverse('admin:rh_employe_change', args=(employe_id,)),
1040 dossier.employe)
1041 except:
1042 employe_html = ""
1043
1044 return "%s %s" % (responsable, employe_html)
1045 _responsable.short_description = 'Responsable'
1046 _responsable.allow_tags = True
1047
1048 def _date_debut(self, obj):
1049 return date_format(obj.date_debut)
1050 _date_debut.short_description = u'Début'
1051 _date_debut.admin_order_field = 'date_debut'
1052
1053 def _date_fin(self, obj):
1054 return date_format(obj.date_fin)
1055 _date_fin.short_description = u'Fin'
1056 _date_fin.admin_order_field = 'date_fin'
1057
1058 def _dae(self, poste):
1059 apercu_link = ""
1060 postes_dae = poste.postes_dae.all()
1061 if len(postes_dae) > 0:
1062 poste_dae = postes_dae[0]
1063 apercu_link = \
1064 u'<a title="Aperçu du dossier" href="%s" ' \
1065 u'onclick="return showAddAnotherPopup(this);">' \
1066 u'<img src="%simg/loupe.png" /></a>' % (reverse(
1067 'poste_consulter', args=("dae-%s" % poste_dae.id,)
1068 ), settings.STATIC_URL)
1069 return apercu_link
1070 _dae.allow_tags = True
1071 _dae.short_description = u"DAE"
1072
1073 def save_formset(self, request, form, formset, change):
1074 instances = formset.save(commit=False)
1075 for instance in instances:
1076 if instance.__class__ == rh.PosteCommentaire:
1077 instance.owner = request.user
1078 instance.date_creation = datetime.datetime.now()
1079 instance.save()
1080 formset.save_m2m()
1081
1082
1083 class ResponsableInline(admin.TabularInline):
1084 model = rh.ResponsableImplantation
1085 extra = 0
1086 fk_name = "implantation"
1087 form = ResponsableInlineForm
1088
1089
1090 class ResponsableImplantationAdmin(BaseAdmin):
1091 actions = None
1092 fields = ('nom', )
1093 inlines = (ResponsableInline, )
1094 list_filter = ('zone_administrative', 'statut', )
1095 list_display = ('_zone_administrative', '_nom', 'statut', '_responsable', )
1096 list_display_links = ('_nom',)
1097 list_per_page = 500
1098 readonly_fields = ('nom', )
1099 search_fields = (
1100 'nom',
1101 'responsable__employe__id',
1102 'responsable__employe__nom',
1103 'responsable__employe__prenom',
1104 )
1105 ordering = ('nom',)
1106 inlines = (ResponsableInline, )
1107
1108 def _zone_administrative(self, obj):
1109 return obj.zone_administrative.code
1110 _zone_administrative.short_description = u"Zone administrative"
1111 _zone_administrative.admin_order_field = 'zone_administrative__code'
1112
1113 def _nom(self, obj):
1114 return obj.nom
1115 _nom.short_description = u"Implantation"
1116 _nom.admin_order_field = 'nom'
1117
1118 def _responsable(self, obj):
1119 try:
1120 employe = employe = obj.responsable.employe
1121 except Exception, e:
1122 return (
1123 u"<span style='color: red;'>"
1124 u"Pas de responsable</span><!-- %s -->" % e
1125 )
1126 try:
1127 dossiers = employe.dossiers_encours()
1128 if len(dossiers) == 0:
1129 return u"<span style='color: red;'>%s %s </span>" % (
1130 employe, u"sans dossier actif")
1131 else:
1132 return employe
1133 except Exception, e:
1134 return u"<!-- %s -->" % e
1135 _responsable.allow_tags = True
1136 _responsable.short_description = u"Responsable"
1137 _responsable.admin_order_field = 'responsable__employe__nom'
1138
1139 def has_add_permission(self, request=None):
1140 return False
1141
1142 def has_change_permission(self, request, obj=None):
1143 return in_drh_or_admin(request.user)
1144
1145 def has_delete_permission(self, request, obj=None):
1146 return False
1147
1148
1149 class ServiceAdminBase(ArchivableAdmin, DerniereModificationAdmin, BaseAdmin):
1150 list_display = ('nom', 'derniere_modification', '_archive')
1151 list_filter = ('archive', )
1152 fieldsets = (
1153 (None, {'fields': ('nom', 'archive')}),
1154 )
1155
1156
1157 class ServiceAdmin(reversion.VersionAdmin, ServiceAdminBase):
1158 ignore_duplicate_revisions = True
1159
1160
1161 class ServiceProxyAdmin(ServiceAdminBase):
1162 list_display = ('nom', '_organigramme', '_archive', )
1163 actions = None
1164
1165 def __init__(self, *args, **kwargs):
1166 super(ServiceProxyAdmin, self).__init__(*args, **kwargs)
1167 self.list_display_links = (None, )
1168
1169 def queryset(self, request):
1170 return super(ServiceProxyAdmin, self).queryset(request) \
1171 .annotate(num_postes=Count('rh_postes')) \
1172 .filter(num_postes__gt=0)
1173
1174 def has_add_permission(self, obj):
1175 return False
1176
1177 def has_change_permission(self, request, obj=None):
1178 user_groups = [g.name for g in request.user.groups.all()]
1179 if groups.CORRESPONDANT_RH in user_groups or \
1180 groups.ADMINISTRATEURS in user_groups or \
1181 groups.DIRECTEUR_DE_BUREAU in user_groups or \
1182 in_drh_or_admin(request.user):
1183 return True
1184 return False
1185
1186 def _organigramme(self, obj):
1187 return """<a href="%s"><strong>Organigramme</strong></a>""" % \
1188 (reverse('rho_service', args=(obj.id,)))
1189 _organigramme.allow_tags = True
1190 _organigramme.short_description = "Organigramme"
1191
1192
1193 class StatutAdmin(reversion.VersionAdmin,
1194 ArchivableAdmin,
1195 DerniereModificationAdmin,
1196 BaseAdmin):
1197 ignore_duplicate_revisions = True
1198 list_display = ('code', 'nom', 'derniere_modification', '_archive')
1199 list_filter = ('archive', )
1200 fieldsets = (
1201 (None, {
1202 'fields': ('code', 'nom', 'archive'),
1203 }),
1204 )
1205
1206
1207 class TauxChangeAdmin(reversion.VersionAdmin, DerniereModificationAdmin,
1208 BaseAdmin):
1209 ignore_duplicate_revisions = True
1210 list_display = ('taux', 'devise', 'annee', 'derniere_modification')
1211 list_filter = ('devise',)
1212 fieldsets = (
1213 (None, {
1214 'fields': ('taux', 'devise', 'annee', ),
1215 }),
1216 )
1217
1218
1219 class TypeContratAdmin(reversion.VersionAdmin,
1220 ArchivableAdmin,
1221 DerniereModificationAdmin,
1222 BaseAdmin):
1223 ignore_duplicate_revisions = True
1224 list_display = ('nom', 'nom_long', 'derniere_modification', '_archive')
1225 list_filter = ('archive', )
1226 fieldsets = (
1227 (None, {
1228 'fields': ('nom', 'nom_long', 'archive'),
1229 }),
1230 )
1231
1232
1233 class TypePosteAdmin(reversion.VersionAdmin,
1234 ArchivableAdmin,
1235 DerniereModificationAdmin,
1236 BaseAdmin):
1237 ignore_duplicate_revisions = True
1238 search_fields = ('nom', 'nom_feminin', )
1239 list_display = ('nom', 'categorie_emploi',
1240 'derniere_modification', '_archive',)
1241 list_filter = ('categorie_emploi', 'famille_professionnelle', 'archive')
1242 fieldsets = (
1243 (None, {
1244 'fields': (
1245 'nom', 'nom_feminin', 'is_responsable', 'categorie_emploi',
1246 'famille_professionnelle',
1247 'archive',
1248 )
1249 }),
1250 )
1251
1252
1253 class TypeRemunerationAdmin(reversion.VersionAdmin, ArchivableAdmin,
1254 DerniereModificationAdmin, BaseAdmin):
1255 ignore_duplicate_revisions = True
1256 list_display = (
1257 'nom', 'type_paiement', 'nature_remuneration',
1258 'derniere_modification', '_archive'
1259 )
1260 list_filter = ('archive', )
1261 fieldsets = (
1262 (None, {
1263 'fields': (
1264 'nom', 'type_paiement', 'nature_remuneration', 'archive'
1265 )
1266 }),
1267 )
1268
1269
1270 class TypeRevalorisationAdmin(reversion.VersionAdmin,
1271 ArchivableAdmin,
1272 DerniereModificationAdmin,
1273 BaseAdmin):
1274 ignore_duplicate_revisions = True
1275 list_display = ('nom', 'derniere_modification', '_archive')
1276 list_filter = ('archive', )
1277 fieldsets = (
1278 (None, {'fields': ('nom', 'archive')}),
1279 )
1280
1281
1282 class ValeurPointAdmin(reversion.VersionAdmin,
1283 DerniereModificationAdmin,
1284 BaseAdmin):
1285 ignore_duplicate_revisions = True
1286 list_display = (
1287 '_devise_code', '_devise_nom', 'annee', 'implantation',
1288 'valeur', 'derniere_modification'
1289 )
1290 list_filter = ('annee', 'devise', 'implantation__zone_administrative', )
1291 fieldsets = (
1292 (None, {'fields': ('valeur', 'devise', 'implantation', 'annee')}),
1293 )
1294
1295 def queryset(self, request):
1296 return super(ValeurPointAdmin, self).queryset(request) \
1297 .select_related('devise', 'implantation')
1298
1299 def _devise_code(self, obj):
1300 return obj.devise.code
1301 _devise_code.short_description = "Code de la devise"
1302
1303 def _devise_nom(self, obj):
1304 return obj.devise.nom
1305 _devise_nom.short_description = "Nom de la devise"
1306
1307
1308 class ImplantationProxyAdmin(BaseAdmin):
1309 list_display = ('nom', '_organigramme')
1310 actions = None
1311
1312 def __init__(self, *args, **kwargs):
1313 super(ImplantationProxyAdmin, self).__init__(*args, **kwargs)
1314 self.list_display_links = (None, )
1315
1316 def has_add_permission(self, obj):
1317 return False
1318
1319 def has_change_permission(self, request, obj=None):
1320 user_groups = [g.name for g in request.user.groups.all()]
1321 if groups.CORRESPONDANT_RH in user_groups or \
1322 groups.ADMINISTRATEURS in user_groups or \
1323 groups.DIRECTEUR_DE_BUREAU in user_groups or \
1324 in_drh_or_admin(request.user):
1325 return True
1326 return False
1327
1328 def _organigramme(self, obj):
1329 return '<a href="%s"><strong>Organigramme</strong></a>' % (
1330 reverse('rho_implantation', args=(obj.id,))
1331 )
1332 _organigramme.allow_tags = True
1333 _organigramme.short_description = "Organigramme"
1334
1335
1336 class RegionProxyAdmin(BaseAdmin):
1337 list_display = ('nom', '_organigramme')
1338 actions = None
1339
1340 def __init__(self, *args, **kwargs):
1341 super(RegionProxyAdmin, self).__init__(*args, **kwargs)
1342 self.list_display_links = (None, )
1343
1344 def has_add_permission(self, obj):
1345 return False
1346
1347 def has_change_permission(self, request, obj=None):
1348 user_groups = [g.name for g in request.user.groups.all()]
1349 if groups.CORRESPONDANT_RH in user_groups or \
1350 groups.ADMINISTRATEURS in user_groups or \
1351 groups.DIRECTEUR_DE_BUREAU in user_groups or \
1352 in_drh_or_admin(request.user):
1353 return True
1354 return False
1355
1356 def _organigramme(self, obj):
1357 return """<a href="%s"><strong>Organigramme</strong></a>""" % (
1358 reverse('rho_region', args=(obj.id,))
1359 )
1360 _organigramme.allow_tags = True
1361 _organigramme.short_description = "Organigramme"
1362
1363
1364 class ProfileInline(admin.StackedInline):
1365 model = rh.UserProfile
1366
1367
1368 class RHUserAdmin(UserAdmin):
1369 inlines = list(UserAdmin.inlines) + [ProfileInline]
1370
1371
1372 def _invalidate(modaladmin, req, qs):
1373 qs.update(valide=False)
1374 _invalidate.short_description = 'Invalider'
1375
1376
1377 def _communique(modaladmin, req, qs):
1378 url_prefix = ('https://' if req.is_secure() else 'http://') + (
1379 req.META['SERVER_NAME'] if 'SERVER_NAME' in req.META else
1380 'localhost') + (':%s' % (req.META['SERVER_PORT']) if 'SERVER_PORT'
1381 in req.META else '')
1382
1383 types = [x[0] for x in rh.TYPES_CHANGEMENT]
1384
1385 # make a list of all possible email types. It is reversed so that
1386 # we start with the largest combinations.
1387 combs = list(itertools.chain(*map(
1388 lambda x: itertools.combinations(types, x),
1389 range(1, len(types)+1))))
1390
1391 combs = reversed(combs)
1392
1393 recipient_list = ref.Employe.objects.filter(
1394 changement_notifications__in=
1395 rh.ChangementPersonnelNotifications.objects.all()).distinct()
1396
1397 thead_colors = {
1398 'NO': 'ff99ff',
1399 'MO': 'ccccff',
1400 'DE': 'ff99ff',
1401 }
1402
1403
1404 for comb in combs:
1405
1406 recipients = ref.Employe.objects.none()
1407 for t in comb:
1408 recipients = recipient_list.filter(changement_notifications__type=t)
1409
1410 recipient_list = recipient_list.exclude(
1411 id__in=recipients.values_list('id', flat=True))
1412
1413 types_dict = dict(rh.TYPES_CHANGEMENT)
1414
1415
1416 if len(recipients):
1417 ctx = {
1418 'types': [
1419 ]
1420 }
1421
1422 for t in comb:
1423 changements = []
1424 ctx['types'].append({
1425 'bgcolor': thead_colors[t],
1426 'name': types_dict[t],
1427 'key': t,
1428 'changements': changements,
1429 })
1430
1431 for ch in qs.filter(type__in=[t]):
1432 changements.append(ch)
1433
1434 template = loader.get_template('email/mouvement_employe.html')
1435 content = template.render(Context(ctx))
1436
1437 sujet = '[SGRH] ARRIVÉES - DÉPARTS - MOBILITÉS'
1438
1439 msg = EmailMessage(
1440 sujet,
1441 content,
1442 settings.SERVER_EMAIL,
1443 [x.courriel for x in recipients],
1444 )
1445 msg.content_subtype = "html"
1446 msg.send()
1447
1448 qs.update(
1449 communique=True,
1450 date_communication=datetime.datetime.now()
1451 )
1452
1453 _communique.short_description = u'Envoyer aux desinataires prévus.'
1454
1455
1456 class ChangementPersonnelAdmin(admin.ModelAdmin):
1457
1458 actions = (
1459 _invalidate,
1460 _communique,
1461 )
1462
1463 def _dossier(obj):
1464 return obj.dossier.__unicode__()
1465 _dossier.short_description = u'Dossier'
1466
1467 list_display = (
1468 'type', _dossier, 'valide', 'communique', 'date_communication'
1469 )
1470
1471 list_filter = (
1472 'type',
1473 'valide',
1474 'communique',
1475 )
1476
1477
1478 admin.site.unregister(User)
1479 admin.site.register(User, RHUserAdmin)
1480
1481 admin.site.register(rh.Classement, ClassementAdmin)
1482 admin.site.register(rh.Devise, DeviseAdmin)
1483 admin.site.register(rh.Dossier, DossierAdmin)
1484 admin.site.register(EmployeProxy, EmployeProxyAdmin)
1485 admin.site.register(ServiceProxy, ServiceProxyAdmin)
1486 admin.site.register(rh.Employe, EmployeAdmin)
1487 admin.site.register(rh.CategorieEmploi, CategorieEmploiAdmin)
1488 admin.site.register(rh.FamilleProfessionnelle)
1489 admin.site.register(rh.OrganismeBstg, OrganismeBstgAdmin)
1490 admin.site.register(rh.Poste, PosteAdmin)
1491 admin.site.register(
1492 rh.ResponsableImplantationProxy, ResponsableImplantationAdmin
1493 )
1494 admin.site.register(rh.Service, ServiceAdmin)
1495 admin.site.register(rh.Statut, StatutAdmin)
1496 admin.site.register(rh.TauxChange, TauxChangeAdmin)
1497 admin.site.register(rh.TypeContrat, TypeContratAdmin)
1498 admin.site.register(rh.TypePoste, TypePosteAdmin)
1499 admin.site.register(rh.TypeRemuneration, TypeRemunerationAdmin)
1500 admin.site.register(rh.TypeRevalorisation, TypeRevalorisationAdmin)
1501 admin.site.register(rh.ValeurPoint, ValeurPointAdmin)
1502 admin.site.register(ImplantationProxy, ImplantationProxyAdmin)
1503 admin.site.register(RegionProxy, RegionProxyAdmin)
1504 admin.site.register(rh.ChangementPersonnelNotifications)
1505 admin.site.register(rh.ChangementPersonnel, ChangementPersonnelAdmin)