[#3178] Ajouté des champs à la recherche textuelle des employés
[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 _nom(self, poste):
901 return """<a href="%s">%s</a>""" % \
902 (reverse('admin:rh_poste_change', args=(poste.id,)),
903 poste.nom)
904 _nom.allow_tags = True
905 _nom.short_description = u'Nom'
906 _nom.admin_order_field = 'nom'
907
908 def _date_modification(self, obj):
909 return date(obj.date_modification)
910 _date_modification.short_description = u'date modification'
911 _date_modification.admin_order_field = 'date_modification'
912
913 def _occupe_par(self, obj):
914 """Formatte la méthode Poste.occupe_par() pour l'admin"""
915 output = u"Vacant"
916 if obj.date_fin is not None and obj.date_fin < datetime.date.today():
917 return u"s/o"
918 employes = obj.occupe_par()
919 if employes:
920 l = []
921 for e in employes:
922 link = u"""<a href='%s'
923 title='Aperçu de l\'employer'
924 onclick='return showAddAnotherPopup(this)'>
925 <img src='%simg/loupe.png' />
926 </a>
927 <a href='%s'>%s</a>""" % \
928 (reverse('employe_apercu', args=(e.id,)),
929 settings.STATIC_URL,
930 reverse('admin:rh_employe_change', args=(e.id,)),
931 e)
932 l.append(link)
933 output = "\n<br />".join(l)
934 return output
935 _occupe_par.allow_tags = True
936 _occupe_par.short_description = "Occupé par"
937
938 def save_formset(self, request, form, formset, change):
939 instances = formset.save(commit=False)
940 for instance in instances:
941 if instance.__class__ == rh.PosteCommentaire:
942 instance.owner = request.user
943 instance.date_creation = datetime.datetime.now()
944 instance.save()
945 formset.save_m2m()
946
947
948 class PosteCommentaireAdmin(admin.ModelAdmin):
949 pass
950
951
952 class PosteFinancementAdmin(admin.ModelAdmin):
953 pass
954
955
956 class PostePieceAdmin(admin.ModelAdmin):
957 fk_name = 'poste'
958
959
960 class RemunerationAdmin(admin.ModelAdmin):
961 pass
962
963
964 class ResponsableInline(admin.TabularInline):
965 model = rh.ResponsableImplantation
966 extra = 0
967 fk_name = "implantation"
968
969
970 class ResponsableImplantationAdmin(admin.ModelAdmin):
971 actions = None
972 list_filter = ('region', 'statut', )
973 list_display = ('nom', 'statut', '_responsable', )
974 readonly_fields = ('nom', )
975 fields = ('nom', )
976 inlines = (ResponsableInline, )
977
978 def _responsable(self, obj):
979 try:
980 employe = obj.responsable.employe
981 dossiers = employe.dossiers_encours()
982 if len(dossiers) == 0:
983 return u"<span style='color: red;'>%s %s </span>" % (
984 employe, u"sans dossier actif")
985 else:
986 return employe
987 except Exception:
988 if obj.statut in (1, 2): # ouverte, ouverture imminente
989 css = "style='color: red;'"
990 else:
991 css = ""
992 return u"<span %s>Pas de responsable</span>" % css
993 _responsable.allow_tags = True
994 _responsable.short_description = u"Responsable"
995
996 def has_add_permission(self, request=None):
997 return False
998
999 def has_change_permission(self, request, obj=None):
1000 return in_drh_or_admin(request.user)
1001
1002 def has_delete_permission(self, request, obj=None):
1003 return False
1004
1005
1006 class ServiceAdmin(AUFMetadataAdminMixin, admin.ModelAdmin, ArchiveMixin):
1007 list_display = (
1008 'nom',
1009 '_archive',
1010 '_date_modification',
1011 'user_modification',
1012 )
1013 list_filter = ('archive', )
1014 fieldsets = AUFMetadataAdminMixin.fieldsets + (
1015 (None, {
1016 'fields': ('nom', 'archive', ),
1017 }),
1018 )
1019
1020 def _date_modification(self, obj):
1021 return date(obj.date_modification) \
1022 if obj.date_modification is not None else "(aucune)"
1023 _date_modification.short_description = u'date modification'
1024 _date_modification.admin_order_field = 'date_modification'
1025
1026
1027 class ServiceProxyAdmin(ServiceAdmin):
1028 list_display = ('nom', '_organigramme', '_archive', )
1029 actions = None
1030
1031 def __init__(self, *args, **kwargs):
1032 super(ServiceProxyAdmin, self).__init__(*args, **kwargs)
1033 self.list_display_links = (None, )
1034
1035 def queryset(self, request):
1036 return super(ServiceProxyAdmin, self).queryset(request) \
1037 .annotate(num_postes=Count('rh_postes')) \
1038 .filter(num_postes__gt=0)
1039
1040 def has_add_permission(self, obj):
1041 return False
1042
1043 def has_change_permission(self, request, obj=None):
1044 return in_drh_or_admin(request.user)
1045
1046 def _organigramme(self, obj):
1047 return """<a href="%s"><strong>Organigramme</strong></a>""" % \
1048 (reverse('rho_service', args=(obj.id,)))
1049 _organigramme.allow_tags = True
1050 _organigramme.short_description = "Organigramme"
1051
1052
1053 class StatutAdmin(AUFMetadataAdminMixin, admin.ModelAdmin):
1054 list_display = ('code', 'nom', '_date_modification', 'user_modification', )
1055 fieldsets = AUFMetadataAdminMixin.fieldsets + (
1056 (None, {
1057 'fields': ('code', 'nom', ),
1058 }),
1059 )
1060
1061 def _date_modification(self, obj):
1062 return date(obj.date_modification) \
1063 if obj.date_modification is not None else "(aucune)"
1064 _date_modification.short_description = u'date modification'
1065 _date_modification.admin_order_field = 'date_modification'
1066
1067
1068 class TauxChangeAdmin(admin.ModelAdmin):
1069 list_display = (
1070 'taux',
1071 'devise',
1072 'annee',
1073 '_date_modification',
1074 'user_modification',
1075 )
1076 list_filter = ('devise', )
1077 fieldsets = AUFMetadataAdminMixin.fieldsets + (
1078 (None, {
1079 'fields': ('taux', 'devise', 'annee', ),
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 TypeContratAdmin(admin.ModelAdmin):
1091 list_display = (
1092 'nom',
1093 'nom_long',
1094 '_date_modification',
1095 'user_modification',
1096 )
1097 fieldsets = AUFMetadataAdminMixin.fieldsets + (
1098 (None, {
1099 'fields': ('nom', 'nom_long', ),
1100 }),
1101 )
1102
1103 def _date_modification(self, obj):
1104 return date(obj.date_modification) \
1105 if obj.date_modification is not None else "(aucune)"
1106 _date_modification.short_description = u'date modification'
1107 _date_modification.admin_order_field = 'date_modification'
1108
1109
1110 class TypePosteAdmin(AUFMetadataAdminMixin, admin.ModelAdmin):
1111 search_fields = ('nom', 'nom_feminin', )
1112 list_display = (
1113 'nom',
1114 'categorie_emploi',
1115 '_date_modification',
1116 'user_modification',
1117 )
1118 list_filter = ('categorie_emploi', 'famille_professionnelle')
1119 fieldsets = AUFMetadataAdminMixin.fieldsets + (
1120 (None, {
1121 'fields': (
1122 'nom',
1123 'nom_feminin',
1124 'is_responsable',
1125 'categorie_emploi',
1126 'famille_professionnelle',
1127 )}
1128 ),
1129 )
1130
1131 def _date_modification(self, obj):
1132 return date(obj.date_modification) \
1133 if obj.date_modification is not None else "(aucune)"
1134 _date_modification.short_description = u'date modification'
1135 _date_modification.admin_order_field = 'date_modification'
1136
1137
1138 class TypeRemunerationAdmin(AUFMetadataAdminMixin, admin.ModelAdmin,
1139 ArchiveMixin):
1140 list_display = (
1141 'nom',
1142 'type_paiement',
1143 'nature_remuneration',
1144 '_archive',
1145 '_date_modification',
1146 'user_modification',)
1147 list_filter = ('archive', )
1148 fieldsets = AUFMetadataAdminMixin.fieldsets + (
1149 (None, {'fields': ('nom', 'type_paiement', 'nature_remuneration',
1150 'archive')}),
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 TypeRevalorisationAdmin(AUFMetadataAdminMixin, admin.ModelAdmin):
1161 list_display = ('nom', '_date_modification', 'user_modification', )
1162 fieldsets = AUFMetadataAdminMixin.fieldsets + (
1163 (None, {'fields': ('nom', )}),
1164 )
1165
1166 def _date_modification(self, obj):
1167 return date(obj.date_modification) \
1168 if obj.date_modification is not None else "(aucune)"
1169 _date_modification.short_description = u'date modification'
1170 _date_modification.admin_order_field = 'date_modification'
1171
1172
1173 class ValeurPointAdmin(AUFMetadataAdminMixin, admin.ModelAdmin):
1174 list_display = (
1175 '_devise_code',
1176 '_devise_nom',
1177 'annee',
1178 'implantation',
1179 'valeur',
1180 '_date_modification',
1181 'user_modification',
1182 )
1183 list_filter = ('annee', 'devise', 'implantation__region', )
1184 fieldsets = AUFMetadataAdminMixin.fieldsets + (
1185 (None, {'fields': ('valeur', 'devise', 'implantation', 'annee', )}),
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 def _devise_code(self, obj):
1195 return obj.devise.code
1196 _devise_code.short_description = "Code de la devise"
1197
1198 def _devise_nom(self, obj):
1199 return obj.devise.nom
1200 _devise_nom.short_description = "Nom de la devise"
1201
1202
1203 class ImplantationProxyAdmin(admin.ModelAdmin):
1204 list_display = ('nom', '_organigramme')
1205 actions = None
1206
1207 def __init__(self, *args, **kwargs):
1208 super(ImplantationProxyAdmin, self).__init__(*args, **kwargs)
1209 self.list_display_links = (None, )
1210
1211 def has_add_permission(self, obj):
1212 return False
1213
1214 def has_change_permission(self, request, obj=None):
1215 return in_drh_or_admin(request.user)
1216
1217 def _organigramme(self, obj):
1218 return '<a href="%s"><strong>Organigramme</strong></a>' % (
1219 reverse('rho_implantation', args=(obj.id,))
1220 )
1221 _organigramme.allow_tags = True
1222 _organigramme.short_description = "Organigramme"
1223
1224
1225 class RegionProxyAdmin(admin.ModelAdmin):
1226 list_display = ('nom', '_organigramme')
1227 actions = None
1228
1229 def __init__(self, *args, **kwargs):
1230 super(RegionProxyAdmin, 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_region', args=(obj.id,))
1242 )
1243 _organigramme.allow_tags = True
1244 _organigramme.short_description = "Organigramme"
1245
1246
1247 admin.site.register(rh.Classement, ClassementAdmin)
1248 admin.site.register(rh.Devise, DeviseAdmin)
1249 admin.site.register(rh.Dossier, DossierAdmin)
1250 admin.site.register(EmployeProxy, EmployeProxyAdmin)
1251 admin.site.register(ServiceProxy, ServiceProxyAdmin)
1252 admin.site.register(rh.Employe, EmployeAdmin)
1253 admin.site.register(rh.CategorieEmploi, CategorieEmploiAdmin)
1254 admin.site.register(rh.FamilleProfessionnelle)
1255 admin.site.register(rh.OrganismeBstg, OrganismeBstgAdmin)
1256 admin.site.register(rh.Poste, PosteAdmin)
1257 admin.site.register(
1258 rh.ResponsableImplantationProxy, ResponsableImplantationAdmin
1259 )
1260 admin.site.register(rh.Service, ServiceAdmin)
1261 admin.site.register(rh.Statut, StatutAdmin)
1262 admin.site.register(rh.TauxChange, TauxChangeAdmin)
1263 admin.site.register(rh.TypeContrat, TypeContratAdmin)
1264 admin.site.register(rh.TypePoste, TypePosteAdmin)
1265 admin.site.register(rh.TypeRemuneration, TypeRemunerationAdmin)
1266 admin.site.register(rh.TypeRevalorisation, TypeRevalorisationAdmin)
1267 admin.site.register(rh.ValeurPoint, ValeurPointAdmin)
1268 admin.site.register(ImplantationProxy, ImplantationProxyAdmin)
1269 admin.site.register(RegionProxy, RegionProxyAdmin)