responsables implantation
[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__famille_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__famille_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 if dae.ImportDossier.objects.filter(rh=d).exists():
402 dae_id = dae.ImportDossier.objects.get(rh=d).dae_id
403 apercu_link = u"""<a title="Aperçu du dossier"
404 onclick="return showAddAnotherPopup(this);"
405 href='%s'>
406 <img src="%simg/loupe.png" />
407 </a>""" % \
408 (reverse('embauche_consulter', args=(dae_id,)),
409 settings.STATIC_URL,
410 )
411 return apercu_link
412 _dae.allow_tags = True
413 _dae.short_description = u"DAE"
414
415 def _date_debut(self, obj):
416 return date(obj.date_debut)
417
418 _date_debut.short_description = u'Occupation début'
419 _date_debut.admin_order_field = 'date_debut'
420
421 def _date_fin(self, obj):
422 return date(obj.date_fin)
423 _date_fin.short_description = u'Occupation fin'
424 _date_fin.admin_order_field = 'date_fin'
425
426 def _date_modification(self, obj):
427 return date(obj.date_modification) \
428 if obj.date_modification is not None else "(aucune)"
429 _date_modification.short_description = u'date modification'
430 _date_modification.admin_order_field = 'date_modification'
431
432 def _poste(self, dossier):
433 link = u"""<a title="Aperçu du poste"
434 onclick="return showAddAnotherPopup(this);"
435 href='%s'><img src="%simg/loupe.png" />
436 </a>
437 <a href="%s" title="Modifier le poste">%s</a>""" % \
438 (reverse('poste_apercu', args=(dossier.poste.id,)),
439 settings.STATIC_URL,
440 reverse('admin:rh_poste_change', args=(dossier.poste.id,)),
441 dossier.poste,
442 )
443 return link
444 _poste.allow_tags = True
445 _poste.short_description = u'Poste'
446 _poste.admin_order_field = 'poste__nom'
447
448 def _employe(self, obj):
449 employe = obj.employe
450 view_link = reverse('employe_apercu', args=(employe.id,))
451 edit_link = reverse('admin:rh_employe_change', args=(employe.id,))
452
453 style = ""
454 view = u"""<a href="%s"
455 title="Aperçu l'employé"
456 onclick="return showAddAnotherPopup(this);">
457 <img src="%simg/loupe.png" />
458 </a>""" % (view_link, settings.STATIC_URL,)
459 return u"""%s<a href='%s' style="%s;">%s</a>""" % \
460 (view, edit_link, style, employe)
461 _employe.allow_tags = True
462 _employe.short_description = u"Employé"
463 _employe.admin_order_field = "employe__nom"
464
465 def save_formset(self, request, form, formset, change):
466 instances = formset.save(commit=False)
467 for instance in instances:
468 if instance.__class__ == rh.DossierCommentaire:
469 instance.owner = request.user
470 instance.date_creation = datetime.datetime.now()
471 instance.save()
472
473
474 class DossierPieceAdmin(admin.ModelAdmin):
475 pass
476
477
478 class DossierCommentaireAdmin(admin.ModelAdmin):
479 pass
480
481
482 class EmployeAdmin(DateRangeMixin, AUFMetadataAdminMixin, \
483 ProtectRegionMixin, admin.ModelAdmin,):
484 prefixe_recherche_temporelle = "rh_dossiers__"
485 alphabet_filter = 'nom'
486 DEFAULT_ALPHABET = u'ABCDEFGHIJKLMNOPQRSTUVWXYZ'
487 search_fields = ('id', 'nom', 'prenom', 'nom_affichage', )
488 ordering = ('nom', )
489 form = EmployeAdminForm
490 list_display = (
491 '_id',
492 '_apercu',
493 '_nom',
494 '_dossiers_postes',
495 '_date_modification',
496 'user_modification',
497 )
498 list_display_links = ('_nom',)
499 list_filter = (
500 'rh_dossiers__poste__implantation__region',
501 'rh_dossiers__poste__implantation',
502 'nb_postes',
503 )
504 inlines = (AyantDroitInline,
505 DossierROInline,
506 EmployePieceInline,
507 EmployeCommentaireInline)
508 fieldsets = AUFMetadataAdminMixin.fieldsets + (
509 ('Identification', {
510 'fields': (
511 ('nom', 'prenom'),
512 ('nom_affichage', 'genre'),
513 'nationalite',
514 'date_naissance',
515 )}
516 ),
517 ('Informations personnelles', {
518 'fields': ('situation_famille', 'date_entree', )}
519 ),
520 ('Coordonnées', {
521 'fields': (
522 ('tel_domicile', 'tel_cellulaire'),
523 ('adresse', 'ville'),
524 ('code_postal', 'province'),
525 'pays',
526 )}
527 ),
528 )
529
530 def _apercu(self, obj):
531 return u"""<a title="Aperçu de l'employé"
532 onclick="return showAddAnotherPopup(this);"
533 href='%s'>
534 <img src="%simg/loupe.png" />
535 </a>""" % \
536 (reverse('employe_apercu', args=(obj.id,)), settings.STATIC_URL)
537 _apercu.allow_tags = True
538 _apercu.short_description = u""
539
540 def _nom(self, obj):
541 edit_link = reverse('admin:rh_employe_change', args=(obj.id,))
542 return u"""<a href='%s'><strong>%s</strong></a>""" % \
543 (edit_link, "%s %s" % (obj.nom.upper(), obj.prenom))
544 _nom.allow_tags = True
545 _nom.short_description = u"Employé"
546 _nom.admin_order_field = "nom"
547
548 def _id(self, obj):
549 return obj.id
550 _id.short_description = u"#"
551 _id.admin_order_field = "id"
552
553 def _date_modification(self, obj):
554 return date(obj.date_modification) \
555 if obj.date_modification is not None else "(aucune)"
556 _date_modification.short_description = u'date modification'
557 _date_modification.admin_order_field = 'date_modification'
558
559 def _dossiers_postes(self, obj):
560 l = []
561 for d in obj.rh_dossiers.all().order_by('-date_debut'):
562 dossier = u"""<a title="Aperçu du dossier"
563 href="%s"
564 onclick="return showAddAnotherPopup(this);"
565 title="Aperçu du dossier">
566 <img src="%simg/loupe.png" />
567 </a>
568 <a href="%s">Dossier</a>
569 &nbsp;""" % \
570 (reverse('dossier_apercu', args=(d.id,)),
571 settings.STATIC_URL,
572 reverse('admin:rh_dossier_change', args=(d.id,)))
573
574 poste = u"""<a title="Aperçu du poste"
575 href="%s"
576 onclick="return showAddAnotherPopup(this);"
577 title="Aperçu du poste">
578 <img src="%simg/loupe.png" />
579 </a>
580 <a href="%s">Poste</a>
581 &nbsp;""" % \
582 (reverse('poste_apercu', args=(d.poste.id,)),
583 settings.STATIC_URL,
584 reverse('admin:rh_poste_change', args=(d.poste.id,)))
585 link = u"""<li>%s %s - %s : [%s] %s</li>""" % \
586 (dossier, poste,
587 d.date_debut.year,
588 d.poste.id,
589 d.poste.nom,
590 )
591
592 # Dossier terminé en gris non cliquable
593 if d.date_fin is not None and d.date_fin < datetime.date.today():
594 link = u"""<li style="color: grey">%s : [%s] %s</li>""" % \
595 (d.date_debut.year,
596 d.poste.id,
597 d.poste.nom,
598 )
599
600 l.append(link)
601 return "<ul>%s</ul>" % "\n".join(l)
602 _dossiers_postes.allow_tags = True
603 _dossiers_postes.short_description = u"Dossiers et postes"
604
605 def queryset(self, request):
606 qs = super(EmployeAdmin, self).queryset(request)
607 return qs.select_related(depth=1).order_by('nom')
608
609 def save_formset(self, request, form, formset, change):
610 instances = formset.save(commit=False)
611 for instance in instances:
612 if instance.__class__ == rh.EmployeCommentaire:
613 instance.owner = request.user
614 instance.date_creation = datetime.datetime.now()
615 instance.save()
616
617
618 class EmployeProxyAdmin(EmployeAdmin):
619 list_display = ('_id', '_apercu', '_nom', '_organigramme')
620 actions = None
621
622 def __init__(self, *args, **kwargs):
623 super(EmployeProxyAdmin, self).__init__(*args, **kwargs)
624 self.list_display_links = (None, )
625
626 def has_add_permission(self, obj):
627 return False
628
629 def _organigramme(self, obj):
630 l = []
631 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():
632 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" />""" % \
633 (d.poste.id, reverse('rho_employe_sans_niveau', args=(d.poste.id,)), d.poste.id)
634 link = u"""<li>%s - [%s] %s : %s</li>""" % \
635 (d.date_debut.year,
636 d.poste.id,
637 d.poste.nom,
638 organigramme
639 )
640 l.append(link)
641 return "<ul>%s</ul>" % "\n".join(l)
642
643 _organigramme.allow_tags = True
644 _organigramme.short_description = "Organigramme"
645
646
647 class EmployeCommentaireAdmin(admin.ModelAdmin):
648 pass
649
650
651 class EmployePieceAdmin(admin.ModelAdmin):
652 pass
653
654
655 class FamilleEmploiAdmin(AUFMetadataAdminMixin, admin.ModelAdmin):
656 list_display = ('nom', '_date_modification', 'user_modification', )
657 inlines = (TypePosteInline,)
658 fieldsets = AUFMetadataAdminMixin.fieldsets + (
659 (None, {'fields': ('nom', )}),)
660
661 def _date_modification(self, obj):
662 return date(obj.date_modification) \
663 if obj.date_modification is not None else "(aucune)"
664 _date_modification.short_description = u'date modification'
665 _date_modification.admin_order_field = 'date_modification'
666
667
668 class OrganismeBstgAdmin(AUFMetadataAdminMixin, admin.ModelAdmin):
669 search_fields = ('nom',)
670 list_display = (
671 'nom',
672 'type',
673 'pays',
674 '_date_modification',
675 'user_modification',
676 )
677 list_filter = ('type', )
678 inlines = (DossierROInline,)
679 fieldsets = AUFMetadataAdminMixin.fieldsets + (
680 (None, {'fields': ('nom', 'type', 'pays',)}),
681 )
682
683 def _date_modification(self, obj):
684 return date(obj.date_modification) \
685 if obj.date_modification is not None else "(aucune)"
686 _date_modification.short_description = u'date modification'
687 _date_modification.admin_order_field = 'date_modification'
688
689
690 class PosteAdmin(DateRangeMixin, AUFMetadataAdminMixin, \
691 ProtectRegionMixin, admin.ModelAdmin, AjaxSelect,):
692 form = make_ajax_form(rh.Poste, {
693 'implantation': 'implantations',
694 'type_poste': 'typepostes',
695 'responsable': 'postes',
696 'valeur_point_min': 'valeurpoints',
697 'valeur_point_max': 'valeurpoints',
698 })
699 alphabet_filter = 'nom'
700 search_fields = (
701 'id',
702 'nom',
703 'implantation__nom',
704 'implantation__region__code',
705 'implantation__region__nom',
706 'rh_dossiers__employe__nom',
707 'rh_dossiers__employe__prenom',
708 )
709 list_display = (
710 '_id',
711 '_apercu',
712 '_nom',
713 '_occupe_par',
714 'implantation',
715 '_service',
716 '_responsable',
717 'date_debut',
718 'date_fin',
719 '_date_modification',
720 'user_modification',
721 '_dae',
722 )
723 list_filter = (
724 'implantation__region',
725 'implantation',
726 'service',
727 'type_poste',
728 'type_poste__famille_emploi',
729 'vacant',
730 )
731 list_display_links = ('_nom',)
732 fieldsets = AUFMetadataAdminMixin.fieldsets + (
733 (None, {'fields': (
734 ('nom', 'nom_feminin'),
735 'implantation',
736 'type_poste',
737 'service',
738 'responsable',
739 )}
740 ),
741 ('Contrat', {
742 'fields': ((
743 'regime_travail',
744 'regime_travail_nb_heure_semaine'),
745 )}
746 ),
747 ('Recrutement', {
748 'fields': (('local', 'expatrie', 'mise_a_disposition', 'appel'),)}
749 ),
750 ('Rémunération', {
751 'fields': (('classement_min',
752 'valeur_point_min',
753 'devise_min',
754 'salaire_min',
755 'indemn_min',
756 'autre_min',),
757 ('classement_max',
758 'valeur_point_max',
759 'devise_max',
760 'salaire_max',
761 'indemn_max',
762 'autre_max',),
763 )}),
764 ('Comparatifs de rémunération', {
765 'fields': ('devise_comparaison',
766 ('comp_locale_min', 'comp_locale_max'),
767 ('comp_universite_min', 'comp_universite_max'),
768 ('comp_fonctionpub_min', 'comp_fonctionpub_max'),
769 ('comp_ong_min', 'comp_ong_max'),
770 ('comp_autre_min', 'comp_autre_max'))}
771 ),
772 ('Justification', {
773 'fields': ('justification',)}
774 ),
775 ('Autres Méta-données', {
776 'fields': ('date_debut', 'date_fin')}
777 ),
778 )
779
780 inlines = (PosteFinancementInline,
781 PostePieceInline,
782 DossierROInline,
783 PosteComparaisonInline,
784 PosteCommentaireInline, )
785
786 def lookup_allowed(self, key, value):
787 if key in (
788 'date_debut__gte',
789 'date_debut__isnull',
790 'date_fin__lte',
791 'date_fin__isnull',
792 'implantation__region__id__exact',
793 'implantation__id__exact',
794 'type_poste__id__exact',
795 'type_poste__famille_emploi__id__exact',
796 'service__id__exact',
797 'service__isnull',
798 'vacant__exact',
799 'vacant__isnull',
800 ):
801 return True
802
803 def _apercu(self, poste):
804 view_link = u"""<a onclick="return showAddAnotherPopup(this);"
805 title="Aperçu du poste"
806 href='%s'>
807 <img src="%simg/loupe.png" />
808 </a>""" % \
809 (reverse('poste_apercu', args=(poste.id,)),
810 settings.STATIC_URL,)
811 return view_link
812 _apercu.allow_tags = True
813 _apercu.short_description = ''
814
815 def _dae(self, poste):
816 apercu_link = ""
817 if dae.ImportPoste.objects.filter(rh=poste).exists():
818 dae_id = dae.ImportPoste.objects.get(rh=poste).dae_id
819 apercu_link = u"""<a title="Aperçu du dossier"
820 onclick="return showAddAnotherPopup(this);"
821 href='%s'>
822 <img src="%simg/loupe.png" />
823 </a>""" % \
824 (reverse('poste_consulter', args=("dae-%s" % dae_id,)),
825 settings.STATIC_URL,
826 )
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')
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 changelist_view(self, request, extra_context=None):
1019 if not request.GET.has_key('status__exact'):
1020 q = request.GET.copy()
1021 q['archive__exact'] = '0'
1022 request.GET = q
1023 request.META['QUERY_STRING'] = request.GET.urlencode()
1024 return super(ServiceProxyAdmin,self).changelist_view(request,
1025 extra_context=extra_context)
1026
1027 def _organigramme(self, obj):
1028 return """<a href="%s"><strong>Organigramme</strong></a>""" % \
1029 (reverse('rho_service', args=(obj.id,)))
1030 _organigramme.allow_tags = True
1031 _organigramme.short_description = "Organigramme"
1032
1033
1034 class StatutAdmin(AUFMetadataAdminMixin, admin.ModelAdmin):
1035 list_display = ('code', 'nom', '_date_modification', 'user_modification', )
1036 fieldsets = AUFMetadataAdminMixin.fieldsets + (
1037 (None, {
1038 'fields': ('code', 'nom', ),
1039 }),
1040 )
1041
1042 def _date_modification(self, obj):
1043 return date(obj.date_modification) \
1044 if obj.date_modification is not None else "(aucune)"
1045 _date_modification.short_description = u'date modification'
1046 _date_modification.admin_order_field = 'date_modification'
1047
1048
1049 class TauxChangeAdmin(admin.ModelAdmin):
1050 list_display = (
1051 'taux',
1052 'devise',
1053 'annee',
1054 '_date_modification',
1055 'user_modification',
1056 )
1057 list_filter = ('devise', )
1058 fieldsets = AUFMetadataAdminMixin.fieldsets + (
1059 (None, {
1060 'fields': ('taux', 'devise', 'annee', ),
1061 }),
1062 )
1063
1064 def _date_modification(self, obj):
1065 return date(obj.date_modification) \
1066 if obj.date_modification is not None else "(aucune)"
1067 _date_modification.short_description = u'date modification'
1068 _date_modification.admin_order_field = 'date_modification'
1069
1070
1071 class TypeContratAdmin(admin.ModelAdmin):
1072 list_display = (
1073 'nom',
1074 'nom_long',
1075 '_date_modification',
1076 'user_modification',
1077 )
1078 fieldsets = AUFMetadataAdminMixin.fieldsets + (
1079 (None, {
1080 'fields': ('nom', 'nom_long', ),
1081 }),
1082 )
1083
1084 def _date_modification(self, obj):
1085 return date(obj.date_modification) \
1086 if obj.date_modification is not None else "(aucune)"
1087 _date_modification.short_description = u'date modification'
1088 _date_modification.admin_order_field = 'date_modification'
1089
1090
1091 class TypePosteAdmin(AUFMetadataAdminMixin, admin.ModelAdmin):
1092 search_fields = ('nom', 'nom_feminin', )
1093 list_display = (
1094 'nom',
1095 'famille_emploi',
1096 '_date_modification',
1097 'user_modification',
1098 )
1099 list_filter = ('famille_emploi', )
1100 fieldsets = AUFMetadataAdminMixin.fieldsets + (
1101 (None, {
1102 'fields': (
1103 'nom',
1104 'nom_feminin',
1105 'is_responsable',
1106 'famille_emploi',
1107 )}
1108 ),
1109 )
1110
1111 def _date_modification(self, obj):
1112 return date(obj.date_modification) \
1113 if obj.date_modification is not None else "(aucune)"
1114 _date_modification.short_description = u'date modification'
1115 _date_modification.admin_order_field = 'date_modification'
1116
1117
1118 class TypeRemunerationAdmin(AUFMetadataAdminMixin, admin.ModelAdmin, ArchiveMixin):
1119 list_display = (
1120 'nom',
1121 'type_paiement',
1122 'nature_remuneration',
1123 '_archive',
1124 '_date_modification',
1125 'user_modification',)
1126 list_filter = ('archive', )
1127 fieldsets = AUFMetadataAdminMixin.fieldsets + (
1128 (None, {'fields': ('nom', 'type_paiement', 'nature_remuneration',
1129 'archive')}),
1130 )
1131
1132 def _date_modification(self, obj):
1133 return date(obj.date_modification) \
1134 if obj.date_modification is not None else "(aucune)"
1135 _date_modification.short_description = u'date modification'
1136 _date_modification.admin_order_field = 'date_modification'
1137
1138
1139 class TypeRevalorisationAdmin(AUFMetadataAdminMixin, admin.ModelAdmin):
1140 list_display = ('nom', '_date_modification', 'user_modification', )
1141 fieldsets = AUFMetadataAdminMixin.fieldsets + (
1142 (None, {'fields': ('nom', )}),
1143 )
1144
1145 def _date_modification(self, obj):
1146 return date(obj.date_modification) \
1147 if obj.date_modification is not None else "(aucune)"
1148 _date_modification.short_description = u'date modification'
1149 _date_modification.admin_order_field = 'date_modification'
1150
1151
1152 class ValeurPointAdmin(AUFMetadataAdminMixin, admin.ModelAdmin):
1153 list_display = (
1154 '_devise_code',
1155 '_devise_nom',
1156 'annee',
1157 'implantation',
1158 'valeur',
1159 '_date_modification',
1160 'user_modification',
1161 )
1162 list_filter = ('annee', 'devise', 'implantation__region', )
1163 fieldsets = AUFMetadataAdminMixin.fieldsets + (
1164 (None, {'fields': ('valeur', 'devise', 'implantation', 'annee', )}),
1165 )
1166
1167 def _date_modification(self, obj):
1168 return date(obj.date_modification) \
1169 if obj.date_modification is not None else "(aucune)"
1170 _date_modification.short_description = u'date modification'
1171 _date_modification.admin_order_field = 'date_modification'
1172
1173 def _devise_code(self, obj):
1174 return obj.devise.code
1175 _devise_code.short_description = "Code de la devise"
1176
1177 def _devise_nom(self, obj):
1178 return obj.devise.nom
1179 _devise_nom.short_description = "Nom de la devise"
1180
1181 class ImplantationProxyAdmin(admin.ModelAdmin):
1182 list_display = ('nom', '_organigramme')
1183 actions = None
1184
1185 def __init__(self, *args, **kwargs):
1186 super(ImplantationProxyAdmin, self).__init__(*args, **kwargs)
1187 self.list_display_links = (None, )
1188
1189 def has_add_permission(self, obj):
1190 return False
1191
1192 def has_change_permission(self, request, obj=None):
1193 return in_drh_or_admin(request.user)
1194
1195 def _organigramme(self, obj):
1196 return """<a href="%s"><strong>Organigramme</strong></a>""" % (reverse('rho_implantation', args=(obj.id,)))
1197 _organigramme.allow_tags = True
1198 _organigramme.short_description = "Organigramme"
1199
1200 class RegionProxyAdmin(admin.ModelAdmin):
1201 list_display = ('nom', '_organigramme')
1202 actions = None
1203
1204 def __init__(self, *args, **kwargs):
1205 super(RegionProxyAdmin, self).__init__(*args, **kwargs)
1206 self.list_display_links = (None, )
1207
1208 def has_add_permission(self, obj):
1209 return False
1210
1211 def has_change_permission(self, request, obj=None):
1212 return in_drh_or_admin(request.user)
1213
1214 def _organigramme(self, obj):
1215 return """<a href="%s"><strong>Organigramme</strong></a>""" % (reverse('rho_region', args=(obj.id,)))
1216 _organigramme.allow_tags = True
1217 _organigramme.short_description = "Organigramme"
1218
1219
1220
1221
1222 admin.site.register(rh.Classement, ClassementAdmin)
1223 admin.site.register(rh.Devise, DeviseAdmin)
1224 admin.site.register(rh.Dossier, DossierAdmin)
1225 admin.site.register(EmployeProxy, EmployeProxyAdmin)
1226 admin.site.register(ServiceProxy, ServiceProxyAdmin)
1227 admin.site.register(rh.Employe, EmployeAdmin)
1228 admin.site.register(rh.FamilleEmploi, FamilleEmploiAdmin)
1229 admin.site.register(rh.OrganismeBstg, OrganismeBstgAdmin)
1230 admin.site.register(rh.Poste, PosteAdmin)
1231 admin.site.register(rh.ResponsableImplantationProxy, ResponsableImplantationAdmin)
1232 admin.site.register(rh.Service, ServiceAdmin)
1233 admin.site.register(rh.Statut, StatutAdmin)
1234 admin.site.register(rh.TauxChange, TauxChangeAdmin)
1235 admin.site.register(rh.TypeContrat, TypeContratAdmin)
1236 admin.site.register(rh.TypePoste, TypePosteAdmin)
1237 admin.site.register(rh.TypeRemuneration, TypeRemunerationAdmin)
1238 admin.site.register(rh.TypeRevalorisation, TypeRevalorisationAdmin)
1239 admin.site.register(rh.ValeurPoint, ValeurPointAdmin)
1240 admin.site.register(ImplantationProxy, ImplantationProxyAdmin)
1241 admin.site.register(RegionProxy, RegionProxyAdmin)