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