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