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