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