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