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