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