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