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