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