8b885c873c6d96a164562576c4938ec560858c6b
[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 'type_poste__famille_professionnelle',
746 'vacant',
747 )
748 list_display_links = ('_nom',)
749 fieldsets = AUFMetadataAdminMixin.fieldsets + (
750 (None, {'fields': (
751 ('nom', 'nom_feminin'),
752 'implantation',
753 'type_poste',
754 'service',
755 'responsable',
756 )}
757 ),
758 ('Contrat', {
759 'fields': ((
760 'regime_travail',
761 'regime_travail_nb_heure_semaine'),
762 )}
763 ),
764 ('Recrutement', {
765 'fields': (('local', 'expatrie', 'mise_a_disposition', 'appel'),)}
766 ),
767 ('Rémunération', {
768 'fields': (('classement_min',
769 'valeur_point_min',
770 'devise_min',
771 'salaire_min',
772 'indemn_min',
773 'autre_min',),
774 ('classement_max',
775 'valeur_point_max',
776 'devise_max',
777 'salaire_max',
778 'indemn_max',
779 'autre_max',),
780 )}),
781 ('Comparatifs de rémunération', {
782 'fields': ('devise_comparaison',
783 ('comp_locale_min', 'comp_locale_max'),
784 ('comp_universite_min', 'comp_universite_max'),
785 ('comp_fonctionpub_min', 'comp_fonctionpub_max'),
786 ('comp_ong_min', 'comp_ong_max'),
787 ('comp_autre_min', 'comp_autre_max'))}
788 ),
789 ('Justification', {
790 'fields': ('justification',)}
791 ),
792 ('Autres Méta-données', {
793 'fields': ('date_debut', 'date_fin')}
794 ),
795 )
796
797 inlines = (PosteFinancementInline,
798 PostePieceInline,
799 DossierROInline,
800 PosteComparaisonInline,
801 PosteCommentaireInline, )
802
803 def lookup_allowed(self, key, value):
804 return key in (
805 'date_debut__gte', 'date_debut__isnull', 'date_fin__lte',
806 'date_fin__isnull', 'implantation__region__id__exact',
807 'implantation__id__exact', 'type_poste__id__exact',
808 'type_poste__categorie_emploi__id__exact', 'service__id__exact',
809 'service__isnull', 'vacant__exact', 'vacant__isnull',
810 ) or super(PosteAdmin, self).lookup_allowed(key, value)
811
812 def _apercu(self, poste):
813 view_link = u"""<a onclick="return showAddAnotherPopup(this);"
814 title="Aperçu du poste"
815 href='%s'>
816 <img src="%simg/loupe.png" />
817 </a>""" % \
818 (reverse('poste_apercu', args=(poste.id,)),
819 settings.STATIC_URL,)
820 return view_link
821 _apercu.allow_tags = True
822 _apercu.short_description = ''
823
824 def _dae(self, poste):
825 apercu_link = ""
826 postes_dae = poste.postes_dae.all()
827 if len(postes_dae) > 0:
828 poste_dae = postes_dae[0]
829 apercu_link = \
830 u'<a title="Aperçu du dossier" href="%s" ' \
831 u'onclick="return showAddAnotherPopup(this);">' \
832 u'<img src="%simg/loupe.png" /></a>' % (reverse(
833 'poste_consulter', args=("dae-%s" % poste_dae.id,)
834 ), settings.STATIC_URL)
835 return apercu_link
836 _dae.allow_tags = True
837 _dae.short_description = u"DAE"
838
839 def _id(self, obj):
840 return "%s" % obj.id
841 _id.short_description = '#'
842 _id.admin_order_field = 'id'
843
844 def _service(self, obj):
845 if obj.service.supprime:
846 return """<span style="color:red">%s</span>""" % obj.service
847 else:
848 return obj.service
849 _service.short_description = 'Service'
850 _service.allow_tags = True
851
852 def _responsable(self, obj):
853 try:
854 responsable = u"""<a href="%s"
855 onclick="return showAddAnotherPopup(this)">
856 <img src="%simg/loupe.png"
857 title="Aperçu du poste" />
858 </a>
859 <a href="%s">%s</a>
860 <br />""" % \
861 (reverse('poste_apercu', args=(obj.responsable.id,)),
862 settings.STATIC_URL,
863 reverse('admin:rh_poste_change', args=(obj.responsable.id,)),
864 obj.responsable.nom)
865 except:
866 responsable = ''
867
868 try:
869 employe = obj.responsable.rh_dossiers.all()[0]
870 employe_id = obj.responsable.rh_dossiers.all()[0].id
871 employe_html = u"""<br />
872 <a href="%s"
873 onclick="return showAddAnotherPopup(this)">
874 <img src="%simg/loupe.png"
875 title="Aperçu de l'employé">
876 </a>
877 <a href="%s">%s</a>""" % \
878 (reverse('employe_apercu', args=(employe_id,)),
879 settings.STATIC_URL,
880 reverse('admin:rh_employe_change', args=(employe_id,)),
881 employe)
882 except:
883 employe_html = ""
884
885 return "%s %s" % (responsable, employe_html)
886 _responsable.short_description = 'Responsable'
887 _responsable.allow_tags = True
888
889 def _nom(self, poste):
890 return """<a href="%s">%s</a>""" % \
891 (reverse('admin:rh_poste_change', args=(poste.id,)),
892 poste.nom)
893 _nom.allow_tags = True
894 _nom.short_description = u'Nom'
895 _nom.admin_order_field = 'nom'
896
897 def _date_modification(self, obj):
898 return date(obj.date_modification)
899 _date_modification.short_description = u'date modification'
900 _date_modification.admin_order_field = 'date_modification'
901
902 def _occupe_par(self, obj):
903 """Formatte la méthode Poste.occupe_par() pour l'admin"""
904 output = u"Vacant"
905 if obj.date_fin is not None and obj.date_fin < datetime.date.today():
906 return u"s/o"
907 employes = obj.occupe_par()
908 if employes:
909 l = []
910 for e in employes:
911 link = u"""<a href='%s'
912 title='Aperçu de l\'employer'
913 onclick='return showAddAnotherPopup(this)'>
914 <img src='%simg/loupe.png' />
915 </a>
916 <a href='%s'>%s</a>""" % \
917 (reverse('employe_apercu', args=(e.id,)),
918 settings.STATIC_URL,
919 reverse('admin:rh_employe_change', args=(e.id,)),
920 e)
921 l.append(link)
922 output = "\n<br />".join(l)
923 return output
924 _occupe_par.allow_tags = True
925 _occupe_par.short_description = "Occupé par"
926
927 def save_formset(self, request, form, formset, change):
928 instances = formset.save(commit=False)
929 for instance in instances:
930 if instance.__class__ == rh.PosteCommentaire:
931 instance.owner = request.user
932 instance.date_creation = datetime.datetime.now()
933 instance.save()
934 formset.save_m2m()
935
936
937 class PosteCommentaireAdmin(admin.ModelAdmin):
938 pass
939
940
941 class PosteFinancementAdmin(admin.ModelAdmin):
942 pass
943
944
945 class PostePieceAdmin(admin.ModelAdmin):
946 fk_name = 'poste'
947
948
949 class RemunerationAdmin(admin.ModelAdmin):
950 pass
951
952
953 class ResponsableInline(admin.TabularInline):
954 model = rh.ResponsableImplantation
955 extra = 0
956 fk_name = "implantation"
957
958
959 class ResponsableImplantationAdmin(admin.ModelAdmin):
960 actions = None
961 list_filter = ('region', 'statut', )
962 list_display = ('nom', 'statut', '_responsable', )
963 readonly_fields = ('nom', )
964 fields = ('nom', )
965 inlines = (ResponsableInline, )
966
967 def _responsable(self, obj):
968 try:
969 employe = obj.responsable.employe
970 dossiers = employe.dossiers_encours()
971 if len(dossiers) == 0:
972 return u"<span style='color: red;'>%s %s </span>" % (
973 employe, u"sans dossier actif")
974 else:
975 return employe
976 except Exception:
977 if obj.statut in (1, 2): # ouverte, ouverture imminente
978 css = "style='color: red;'"
979 else:
980 css = ""
981 return u"<span %s>Pas de responsable</span>" % css
982 _responsable.allow_tags = True
983 _responsable.short_description = u"Responsable"
984
985 def has_add_permission(self, request=None):
986 return False
987
988 def has_change_permission(self, request, obj=None):
989 return in_drh_or_admin(request.user)
990
991 def has_delete_permission(self, request, obj=None):
992 return False
993
994
995 class ServiceAdmin(AUFMetadataAdminMixin, admin.ModelAdmin, ArchiveMixin):
996 list_display = (
997 'nom',
998 '_archive',
999 '_date_modification',
1000 'user_modification',
1001 )
1002 list_filter = ('archive', )
1003 fieldsets = AUFMetadataAdminMixin.fieldsets + (
1004 (None, {
1005 'fields': ('nom', 'archive', ),
1006 }),
1007 )
1008
1009 def _date_modification(self, obj):
1010 return date(obj.date_modification) \
1011 if obj.date_modification is not None else "(aucune)"
1012 _date_modification.short_description = u'date modification'
1013 _date_modification.admin_order_field = 'date_modification'
1014
1015
1016 class ServiceProxyAdmin(ServiceAdmin):
1017 list_display = ('nom', '_organigramme', '_archive', )
1018 actions = None
1019
1020 def __init__(self, *args, **kwargs):
1021 super(ServiceProxyAdmin, self).__init__(*args, **kwargs)
1022 self.list_display_links = (None, )
1023
1024 def has_add_permission(self, obj):
1025 return False
1026
1027 def has_change_permission(self, request, obj=None):
1028 return in_drh_or_admin(request.user)
1029
1030 def _organigramme(self, obj):
1031 return """<a href="%s"><strong>Organigramme</strong></a>""" % \
1032 (reverse('rho_service', args=(obj.id,)))
1033 _organigramme.allow_tags = True
1034 _organigramme.short_description = "Organigramme"
1035
1036
1037 class StatutAdmin(AUFMetadataAdminMixin, admin.ModelAdmin):
1038 list_display = ('code', 'nom', '_date_modification', 'user_modification', )
1039 fieldsets = AUFMetadataAdminMixin.fieldsets + (
1040 (None, {
1041 'fields': ('code', 'nom', ),
1042 }),
1043 )
1044
1045 def _date_modification(self, obj):
1046 return date(obj.date_modification) \
1047 if obj.date_modification is not None else "(aucune)"
1048 _date_modification.short_description = u'date modification'
1049 _date_modification.admin_order_field = 'date_modification'
1050
1051
1052 class TauxChangeAdmin(admin.ModelAdmin):
1053 list_display = (
1054 'taux',
1055 'devise',
1056 'annee',
1057 '_date_modification',
1058 'user_modification',
1059 )
1060 list_filter = ('devise', )
1061 fieldsets = AUFMetadataAdminMixin.fieldsets + (
1062 (None, {
1063 'fields': ('taux', 'devise', 'annee', ),
1064 }),
1065 )
1066
1067 def _date_modification(self, obj):
1068 return date(obj.date_modification) \
1069 if obj.date_modification is not None else "(aucune)"
1070 _date_modification.short_description = u'date modification'
1071 _date_modification.admin_order_field = 'date_modification'
1072
1073
1074 class TypeContratAdmin(admin.ModelAdmin):
1075 list_display = (
1076 'nom',
1077 'nom_long',
1078 '_date_modification',
1079 'user_modification',
1080 )
1081 fieldsets = AUFMetadataAdminMixin.fieldsets + (
1082 (None, {
1083 'fields': ('nom', 'nom_long', ),
1084 }),
1085 )
1086
1087 def _date_modification(self, obj):
1088 return date(obj.date_modification) \
1089 if obj.date_modification is not None else "(aucune)"
1090 _date_modification.short_description = u'date modification'
1091 _date_modification.admin_order_field = 'date_modification'
1092
1093
1094 class TypePosteAdmin(AUFMetadataAdminMixin, admin.ModelAdmin):
1095 search_fields = ('nom', 'nom_feminin', )
1096 list_display = (
1097 'nom',
1098 'categorie_emploi',
1099 '_date_modification',
1100 'user_modification',
1101 )
1102 list_filter = ('categorie_emploi', 'famille_professionnelle')
1103 fieldsets = AUFMetadataAdminMixin.fieldsets + (
1104 (None, {
1105 'fields': (
1106 'nom',
1107 'nom_feminin',
1108 'is_responsable',
1109 'categorie_emploi',
1110 'famille_professionnelle',
1111 )}
1112 ),
1113 )
1114
1115 def _date_modification(self, obj):
1116 return date(obj.date_modification) \
1117 if obj.date_modification is not None else "(aucune)"
1118 _date_modification.short_description = u'date modification'
1119 _date_modification.admin_order_field = 'date_modification'
1120
1121
1122 class TypeRemunerationAdmin(AUFMetadataAdminMixin, admin.ModelAdmin,
1123 ArchiveMixin):
1124 list_display = (
1125 'nom',
1126 'type_paiement',
1127 'nature_remuneration',
1128 '_archive',
1129 '_date_modification',
1130 'user_modification',)
1131 list_filter = ('archive', )
1132 fieldsets = AUFMetadataAdminMixin.fieldsets + (
1133 (None, {'fields': ('nom', 'type_paiement', 'nature_remuneration',
1134 'archive')}),
1135 )
1136
1137 def _date_modification(self, obj):
1138 return date(obj.date_modification) \
1139 if obj.date_modification is not None else "(aucune)"
1140 _date_modification.short_description = u'date modification'
1141 _date_modification.admin_order_field = 'date_modification'
1142
1143
1144 class TypeRevalorisationAdmin(AUFMetadataAdminMixin, admin.ModelAdmin):
1145 list_display = ('nom', '_date_modification', 'user_modification', )
1146 fieldsets = AUFMetadataAdminMixin.fieldsets + (
1147 (None, {'fields': ('nom', )}),
1148 )
1149
1150 def _date_modification(self, obj):
1151 return date(obj.date_modification) \
1152 if obj.date_modification is not None else "(aucune)"
1153 _date_modification.short_description = u'date modification'
1154 _date_modification.admin_order_field = 'date_modification'
1155
1156
1157 class ValeurPointAdmin(AUFMetadataAdminMixin, admin.ModelAdmin):
1158 list_display = (
1159 '_devise_code',
1160 '_devise_nom',
1161 'annee',
1162 'implantation',
1163 'valeur',
1164 '_date_modification',
1165 'user_modification',
1166 )
1167 list_filter = ('annee', 'devise', 'implantation__region', )
1168 fieldsets = AUFMetadataAdminMixin.fieldsets + (
1169 (None, {'fields': ('valeur', 'devise', 'implantation', 'annee', )}),
1170 )
1171
1172 def _date_modification(self, obj):
1173 return date(obj.date_modification) \
1174 if obj.date_modification is not None else "(aucune)"
1175 _date_modification.short_description = u'date modification'
1176 _date_modification.admin_order_field = 'date_modification'
1177
1178 def _devise_code(self, obj):
1179 return obj.devise.code
1180 _devise_code.short_description = "Code de la devise"
1181
1182 def _devise_nom(self, obj):
1183 return obj.devise.nom
1184 _devise_nom.short_description = "Nom de la devise"
1185
1186
1187 class ImplantationProxyAdmin(admin.ModelAdmin):
1188 list_display = ('nom', '_organigramme')
1189 actions = None
1190
1191 def __init__(self, *args, **kwargs):
1192 super(ImplantationProxyAdmin, self).__init__(*args, **kwargs)
1193 self.list_display_links = (None, )
1194
1195 def has_add_permission(self, obj):
1196 return False
1197
1198 def has_change_permission(self, request, obj=None):
1199 return in_drh_or_admin(request.user)
1200
1201 def _organigramme(self, obj):
1202 return '<a href="%s"><strong>Organigramme</strong></a>' % (
1203 reverse('rho_implantation', args=(obj.id,))
1204 )
1205 _organigramme.allow_tags = True
1206 _organigramme.short_description = "Organigramme"
1207
1208
1209 class RegionProxyAdmin(admin.ModelAdmin):
1210 list_display = ('nom', '_organigramme')
1211 actions = None
1212
1213 def __init__(self, *args, **kwargs):
1214 super(RegionProxyAdmin, self).__init__(*args, **kwargs)
1215 self.list_display_links = (None, )
1216
1217 def has_add_permission(self, obj):
1218 return False
1219
1220 def has_change_permission(self, request, obj=None):
1221 return in_drh_or_admin(request.user)
1222
1223 def _organigramme(self, obj):
1224 return """<a href="%s"><strong>Organigramme</strong></a>""" % (
1225 reverse('rho_region', args=(obj.id,))
1226 )
1227 _organigramme.allow_tags = True
1228 _organigramme.short_description = "Organigramme"
1229
1230
1231 admin.site.register(rh.Classement, ClassementAdmin)
1232 admin.site.register(rh.Devise, DeviseAdmin)
1233 admin.site.register(rh.Dossier, DossierAdmin)
1234 admin.site.register(EmployeProxy, EmployeProxyAdmin)
1235 admin.site.register(ServiceProxy, ServiceProxyAdmin)
1236 admin.site.register(rh.Employe, EmployeAdmin)
1237 admin.site.register(rh.CategorieEmploi, CategorieEmploiAdmin)
1238 admin.site.register(rh.FamilleProfessionnelle)
1239 admin.site.register(rh.OrganismeBstg, OrganismeBstgAdmin)
1240 admin.site.register(rh.Poste, PosteAdmin)
1241 admin.site.register(
1242 rh.ResponsableImplantationProxy, ResponsableImplantationAdmin
1243 )
1244 admin.site.register(rh.Service, ServiceAdmin)
1245 admin.site.register(rh.Statut, StatutAdmin)
1246 admin.site.register(rh.TauxChange, TauxChangeAdmin)
1247 admin.site.register(rh.TypeContrat, TypeContratAdmin)
1248 admin.site.register(rh.TypePoste, TypePosteAdmin)
1249 admin.site.register(rh.TypeRemuneration, TypeRemunerationAdmin)
1250 admin.site.register(rh.TypeRevalorisation, TypeRevalorisationAdmin)
1251 admin.site.register(rh.ValeurPoint, ValeurPointAdmin)
1252 admin.site.register(ImplantationProxy, ImplantationProxyAdmin)
1253 admin.site.register(RegionProxy, RegionProxyAdmin)