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