3be2715e38bce8c9e490a125f8108e196725a142
[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_entree',
509 '_date_modification',
510 'user_modification',
511 )
512 list_display_links = ('_nom',)
513 list_filter = (
514 'rh_dossiers__poste__implantation__region',
515 'rh_dossiers__poste__implantation',
516 'nb_postes',
517 )
518 inlines = (AyantDroitInline,
519 DossierROInline,
520 EmployePieceInline,
521 EmployeCommentaireInline)
522 fieldsets = AUFMetadataAdminMixin.fieldsets + (
523 ('Identification', {
524 'fields': (
525 ('nom', 'prenom'),
526 ('nom_affichage', 'genre'),
527 'nationalite',
528 'date_naissance',
529 )}
530 ),
531 ('Informations personnelles', {
532 'fields': ('situation_famille', 'date_entree', )}
533 ),
534 ('Coordonnées personnelles', {
535 'fields': (
536 ('tel_domicile', 'tel_cellulaire'),
537 ('adresse', 'ville'),
538 ('code_postal', 'province'),
539 'pays',
540 'courriel_perso'
541 )}
542 ),
543 )
544
545 def _apercu(self, obj):
546 return u"""<a title="Aperçu de l'employé"
547 onclick="return showAddAnotherPopup(this);"
548 href='%s'>
549 <img src="%simg/loupe.png" />
550 </a>""" % \
551 (reverse('employe_apercu', args=(obj.id,)), settings.STATIC_URL)
552 _apercu.allow_tags = True
553 _apercu.short_description = u""
554
555 def _nom(self, obj):
556 edit_link = reverse('admin:rh_employe_change', args=(obj.id,))
557 return u"""<a href='%s'><strong>%s</strong></a>""" % \
558 (edit_link, "%s %s" % (obj.nom.upper(), obj.prenom))
559 _nom.allow_tags = True
560 _nom.short_description = u"Employé"
561 _nom.admin_order_field = "nom"
562
563 def _id(self, obj):
564 return obj.id
565 _id.short_description = u"#"
566 _id.admin_order_field = "id"
567
568 def _date_modification(self, obj):
569 return date(obj.date_modification) \
570 if obj.date_modification is not None else "(aucune)"
571 _date_modification.short_description = u'date modification'
572 _date_modification.admin_order_field = 'date_modification'
573
574 def _dossiers_postes(self, obj):
575 l = []
576 for d in obj.rh_dossiers.all().order_by('-date_debut'):
577 dossier = u"""<a title="Aperçu du dossier"
578 href="%s"
579 onclick="return showAddAnotherPopup(this);"
580 title="Aperçu du dossier">
581 <img src="%simg/loupe.png" />
582 </a>
583 <a href="%s">Dossier</a>
584 &nbsp;""" % \
585 (reverse('dossier_apercu', args=(d.id,)),
586 settings.STATIC_URL,
587 reverse('admin:rh_dossier_change', args=(d.id,)))
588
589 poste = u"""<a title="Aperçu du poste"
590 href="%s"
591 onclick="return showAddAnotherPopup(this);"
592 title="Aperçu du poste">
593 <img src="%simg/loupe.png" />
594 </a>
595 <a href="%s">Poste</a>
596 &nbsp;""" % \
597 (reverse('poste_apercu', args=(d.poste.id,)),
598 settings.STATIC_URL,
599 reverse('admin:rh_poste_change', args=(d.poste.id,)))
600 link = u"""<li>%s %s - %s : [%s] %s</li>""" % \
601 (dossier, poste,
602 d.date_debut.year,
603 d.poste.id,
604 d.poste.nom,
605 )
606
607 # Dossier terminé en gris non cliquable
608 if d.date_fin is not None and d.date_fin < datetime.date.today():
609 link = u"""<li style="color: grey">%s : [%s] %s</li>""" % \
610 (d.date_debut.year,
611 d.poste.id,
612 d.poste.nom,
613 )
614
615 l.append(link)
616 return "<ul>%s</ul>" % "\n".join(l)
617 _dossiers_postes.allow_tags = True
618 _dossiers_postes.short_description = u"Dossiers et postes"
619
620 def queryset(self, request):
621 qs = super(EmployeAdmin, self).queryset(request)
622 return qs.select_related(depth=1).order_by('nom')
623
624 def save_formset(self, request, form, formset, change):
625 instances = formset.save(commit=False)
626 for instance in instances:
627 if instance.__class__ == rh.EmployeCommentaire:
628 instance.owner = request.user
629 instance.date_creation = datetime.datetime.now()
630 instance.save()
631
632
633 class EmployeProxyAdmin(EmployeAdmin):
634 list_display = ('_id', '_apercu', '_nom', '_organigramme')
635 actions = None
636
637 def __init__(self, *args, **kwargs):
638 super(EmployeProxyAdmin, self).__init__(*args, **kwargs)
639 self.list_display_links = (None, )
640
641 def has_add_permission(self, obj):
642 return False
643
644 def _organigramme(self, obj):
645 l = []
646 for d in rh.Dossier.objects.filter(
647 Q(date_fin__gt=datetime.date.today()) | Q(date_fin=None),
648 Q(date_debut__lt=datetime.date.today()) | Q(date_debut=None),
649 employe=obj.id
650 ):
651 organigramme = \
652 u'Organigramme, niveau: ' \
653 u'<input type="text" id="level_%s" ' \
654 u'style="width:30px;height:15px;" /> ' \
655 u'<input type="button" value="Générer" ' \
656 u"""onclick="window.location='%s' + """ \
657 u"""document.getElementById('level_%s').value" />""" % (
658 d.poste.id,
659 reverse('rho_employe_sans_niveau', args=(d.poste.id,)),
660 d.poste.id
661 )
662 link = u"""<li>%s - [%s] %s : %s</li>""" % (
663 d.date_debut.year,
664 d.poste.id,
665 d.poste.nom,
666 organigramme
667 )
668 l.append(link)
669 return "<ul>%s</ul>" % "\n".join(l)
670
671 _organigramme.allow_tags = True
672 _organigramme.short_description = "Organigramme"
673
674
675 class EmployeCommentaireAdmin(admin.ModelAdmin):
676 pass
677
678
679 class EmployePieceAdmin(admin.ModelAdmin):
680 pass
681
682
683 class CategorieEmploiAdmin(AUFMetadataAdminMixin, admin.ModelAdmin):
684 list_display = ('nom', '_date_modification', 'user_modification', )
685 inlines = (TypePosteInline,)
686 fieldsets = AUFMetadataAdminMixin.fieldsets + (
687 (None, {'fields': ('nom', )}),)
688
689 def _date_modification(self, obj):
690 return date(obj.date_modification) \
691 if obj.date_modification is not None else "(aucune)"
692 _date_modification.short_description = u'date modification'
693 _date_modification.admin_order_field = 'date_modification'
694
695
696 class OrganismeBstgAdmin(AUFMetadataAdminMixin, admin.ModelAdmin):
697 search_fields = ('nom',)
698 list_display = (
699 'nom',
700 'type',
701 'pays',
702 '_date_modification',
703 'user_modification',
704 )
705 list_filter = ('type', )
706 inlines = (DossierROInline,)
707 fieldsets = AUFMetadataAdminMixin.fieldsets + (
708 (None, {'fields': ('nom', 'type', 'pays',)}),
709 )
710
711 def _date_modification(self, obj):
712 return date(obj.date_modification) \
713 if obj.date_modification is not None else "(aucune)"
714 _date_modification.short_description = u'date modification'
715 _date_modification.admin_order_field = 'date_modification'
716
717
718 class PosteAdmin(DateRangeMixin, AUFMetadataAdminMixin, \
719 ProtectRegionMixin, admin.ModelAdmin, AjaxSelect,):
720 form = make_ajax_form(rh.Poste, {
721 'implantation': 'implantations',
722 'type_poste': 'typepostes',
723 'responsable': 'postes',
724 'valeur_point_min': 'valeurpoints',
725 'valeur_point_max': 'valeurpoints',
726 })
727 alphabet_filter = 'nom'
728 search_fields = (
729 'id',
730 'nom',
731 'implantation__nom',
732 'implantation__region__code',
733 'implantation__region__nom',
734 'rh_dossiers__employe__nom',
735 'rh_dossiers__employe__prenom',
736 )
737 list_display = (
738 '_id',
739 '_apercu',
740 '_nom',
741 '_occupe_par',
742 '_implantation',
743 '_service',
744 '_responsable',
745 'date_debut',
746 'date_fin',
747 '_date_modification',
748 'user_modification',
749 '_dae',
750 )
751 list_filter = (
752 'implantation__region',
753 'implantation',
754 'service',
755 'type_poste',
756 'type_poste__categorie_emploi',
757 'type_poste__famille_professionnelle',
758 'vacant',
759 )
760 list_display_links = ('_nom',)
761 fieldsets = AUFMetadataAdminMixin.fieldsets + (
762 (None, {'fields': (
763 ('nom', 'nom_feminin'),
764 'implantation',
765 'type_poste',
766 'service',
767 'responsable',
768 )}
769 ),
770 ('Contrat', {
771 'fields': ((
772 'regime_travail',
773 'regime_travail_nb_heure_semaine'),
774 )}
775 ),
776 ('Recrutement', {
777 'fields': (('local', 'expatrie', 'mise_a_disposition', 'appel'),)}
778 ),
779 ('Rémunération', {
780 'fields': (('classement_min',
781 'valeur_point_min',
782 'devise_min',
783 'salaire_min',
784 'indemn_min',
785 'autre_min',),
786 ('classement_max',
787 'valeur_point_max',
788 'devise_max',
789 'salaire_max',
790 'indemn_max',
791 'autre_max',),
792 )}),
793 ('Comparatifs de rémunération', {
794 'fields': ('devise_comparaison',
795 ('comp_locale_min', 'comp_locale_max'),
796 ('comp_universite_min', 'comp_universite_max'),
797 ('comp_fonctionpub_min', 'comp_fonctionpub_max'),
798 ('comp_ong_min', 'comp_ong_max'),
799 ('comp_autre_min', 'comp_autre_max'))}
800 ),
801 ('Justification', {
802 'fields': ('justification',)}
803 ),
804 ('Autres Méta-données', {
805 'fields': ('date_debut', 'date_fin')}
806 ),
807 )
808
809 inlines = (PosteFinancementInline,
810 PostePieceInline,
811 DossierROInline,
812 PosteComparaisonInline,
813 PosteCommentaireInline, )
814
815 def lookup_allowed(self, key, value):
816 return key in (
817 'date_debut__gte', 'date_debut__isnull', 'date_fin__lte',
818 'date_fin__isnull', 'implantation__region__id__exact',
819 'implantation__id__exact', 'type_poste__id__exact',
820 'type_poste__categorie_emploi__id__exact', 'service__id__exact',
821 'service__isnull', 'vacant__exact', 'vacant__isnull',
822 ) or super(PosteAdmin, self).lookup_allowed(key, value)
823
824 def _apercu(self, poste):
825 view_link = u"""<a onclick="return showAddAnotherPopup(this);"
826 title="Aperçu du poste"
827 href='%s'>
828 <img src="%simg/loupe.png" />
829 </a>""" % \
830 (reverse('poste_apercu', args=(poste.id,)),
831 settings.STATIC_URL,)
832 return view_link
833 _apercu.allow_tags = True
834 _apercu.short_description = ''
835
836 def _dae(self, poste):
837 apercu_link = ""
838 postes_dae = poste.postes_dae.all()
839 if len(postes_dae) > 0:
840 poste_dae = postes_dae[0]
841 apercu_link = \
842 u'<a title="Aperçu du dossier" href="%s" ' \
843 u'onclick="return showAddAnotherPopup(this);">' \
844 u'<img src="%simg/loupe.png" /></a>' % (reverse(
845 'poste_consulter', args=("dae-%s" % poste_dae.id,)
846 ), settings.STATIC_URL)
847 return apercu_link
848 _dae.allow_tags = True
849 _dae.short_description = u"DAE"
850
851 def _id(self, obj):
852 return "%s" % obj.id
853 _id.short_description = '#'
854 _id.admin_order_field = 'id'
855
856 def _service(self, obj):
857 if obj.service.supprime:
858 return """<span style="color:red">%s</span>""" % obj.service
859 else:
860 return obj.service
861 _service.short_description = 'Service'
862 _service.allow_tags = True
863
864 def _responsable(self, obj):
865 try:
866 responsable = u"""<a href="%s"
867 onclick="return showAddAnotherPopup(this)">
868 <img src="%simg/loupe.png"
869 title="Aperçu du poste" />
870 </a>
871 <a href="%s">%s</a>
872 <br />""" % \
873 (reverse('poste_apercu', args=(obj.responsable.id,)),
874 settings.STATIC_URL,
875 reverse('admin:rh_poste_change', args=(obj.responsable.id,)),
876 obj.responsable.nom)
877 except:
878 responsable = ''
879
880 try:
881 employe = obj.responsable.rh_dossiers.all()[0]
882 employe_id = obj.responsable.rh_dossiers.all()[0].id
883 employe_html = u"""<br />
884 <a href="%s"
885 onclick="return showAddAnotherPopup(this)">
886 <img src="%simg/loupe.png"
887 title="Aperçu de l'employé">
888 </a>
889 <a href="%s">%s</a>""" % \
890 (reverse('employe_apercu', args=(employe_id,)),
891 settings.STATIC_URL,
892 reverse('admin:rh_employe_change', args=(employe_id,)),
893 employe)
894 except:
895 employe_html = ""
896
897 return "%s %s" % (responsable, employe_html)
898 _responsable.short_description = 'Responsable'
899 _responsable.allow_tags = True
900
901 def _implantation(self, poste):
902 return poste.implantation.nom
903 _implantation.short_description = 'Implantation'
904 _implantation.admin_order_field = 'implantation'
905
906 def _nom(self, poste):
907 return """<a href="%s">%s</a>""" % \
908 (reverse('admin:rh_poste_change', args=(poste.id,)),
909 poste.nom)
910 _nom.allow_tags = True
911 _nom.short_description = u'Poste'
912 _nom.admin_order_field = 'nom'
913
914 def _date_modification(self, obj):
915 return date(obj.date_modification)
916 _date_modification.short_description = u'date modification'
917 _date_modification.admin_order_field = 'date_modification'
918
919 def _occupe_par(self, obj):
920 """Formatte la méthode Poste.occupe_par() pour l'admin"""
921 output = u"Vacant"
922 if obj.date_fin is not None and obj.date_fin < datetime.date.today():
923 return u"s/o"
924 employes = obj.occupe_par()
925 if employes:
926 l = []
927 for e in employes:
928 link = u"""<a href='%s'
929 title='Aperçu de l\'employer'
930 onclick='return showAddAnotherPopup(this)'>
931 <img src='%simg/loupe.png' />
932 </a>
933 <a href='%s'>%s</a>""" % \
934 (reverse('employe_apercu', args=(e.id,)),
935 settings.STATIC_URL,
936 reverse('admin:rh_employe_change', args=(e.id,)),
937 e)
938 l.append(link)
939 output = "\n<br />".join(l)
940 return output
941 _occupe_par.allow_tags = True
942 _occupe_par.short_description = "Occupé par"
943
944 def save_formset(self, request, form, formset, change):
945 instances = formset.save(commit=False)
946 for instance in instances:
947 if instance.__class__ == rh.PosteCommentaire:
948 instance.owner = request.user
949 instance.date_creation = datetime.datetime.now()
950 instance.save()
951 formset.save_m2m()
952
953
954 class PosteCommentaireAdmin(admin.ModelAdmin):
955 pass
956
957
958 class PosteFinancementAdmin(admin.ModelAdmin):
959 pass
960
961
962 class PostePieceAdmin(admin.ModelAdmin):
963 fk_name = 'poste'
964
965
966 class RemunerationAdmin(admin.ModelAdmin):
967 pass
968
969
970 class ResponsableInline(admin.TabularInline):
971 model = rh.ResponsableImplantation
972 extra = 0
973 fk_name = "implantation"
974
975
976 class ResponsableImplantationAdmin(admin.ModelAdmin):
977 actions = None
978 list_filter = ('region', 'statut', )
979 list_display = ('_region', '_nom', 'statut', '_responsable', )
980 readonly_fields = ('nom', )
981 fields = ('nom', )
982 inlines = (ResponsableInline, )
983
984 def _region(self, obj):
985 return obj.region.code
986 _region.short_description = u"Région"
987 _region.admin_order_field = 'region__code'
988
989 def _nom(self, obj):
990 return obj.nom
991 _nom.short_description = u"Implantation"
992 _nom.admin_order_field = 'nom'
993
994 def _responsable(self, obj):
995 try:
996 employe = obj.responsable.employe
997 dossiers = employe.dossiers_encours()
998 if len(dossiers) == 0:
999 return u"<span style='color: red;'>%s %s </span>" % (
1000 employe, u"sans dossier actif")
1001 else:
1002 return employe
1003 except Exception:
1004 if obj.statut in (1, 2): # ouverte, ouverture imminente
1005 css = "style='color: red;'"
1006 else:
1007 css = ""
1008 return u"<span %s>Pas de responsable</span>" % css
1009 _responsable.allow_tags = True
1010 _responsable.short_description = u"Responsable"
1011
1012 def has_add_permission(self, request=None):
1013 return False
1014
1015 def has_change_permission(self, request, obj=None):
1016 return in_drh_or_admin(request.user)
1017
1018 def has_delete_permission(self, request, obj=None):
1019 return False
1020
1021
1022 class ServiceAdmin(AUFMetadataAdminMixin, admin.ModelAdmin, ArchiveMixin):
1023 list_display = (
1024 'nom',
1025 '_archive',
1026 '_date_modification',
1027 'user_modification',
1028 )
1029 list_filter = ('archive', )
1030 fieldsets = AUFMetadataAdminMixin.fieldsets + (
1031 (None, {
1032 'fields': ('nom', 'archive', ),
1033 }),
1034 )
1035
1036 def _date_modification(self, obj):
1037 return date(obj.date_modification) \
1038 if obj.date_modification is not None else "(aucune)"
1039 _date_modification.short_description = u'date modification'
1040 _date_modification.admin_order_field = 'date_modification'
1041
1042
1043 class ServiceProxyAdmin(ServiceAdmin):
1044 list_display = ('nom', '_organigramme', '_archive', )
1045 actions = None
1046
1047 def __init__(self, *args, **kwargs):
1048 super(ServiceProxyAdmin, self).__init__(*args, **kwargs)
1049 self.list_display_links = (None, )
1050
1051 def queryset(self, request):
1052 return super(ServiceProxyAdmin, self).queryset(request) \
1053 .annotate(num_postes=Count('rh_postes')) \
1054 .filter(num_postes__gt=0)
1055
1056 def has_add_permission(self, obj):
1057 return False
1058
1059 def has_change_permission(self, request, obj=None):
1060 return in_drh_or_admin(request.user)
1061
1062 def _organigramme(self, obj):
1063 return """<a href="%s"><strong>Organigramme</strong></a>""" % \
1064 (reverse('rho_service', args=(obj.id,)))
1065 _organigramme.allow_tags = True
1066 _organigramme.short_description = "Organigramme"
1067
1068
1069 class StatutAdmin(AUFMetadataAdminMixin, admin.ModelAdmin):
1070 list_display = ('code', 'nom', '_date_modification', 'user_modification', )
1071 fieldsets = AUFMetadataAdminMixin.fieldsets + (
1072 (None, {
1073 'fields': ('code', 'nom', ),
1074 }),
1075 )
1076
1077 def _date_modification(self, obj):
1078 return date(obj.date_modification) \
1079 if obj.date_modification is not None else "(aucune)"
1080 _date_modification.short_description = u'date modification'
1081 _date_modification.admin_order_field = 'date_modification'
1082
1083
1084 class TauxChangeAdmin(admin.ModelAdmin):
1085 list_display = (
1086 'taux',
1087 'devise',
1088 'annee',
1089 '_date_modification',
1090 'user_modification',
1091 )
1092 list_filter = ('devise', )
1093 fieldsets = AUFMetadataAdminMixin.fieldsets + (
1094 (None, {
1095 'fields': ('taux', 'devise', 'annee', ),
1096 }),
1097 )
1098
1099 def _date_modification(self, obj):
1100 return date(obj.date_modification) \
1101 if obj.date_modification is not None else "(aucune)"
1102 _date_modification.short_description = u'date modification'
1103 _date_modification.admin_order_field = 'date_modification'
1104
1105
1106 class TypeContratAdmin(admin.ModelAdmin):
1107 list_display = (
1108 'nom',
1109 'nom_long',
1110 '_date_modification',
1111 'user_modification',
1112 )
1113 fieldsets = AUFMetadataAdminMixin.fieldsets + (
1114 (None, {
1115 'fields': ('nom', 'nom_long', ),
1116 }),
1117 )
1118
1119 def _date_modification(self, obj):
1120 return date(obj.date_modification) \
1121 if obj.date_modification is not None else "(aucune)"
1122 _date_modification.short_description = u'date modification'
1123 _date_modification.admin_order_field = 'date_modification'
1124
1125
1126 class TypePosteAdmin(AUFMetadataAdminMixin, admin.ModelAdmin):
1127 search_fields = ('nom', 'nom_feminin', )
1128 list_display = (
1129 'nom',
1130 'categorie_emploi',
1131 '_date_modification',
1132 'user_modification',
1133 )
1134 list_filter = ('categorie_emploi', 'famille_professionnelle')
1135 fieldsets = AUFMetadataAdminMixin.fieldsets + (
1136 (None, {
1137 'fields': (
1138 'nom',
1139 'nom_feminin',
1140 'is_responsable',
1141 'categorie_emploi',
1142 'famille_professionnelle',
1143 )}
1144 ),
1145 )
1146
1147 def _date_modification(self, obj):
1148 return date(obj.date_modification) \
1149 if obj.date_modification is not None else "(aucune)"
1150 _date_modification.short_description = u'date modification'
1151 _date_modification.admin_order_field = 'date_modification'
1152
1153
1154 class TypeRemunerationAdmin(AUFMetadataAdminMixin, admin.ModelAdmin,
1155 ArchiveMixin):
1156 list_display = (
1157 'nom',
1158 'type_paiement',
1159 'nature_remuneration',
1160 '_archive',
1161 '_date_modification',
1162 'user_modification',)
1163 list_filter = ('archive', )
1164 fieldsets = AUFMetadataAdminMixin.fieldsets + (
1165 (None, {'fields': ('nom', 'type_paiement', 'nature_remuneration',
1166 'archive')}),
1167 )
1168
1169 def _date_modification(self, obj):
1170 return date(obj.date_modification) \
1171 if obj.date_modification is not None else "(aucune)"
1172 _date_modification.short_description = u'date modification'
1173 _date_modification.admin_order_field = 'date_modification'
1174
1175
1176 class TypeRevalorisationAdmin(AUFMetadataAdminMixin, admin.ModelAdmin):
1177 list_display = ('nom', '_date_modification', 'user_modification', )
1178 fieldsets = AUFMetadataAdminMixin.fieldsets + (
1179 (None, {'fields': ('nom', )}),
1180 )
1181
1182 def _date_modification(self, obj):
1183 return date(obj.date_modification) \
1184 if obj.date_modification is not None else "(aucune)"
1185 _date_modification.short_description = u'date modification'
1186 _date_modification.admin_order_field = 'date_modification'
1187
1188
1189 class ValeurPointAdmin(AUFMetadataAdminMixin, admin.ModelAdmin):
1190 list_display = (
1191 '_devise_code',
1192 '_devise_nom',
1193 'annee',
1194 'implantation',
1195 'valeur',
1196 '_date_modification',
1197 'user_modification',
1198 )
1199 list_filter = ('annee', 'devise', 'implantation__region', )
1200 fieldsets = AUFMetadataAdminMixin.fieldsets + (
1201 (None, {'fields': ('valeur', 'devise', 'implantation', 'annee', )}),
1202 )
1203
1204 def _date_modification(self, obj):
1205 return date(obj.date_modification) \
1206 if obj.date_modification is not None else "(aucune)"
1207 _date_modification.short_description = u'date modification'
1208 _date_modification.admin_order_field = 'date_modification'
1209
1210 def _devise_code(self, obj):
1211 return obj.devise.code
1212 _devise_code.short_description = "Code de la devise"
1213
1214 def _devise_nom(self, obj):
1215 return obj.devise.nom
1216 _devise_nom.short_description = "Nom de la devise"
1217
1218
1219 class ImplantationProxyAdmin(admin.ModelAdmin):
1220 list_display = ('nom', '_organigramme')
1221 actions = None
1222
1223 def __init__(self, *args, **kwargs):
1224 super(ImplantationProxyAdmin, self).__init__(*args, **kwargs)
1225 self.list_display_links = (None, )
1226
1227 def has_add_permission(self, obj):
1228 return False
1229
1230 def has_change_permission(self, request, obj=None):
1231 return in_drh_or_admin(request.user)
1232
1233 def _organigramme(self, obj):
1234 return '<a href="%s"><strong>Organigramme</strong></a>' % (
1235 reverse('rho_implantation', args=(obj.id,))
1236 )
1237 _organigramme.allow_tags = True
1238 _organigramme.short_description = "Organigramme"
1239
1240
1241 class RegionProxyAdmin(admin.ModelAdmin):
1242 list_display = ('nom', '_organigramme')
1243 actions = None
1244
1245 def __init__(self, *args, **kwargs):
1246 super(RegionProxyAdmin, self).__init__(*args, **kwargs)
1247 self.list_display_links = (None, )
1248
1249 def has_add_permission(self, obj):
1250 return False
1251
1252 def has_change_permission(self, request, obj=None):
1253 return in_drh_or_admin(request.user)
1254
1255 def _organigramme(self, obj):
1256 return """<a href="%s"><strong>Organigramme</strong></a>""" % (
1257 reverse('rho_region', args=(obj.id,))
1258 )
1259 _organigramme.allow_tags = True
1260 _organigramme.short_description = "Organigramme"
1261
1262
1263 admin.site.register(rh.Classement, ClassementAdmin)
1264 admin.site.register(rh.Devise, DeviseAdmin)
1265 admin.site.register(rh.Dossier, DossierAdmin)
1266 admin.site.register(EmployeProxy, EmployeProxyAdmin)
1267 admin.site.register(ServiceProxy, ServiceProxyAdmin)
1268 admin.site.register(rh.Employe, EmployeAdmin)
1269 admin.site.register(rh.CategorieEmploi, CategorieEmploiAdmin)
1270 admin.site.register(rh.FamilleProfessionnelle)
1271 admin.site.register(rh.OrganismeBstg, OrganismeBstgAdmin)
1272 admin.site.register(rh.Poste, PosteAdmin)
1273 admin.site.register(
1274 rh.ResponsableImplantationProxy, ResponsableImplantationAdmin
1275 )
1276 admin.site.register(rh.Service, ServiceAdmin)
1277 admin.site.register(rh.Statut, StatutAdmin)
1278 admin.site.register(rh.TauxChange, TauxChangeAdmin)
1279 admin.site.register(rh.TypeContrat, TypeContratAdmin)
1280 admin.site.register(rh.TypePoste, TypePosteAdmin)
1281 admin.site.register(rh.TypeRemuneration, TypeRemunerationAdmin)
1282 admin.site.register(rh.TypeRevalorisation, TypeRevalorisationAdmin)
1283 admin.site.register(rh.ValeurPoint, ValeurPointAdmin)
1284 admin.site.register(ImplantationProxy, ImplantationProxyAdmin)
1285 admin.site.register(RegionProxy, RegionProxyAdmin)