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