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