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