Merge branch 'dev' of ssh://git.auf/auf_rh_dae into dev
[auf_rh_dae.git] / project / rh / admin.py
1 # -*- encoding: utf-8 -*-
2
3 from collections import defaultdict
4 import datetime
5
6 from django.db import models
7 from django import forms
8 from django.core.urlresolvers import reverse
9 from django.contrib import admin
10 from django.contrib.admin.views.main import ChangeList as DjangoChangeList
11 from django.conf import settings
12 from django.db.models import Q
13 from django.template.defaultfilters import date
14 from ajax_select import make_ajax_form
15 from auf.django.metadata.admin import AUFMetadataAdminMixin, AUFMetadataInlineAdminMixin, AUF_METADATA_READONLY_FIELDS
16 from forms import ContratForm, AyantDroitForm, EmployeAdminForm, AjaxSelect
17 from dae.utils import get_employe_from_user
18 from groups import grp_drh
19 import models as rh
20 import filters
21
22 ################################################################################
23 # FILTRAGE PAR DATE
24 ################################################################################
25 class DateRangeMixin(object):
26 """
27 Mixin pour que le model admin utilise le changelist trafiqué permettant de filter par range
28 non strict.
29 Par défaut, le filtrage est configuré sur aujourd'hui, soit les actifs
30 """
31 date_borne_gauche = 'date_debut'
32 date_borne_droite = 'date_fin'
33 def get_changelist(self, request, **kwargs):
34 if request.META.has_key('HTTP_REFERER'):
35 referer = request.META['HTTP_REFERER']
36 referer = "/".join(referer.split('/')[3:])
37 referer = "/%s" % referer.split('?')[0]
38 change_list_view = 'admin:%s_%s_changelist' % (self.model._meta.app_label, self.model.__name__.lower())
39 if referer != reverse(change_list_view):
40 params = request.GET.copy()
41 today = datetime.date.today()
42 params.update({'%s__gte' % self.date_borne_gauche : str(today), '%s__lte' % self.date_borne_droite : str(today) })
43 request.GET = params
44 return ChangeList
45
46 class ChangeList(DjangoChangeList):
47
48 def __init__(self, *args, **kwargs):
49 super(ChangeList, self).__init__(*args, **kwargs)
50
51 def get_query_set(self):
52 old = self.params.copy()
53 date_debut = None
54 date_fin = None
55 for k, v in self.params.items():
56 if 'date_debut' in k:
57 prefix_debut = "".join(k.split('date_debut')[0:-1]) + 'date_debut'
58 date_debut = v
59 del self.params[k]
60 elif 'date_fin' in k:
61 prefix_fin = "".join(k.split('date_fin')[0:-1]) + 'date_fin'
62 date_fin = v
63 del self.params[k]
64 qs = super(ChangeList, self).get_query_set()
65
66 # hack pour spécifier un range
67 if date_fin is None and date_debut is not None:
68 date_fin = '2020-01-01'
69 prefix_fin = prefix_debut.replace('debut', 'fin')
70 if date_debut is None and date_fin is not None:
71 date_debut = '1000-01-01'
72 prefix_debut = prefix_fin.replace('fin', 'debut')
73
74 if date_debut is not None and date_fin is not None:
75 q_left = (Q(**{'%s__isnull' % prefix_debut : True}) | Q(**{'%s__lte' % prefix_debut : date_debut})) & (Q(**{'%s__gte' % prefix_fin : date_debut}) & Q(**{'%s__lte' % prefix_fin : date_fin}))
76 q_right = (Q(**{'%s__isnull' % prefix_fin : True}) | Q(**{'%s__gte' % prefix_fin : date_fin})) & (Q(**{'%s__gte' % prefix_debut : date_debut}) & Q(**{'%s__lte' % prefix_debut : date_fin}))
77 q_both = Q(**{'%s__isnull' % prefix_fin : True}) | Q(**{'%s__lte' % prefix_fin : date_fin}) & (Q(**{'%s__isnull' % prefix_debut : True}) | Q(**{'%s__gte' % prefix_debut : date_debut}))
78 q_non_supprime = Q(**{'%s__exact' % prefix_debut.replace('date_debut', 'supprime') : False})
79 q = (q_left | q_right | q_both) & q_non_supprime
80 qs = qs.filter(q).distinct()
81
82 self.params = old
83 return qs
84
85 ################################################################################
86
87 # Override of the InlineModelAdmin to support the link in the tabular inline
88 class LinkedInline(admin.options.InlineModelAdmin):
89 template = "admin/linked.html"
90 admin_model_path = None
91
92 def __init__(self, *args):
93 super(LinkedInline, self).__init__(*args)
94 if self.admin_model_path is None:
95 self.admin_model_path = self.model.__name__.lower()
96
97
98 class ProtectRegionMixin(object):
99
100 def queryset(self, request):
101 from dae.workflow import grp_drh, grp_correspondants_rh
102 qs = super(ProtectRegionMixin, self).queryset(request)
103
104 if request.user.is_superuser:
105 return qs
106
107 user_groups = request.user.groups.all()
108
109 if grp_drh in user_groups:
110 return qs
111
112 if grp_correspondants_rh in user_groups:
113 employe = get_employe_from_user(request.user)
114 q = Q(**{self.model.prefix_implantation: employe.implantation.region})
115 qs = qs.filter(q).distinct()
116 return qs
117 return qs.none()
118
119 def has_change_permission(self, request, obj=None):
120 user_groups = request.user.groups.all()
121
122 # Lock pour autoriser uniquement les DRH à utiliser RH
123 if not request.user.is_superuser and not grp_drh in user_groups:
124 return False
125
126 if len(user_groups) == 0 and not request.user.is_superuser:
127 return False
128
129 if obj is None:
130 return True
131 ids = [o.id for o in self.queryset(request)]
132 return obj.id in ids
133
134
135 # Inlines
136
137 class ReadOnlyInlineMixin(object):
138 def get_readonly_fields(self, request, obj=None):
139 return [f.name for f in self.model._meta.fields if f.name not in AUF_METADATA_READONLY_FIELDS]
140
141
142 class AyantDroitInline(AUFMetadataInlineAdminMixin, admin.StackedInline):
143 model = rh.AyantDroit
144 form = AyantDroitForm
145 extra = 0
146
147 fieldsets = (
148 (None, {
149 'fields': (('nom', 'prenom'), ('nom_affichage', 'genre'), 'nationalite', 'date_naissance', 'lien_parente', )
150 }),
151 )
152
153
154 class AyantDroitCommentaireInline(AUFMetadataInlineAdminMixin, admin.TabularInline):
155 readonly_fields = ('owner', )
156 model = rh.AyantDroitCommentaire
157 extra = 1
158
159
160 class ContratInline(AUFMetadataInlineAdminMixin, admin.TabularInline):
161 form = ContratForm
162 model = rh.Contrat
163 extra = 1
164
165
166 class DossierROInline(ReadOnlyInlineMixin, LinkedInline):
167 template = "admin/rh/dossier/linked.html"
168 exclude = AUF_METADATA_READONLY_FIELDS
169 model = rh.Dossier
170 extra = 0
171 can_delete = False
172
173 def has_add_permission(self, request=None):
174 return False
175
176 def has_change_permission(self, request, obj=None):
177 return False
178
179 def has_delete_permission(self, request, obj=None):
180 return False
181
182
183 class DossierCommentaireInline(AUFMetadataInlineAdminMixin, admin.TabularInline):
184 readonly_fields = ('owner', )
185 model = rh.DossierCommentaire
186 extra = 1
187
188
189 class DossierPieceInline(admin.TabularInline):
190 model = rh.DossierPiece
191 extra = 4
192
193
194 class EmployeInline(admin.TabularInline):
195 model = rh.Employe
196
197 class EmployeCommentaireInline(AUFMetadataInlineAdminMixin, admin.TabularInline):
198 readonly_fields = ('owner', )
199 model = rh.EmployeCommentaire
200 extra = 1
201
202
203 class EmployePieceInline(admin.TabularInline):
204 model = rh.EmployePiece
205 extra = 4
206
207
208 class PosteCommentaireInline(AUFMetadataInlineAdminMixin, admin.TabularInline):
209 readonly_fields = ('owner', )
210 model = rh.PosteCommentaire
211 extra = 1
212
213
214 class PosteFinancementInline(admin.TabularInline):
215 model = rh.PosteFinancement
216
217
218 class PostePieceInline(admin.TabularInline):
219 model = rh.PostePiece
220
221
222 class RemunerationInline(AUFMetadataInlineAdminMixin, admin.TabularInline):
223 model = rh.Remuneration
224 extra = 1
225
226
227 class RemunerationROInline(ReadOnlyInlineMixin, RemunerationInline):
228 pass
229
230
231 class TypePosteInline(AUFMetadataInlineAdminMixin, admin.TabularInline):
232 model = rh.TypePoste
233
234
235 class PosteComparaisonInline(AUFMetadataInlineAdminMixin, admin.TabularInline):
236 model = rh.PosteComparaison
237
238
239 class ClassementAdmin(AUFMetadataAdminMixin, admin.ModelAdmin):
240 list_display = ('_classement', '_date_modification', 'user_modification', )
241 fieldsets = AUFMetadataAdminMixin.fieldsets + (
242 (None, {
243 'fields': ('type', 'echelon', 'degre', 'coefficient', )
244 }),
245 )
246
247 def _classement(self, obj):
248 return unicode(obj)
249 _classement.short_description = u"Classement"
250
251 def _date_modification(self, obj):
252 return date(obj.date_modification) if obj.date_modification is not None else "(aucune)"
253 _date_modification.short_description = u'date modification'
254 _date_modification.admin_order_field = 'date_modification'
255
256 class CommentaireAdmin(admin.ModelAdmin):
257 pass
258
259
260 class DeviseAdmin(AUFMetadataAdminMixin, admin.ModelAdmin):
261 list_display = ('code', 'nom', '_date_modification', 'user_modification', '_archive',)
262 list_filter = ('archive', )
263 fieldsets = AUFMetadataAdminMixin.fieldsets + (
264 (None, {
265 'fields': ('code', 'nom', 'archive', ),
266 }),
267 )
268
269 def queryset(self, request):
270 return rh.Devise._base_manager
271
272 def _archive(self, obj):
273 if obj.archive:
274 icon = 'no'
275 else:
276 icon = 'yes'
277 html = """<img alt="%s" src="%sadmin/img/admin/icon-%s.gif">""" % (obj.archive, settings.STATIC_URL, icon)
278 return html
279 _archive.short_description = u'Archivé'
280 _archive.admin_order_field = 'archive'
281 _archive.allow_tags = True
282
283
284 def _date_modification(self, obj):
285 return date(obj.date_modification) if obj.date_modification is not None else "(aucune)"
286 _date_modification.short_description = u'date modification'
287 _date_modification.admin_order_field = 'date_modification'
288
289 class DossierAdmin(DateRangeMixin, AUFMetadataAdminMixin, ProtectRegionMixin, admin.ModelAdmin, AjaxSelect,):
290 alphabet_filter = 'employe__nom'
291 search_fields = ('employe__nom', 'employe__prenom', 'poste__nom', 'poste__nom_feminin')
292 list_display = (
293 '_id',
294 '_apercu',
295 '_nom',
296 '_poste',
297 '_employe',
298 '_date_debut',
299 '_date_fin',
300 '_date_modification',
301 'user_modification',
302 )
303 list_display_links = ('_nom',)
304 list_filter = (
305 'poste__implantation__region',
306 'poste__implantation',
307 'poste__type_poste__famille_emploi',
308 'poste__type_poste',
309 'rh_contrats__type_contrat',
310 'date_debut',
311 'date_fin',
312 )
313 inlines = (DossierPieceInline, ContratInline,
314 RemunerationInline,
315 DossierCommentaireInline,
316 )
317 fieldsets = AUFMetadataAdminMixin.fieldsets + (
318 (None, {
319 'fields': ('employe', 'poste', 'statut', 'organisme_bstg',)
320 }),
321 ('Recrutement', {
322 'fields': ('statut_residence', 'remplacement', 'remplacement_de', )
323 }),
324 ('Rémunération', {
325 'fields': ('classement', ('regime_travail', 'regime_travail_nb_heure_semaine'),)
326 }),
327 ('Occupation du Poste par cet Employe', {
328 'fields': (('date_debut', 'date_fin'), )
329 }),
330 )
331 form = make_ajax_form(rh.Dossier, {
332 'employe' : 'employes',
333 'poste' : 'postes',
334 'remplacement_de' : 'dossiers',
335 })
336
337 def lookup_allowed(self, key, value):
338 if key in (
339 'employe__nom__istartswith',
340 'poste__implantation__region__id__exact',
341 'poste__implantation__id__exact',
342 'poste__type_poste__id__exact',
343 'poste__type_poste__famille_emploi__id__exact',
344 'rh_contrats__type_contrat__id__exact',
345 'date_debut__gte',
346 'date_debut__isnull',
347 'date_fin__lte',
348 'date_fin__isnull',
349 ):
350 return True
351
352 def _id(self, obj):
353 return obj.id
354 _id.short_description = u"#"
355 _id.admin_order_field = "id"
356
357 def _nom(self, obj):
358 return "%d : %s&nbsp;%s" % \
359 (obj.date_debut.year, obj.employe.nom.upper(), obj.employe.prenom)
360 _nom.allow_tags = True
361 _nom.short_description = u"Dossier"
362
363
364 def _apercu(self, d):
365 apercu_link = u"""<a title="Aperçu du dossier" onclick="return showAddAnotherPopup(this);" href='%s'><img src="%simg/loupe.png" /></a>""" % \
366 (reverse('dossier_apercu', args=(d.id,)),
367 settings.STATIC_URL,
368 )
369 return apercu_link
370 _apercu.allow_tags = True
371 _apercu.short_description = u""
372
373
374 def _date_debut(self, obj):
375 return date(obj.date_debut)
376
377 _date_debut.short_description = u'Occupation début'
378 _date_debut.admin_order_field = 'date_debut'
379
380 def _date_fin(self, obj):
381 return date(obj.date_fin)
382 _date_fin.short_description = u'Occupation fin'
383 _date_fin.admin_order_field = 'date_fin'
384
385
386 def _date_modification(self, obj):
387 return date(obj.date_modification) if obj.date_modification is not None else "(aucune)"
388 _date_modification.short_description = u'date modification'
389 _date_modification.admin_order_field = 'date_modification'
390
391 def _poste(self, dossier):
392 link = u"""<a title="Aperçu du poste" onclick="return showAddAnotherPopup(this);" href='%s'><img src="%simg/loupe.png" /></a> <a href="%s" title="Modifier le poste">%s</a>""" % \
393 (reverse('poste_apercu', args=(dossier.poste.id,)),
394 settings.STATIC_URL,
395 reverse('admin:rh_poste_change', args=(dossier.poste.id,)),
396 dossier.poste,
397 )
398 return link
399 _poste.allow_tags = True
400 _poste.short_description = u'Poste'
401 _poste.admin_order_field = 'poste__nom'
402
403 def _employe(self, obj):
404 employe = obj.employe
405 view_link = reverse('employe_apercu', args=(employe.id,))
406 edit_link = reverse('admin:rh_employe_change', args=(employe.id,))
407
408 style = ""
409 view = u"""<a href="%s" title="Aperçu l'employé" onclick="return showAddAnotherPopup(this);"><img src="%simg/loupe.png" /></a>""" % (view_link, settings.STATIC_URL,)
410 return u"""%s<a href='%s' style="%s;">%s</a>""" % \
411 (view, edit_link, style, employe)
412 _employe.allow_tags = True
413 _employe.short_description = u"Employé"
414 _employe.admin_order_field = "employe__nom"
415
416 def save_formset(self, request, form, formset, change):
417 instances = formset.save(commit=False)
418 for instance in instances:
419 if instance.__class__ == rh.DossierCommentaire:
420 instance.owner = request.user
421 instance.date_creation = datetime.datetime.now()
422 instance.save()
423
424
425 class DossierPieceAdmin(admin.ModelAdmin):
426 pass
427
428
429 class DossierCommentaireAdmin(admin.ModelAdmin):
430 pass
431
432
433 class EmployeAdmin(DateRangeMixin, AUFMetadataAdminMixin, ProtectRegionMixin, admin.ModelAdmin,):
434 alphabet_filter = 'nom'
435 DEFAULT_ALPHABET = u'ABCDEFGHIJKLMNOPQRSTUVWXYZ'
436 search_fields = ('id', 'nom', 'prenom', 'nom_affichage', )
437 ordering = ('nom', )
438 form = EmployeAdminForm
439 list_display = ('_id', '_apercu', '_nom', '_dossiers_postes', '_date_modification', 'user_modification', )
440 list_display_links = ('_nom',)
441 list_filter = ('rh_dossiers__poste__implantation__region', 'rh_dossiers__poste__implantation', 'nb_postes', 'rh_dossiers__date_debut', 'rh_dossiers__date_fin')
442 date_borne_gauche = 'rh_dossiers__date_debut'
443 date_borne_droite = 'rh_dossiers__date_fin'
444 inlines = (AyantDroitInline,
445 DossierROInline,
446 EmployePieceInline,
447 EmployeCommentaireInline)
448 fieldsets = AUFMetadataAdminMixin.fieldsets + (
449 ('Identification', {
450 'fields': (('nom', 'prenom'), ('nom_affichage', 'genre'), 'nationalite', 'date_naissance', )
451 }),
452 ('Informations personnelles', {
453 'fields': ('situation_famille', 'date_entree', )
454 }),
455 ('Coordonnées', {
456 'fields': (('tel_domicile', 'tel_cellulaire'), ('adresse', 'ville'), ('code_postal', 'province'), 'pays', )
457 }),
458 )
459
460 def _apercu(self, obj):
461 return u"""<a title="Aperçu de l'employé" onclick="return showAddAnotherPopup(this);" href='%s'><img src="%simg/loupe.png" /></a>""" % \
462 (reverse('employe_apercu', args=(obj.id,)), settings.STATIC_URL)
463 _apercu.allow_tags = True
464 _apercu.short_description = u""
465
466 def _nom(self, obj):
467 edit_link = reverse('admin:rh_employe_change', args=(obj.id,))
468 return u"""<a href='%s'><strong>%s</strong></a>""" % \
469 (edit_link, "%s %s" % (obj.nom.upper(), obj.prenom))
470 _nom.allow_tags = True
471 _nom.short_description = u"Employé"
472 _nom.admin_order_field = "nom"
473
474 def _id(self, obj):
475 return obj.id
476 _id.short_description = u"#"
477 _id.admin_order_field = "id"
478
479 def _date_modification(self, obj):
480 return date(obj.date_modification) if obj.date_modification is not None else "(aucune)"
481 _date_modification.short_description = u'date modification'
482 _date_modification.admin_order_field = 'date_modification'
483
484 def _dossiers_postes(self, obj):
485 l = []
486 for d in obj.rh_dossiers.all().order_by('-date_debut'):
487 dossier = u"""<a title="Aperçu du dossier" href="%s" onclick="return showAddAnotherPopup(this);" title="Aperçu du dossier"><img src="%simg/loupe.png" /></a><a href="%s">Dossier</a>&nbsp;""" % \
488 ( reverse('dossier_apercu', args=(d.id,)),
489 settings.STATIC_URL,
490 reverse('admin:rh_dossier_change', args=(d.id,))
491 )
492
493 poste = u"""<a title="Aperçu du poste" href="%s" onclick="return showAddAnotherPopup(this);" title="Aperçu du poste"><img src="%simg/loupe.png" /></a><a href="%s">Poste</a>&nbsp;""" % \
494 ( reverse('poste_apercu', args=(d.poste.id,)),
495 settings.STATIC_URL,
496 reverse('admin:rh_poste_change', args=(d.poste.id,))
497 )
498 link = u"""<li>%s %s - %s : [%s] %s</li>""" % \
499 (dossier, poste,
500 d.date_debut.year,
501 d.poste.id,
502 d.poste.nom,
503 )
504
505 # Dossier terminé en gris non cliquable
506 if d.date_fin is not None:
507 link = u"""<li style="color: grey">%s : [%s] %s</li>""" % \
508 (d.date_debut.year,
509 d.poste.id,
510 d.poste.nom,
511 )
512
513 l.append(link)
514 return "<ul>%s</ul>" % "\n".join(l)
515 _dossiers_postes.allow_tags = True
516 _dossiers_postes.short_description = u"Dossiers et postes"
517
518 def queryset(self, request):
519 qs = super(EmployeAdmin, self).queryset(request)
520 return qs.select_related(depth=1).order_by('nom')
521
522 def save_formset(self, request, form, formset, change):
523 instances = formset.save(commit=False)
524 for instance in instances:
525 if instance.__class__ == rh.EmployeCommentaire:
526 instance.owner = request.user
527 instance.date_creation = datetime.datetime.now()
528 instance.save()
529
530
531
532 class EmployeCommentaireAdmin(admin.ModelAdmin):
533 pass
534
535
536 class EmployePieceAdmin(admin.ModelAdmin):
537 pass
538
539
540 class FamilleEmploiAdmin(AUFMetadataAdminMixin, admin.ModelAdmin):
541 list_display = ('nom', '_date_modification', 'user_modification', )
542 inlines = (TypePosteInline,)
543 fieldsets = AUFMetadataAdminMixin.fieldsets + (
544 (None, {
545 'fields': ('nom', )
546 }),
547 )
548
549 def _date_modification(self, obj):
550 return date(obj.date_modification) if obj.date_modification is not None else "(aucune)"
551 _date_modification.short_description = u'date modification'
552 _date_modification.admin_order_field = 'date_modification'
553
554 class OrganismeBstgAdmin(AUFMetadataAdminMixin, admin.ModelAdmin):
555 search_fields = ('nom',)
556 list_display = ('nom', 'type', 'pays', '_date_modification', 'user_modification', )
557 list_filter = ('type', )
558 inlines = (DossierROInline,)
559 fieldsets = AUFMetadataAdminMixin.fieldsets + (
560 (None, {
561 'fields': ('nom', 'type', 'pays', )
562 }),
563 )
564
565 def _date_modification(self, obj):
566 return date(obj.date_modification) if obj.date_modification is not None else "(aucune)"
567 _date_modification.short_description = u'date modification'
568 _date_modification.admin_order_field = 'date_modification'
569
570
571 class PosteAdmin(DateRangeMixin, AUFMetadataAdminMixin, ProtectRegionMixin, admin.ModelAdmin, AjaxSelect,):
572 form = make_ajax_form(rh.Poste, {
573 'implantation' : 'implantations',
574 'type_poste' : 'typepostes',
575 'responsable' : 'postes',
576 'valeur_point_min' : 'valeurpoints',
577 'valeur_point_max' : 'valeurpoints',
578 })
579 alphabet_filter = 'nom'
580 search_fields = ('nom',
581 'implantation__code',
582 'implantation__nom',
583 'implantation__region__code',
584 'implantation__region__nom',
585 'rh_dossiers__employe__nom',
586 'rh_dossiers__employe__prenom',
587 )
588 list_display = (
589 '_id',
590 '_apercu',
591 '_nom',
592 '_occupe_par',
593 'implantation',
594 '_service',
595 'date_debut',
596 'date_fin',
597 '_date_modification',
598 'user_modification',
599 )
600 list_filter = (
601 'implantation__region',
602 'implantation',
603 'service',
604 'type_poste',
605 'type_poste__famille_emploi',
606 'date_debut',
607 'date_fin',
608 'vacant',
609 )
610 list_display_links = ('_nom',)
611 fieldsets = AUFMetadataAdminMixin.fieldsets + (
612 (None, {
613 'fields': (('nom', 'nom_feminin'), 'implantation', 'type_poste',
614 'service', 'responsable')
615 }),
616 ('Contrat', {
617 'fields': (('regime_travail', 'regime_travail_nb_heure_semaine'), )
618 }),
619 ('Recrutement', {
620 'fields': (('local', 'expatrie', 'mise_a_disposition', 'appel'),)
621 }),
622 ('Rémunération', {
623 'fields': (('classement_min', 'valeur_point_min', 'devise_min', 'salaire_min', 'indemn_min', 'autre_min', ),
624 ('classement_max', 'valeur_point_max' ,'devise_max', 'salaire_max', 'indemn_max', 'autre_max', ),
625 )
626 }),
627 ('Comparatifs de rémunération', {
628 'fields': ('devise_comparaison',
629 ('comp_locale_min', 'comp_locale_max'),
630 ('comp_universite_min', 'comp_universite_max'),
631 ('comp_fonctionpub_min', 'comp_fonctionpub_max'),
632 ('comp_ong_min', 'comp_ong_max'),
633 ('comp_autre_min', 'comp_autre_max'))
634 }),
635 ('Justification', {
636 'fields': ('justification',)
637 }),
638 ('Autres Méta-données', {
639 'fields': ('date_debut', 'date_fin')
640 }),
641 )
642
643 inlines = (PosteFinancementInline,
644 PostePieceInline,
645 DossierROInline,
646 PosteComparaisonInline,
647 PosteCommentaireInline, )
648
649
650 def lookup_allowed(self, key, value):
651 if key in (
652 'date_debut__gte',
653 'date_debut__isnull',
654 'date_fin__lte',
655 'date_fin__isnull',
656 'implantation__region__id__exact',
657 'implantation__id__exact',
658 'type_poste__id__exact',
659 'type_poste__famille_emploi__id__exact',
660 'service__id__exact',
661 'service__isnull',
662 'vacant__exact',
663 ):
664 return True
665
666
667 def _apercu(self, poste):
668 view_link = u"""<a onclick="return showAddAnotherPopup(this);" title="Aperçu du poste" href='%s'><img src="%simg/loupe.png" /></a>""" % \
669 (reverse('poste_apercu', args=(poste.id,)),
670 settings.STATIC_URL,
671 )
672 return view_link
673 _apercu.allow_tags = True
674 _apercu.short_description = ''
675
676 def _id(self, obj):
677 return "%s" % obj.id
678 _id.short_description = '#'
679 _id.admin_order_field = 'id'
680
681 def _service(self, obj):
682 return obj.service
683 _service.short_description = 'Service'
684
685 def _nom(self, poste):
686 return """<a href="%s">%s</a>""" % \
687 (reverse('admin:rh_poste_change', args=(poste.id,)),
688 poste.nom
689 )
690 _nom.allow_tags = True
691 _nom.short_description = u'Nom'
692 _nom.admin_order_field = 'nom'
693
694 def _date_modification(self, obj):
695 return date(obj.date_modification)
696 _date_modification.short_description = u'date modification'
697 _date_modification.admin_order_field = 'date_modification'
698
699 def _occupe_par(self, obj):
700 """Formatte la méthode Poste.occupe_par() pour l'admin"""
701 output = u"Vacant"
702 if obj.date_fin is not None and obj.date_fin < datetime.date.now():
703 return u"s/o"
704 employes = obj.occupe_par()
705 if employes:
706 l = []
707 for e in employes:
708 link = "<a href='%s' title='Aperçu de l\'employer' onclick='return showAddAnotherPopup(this)'><img src='%simg/loupe.png' /></a> <a href='%s'>%s</a>" % \
709 (reverse('employe_apercu', args=(e.id,)),
710 settings.STATIC_URL,
711 reverse('admin:rh_employe_change', args=(e.id,)),
712 e
713 )
714 l.append(link)
715 output = "\n<br />".join(l)
716 return output
717 _occupe_par.allow_tags = True
718 _occupe_par.short_description = "Occupé par"
719
720 def save_formset(self, request, form, formset, change):
721 instances = formset.save(commit=False)
722 for instance in instances:
723 if instance.__class__ == rh.PosteCommentaire:
724 instance.owner = request.user
725 instance.date_creation = datetime.datetime.now()
726 instance.save()
727 formset.save_m2m()
728
729
730 class PosteCommentaireAdmin(admin.ModelAdmin):
731 pass
732
733
734 class PosteFinancementAdmin(admin.ModelAdmin):
735 pass
736
737
738 class PostePieceAdmin(admin.ModelAdmin):
739 fk_name = 'poste'
740
741
742 class RemunerationAdmin(admin.ModelAdmin):
743 pass
744
745
746 class ResponsableImplantationAdmin(AUFMetadataAdminMixin, admin.ModelAdmin):
747 fieldsets = AUFMetadataAdminMixin.fieldsets + (
748 (None, {
749 'fields': ('employe', 'implantation', ),
750 }),
751 )
752
753
754 class ServiceAdmin(AUFMetadataAdminMixin, admin.ModelAdmin):
755 list_display = ('nom', '_date_modification', 'user_modification', )
756 fieldsets = AUFMetadataAdminMixin.fieldsets + (
757 (None, {
758 'fields': ('nom', ),
759 }),
760 )
761
762 def _date_modification(self, obj):
763 return date(obj.date_modification) if obj.date_modification is not None else "(aucune)"
764 _date_modification.short_description = u'date modification'
765 _date_modification.admin_order_field = 'date_modification'
766
767
768 class StatutAdmin(AUFMetadataAdminMixin, admin.ModelAdmin):
769 list_display = ('code', 'nom', '_date_modification', 'user_modification', )
770 fieldsets = AUFMetadataAdminMixin.fieldsets + (
771 (None, {
772 'fields': ('code', 'nom', ),
773 }),
774 )
775
776 def _date_modification(self, obj):
777 return date(obj.date_modification) if obj.date_modification is not None else "(aucune)"
778 _date_modification.short_description = u'date modification'
779 _date_modification.admin_order_field = 'date_modification'
780
781 class TauxChangeAdmin(admin.ModelAdmin):
782 list_display = ('taux', 'devise', 'annee', '_date_modification', 'user_modification', )
783 list_filter = ('devise', )
784 fieldsets = AUFMetadataAdminMixin.fieldsets + (
785 (None, {
786 'fields': ('taux', 'devise', 'annee', ),
787 }),
788 )
789
790 def _date_modification(self, obj):
791 return date(obj.date_modification) if obj.date_modification is not None else "(aucune)"
792 _date_modification.short_description = u'date modification'
793 _date_modification.admin_order_field = 'date_modification'
794
795 class TypeContratAdmin(admin.ModelAdmin):
796 list_display = ('nom', 'nom_long', '_date_modification', 'user_modification', )
797 fieldsets = AUFMetadataAdminMixin.fieldsets + (
798 (None, {
799 'fields': ('nom', 'nom_long', ),
800 }),
801 )
802
803 def _date_modification(self, obj):
804 return date(obj.date_modification) if obj.date_modification is not None else "(aucune)"
805 _date_modification.short_description = u'date modification'
806 _date_modification.admin_order_field = 'date_modification'
807
808
809 class TypePosteAdmin(AUFMetadataAdminMixin, admin.ModelAdmin):
810 search_fields = ('nom', 'nom_feminin', )
811 list_display = ('nom', 'famille_emploi', '_date_modification', 'user_modification', )
812 list_filter = ('famille_emploi', )
813 fieldsets = AUFMetadataAdminMixin.fieldsets + (
814 (None, {
815 'fields': ('nom', 'nom_feminin', 'is_responsable', 'famille_emploi', )
816 }),
817 )
818
819 def _date_modification(self, obj):
820 return date(obj.date_modification) if obj.date_modification is not None else "(aucune)"
821 _date_modification.short_description = u'date modification'
822 _date_modification.admin_order_field = 'date_modification'
823
824
825 class TypeRemunerationAdmin(AUFMetadataAdminMixin, admin.ModelAdmin):
826 list_display = ('nom', 'type_paiement', 'nature_remuneration', '_date_modification', 'user_modification', )
827 fieldsets = AUFMetadataAdminMixin.fieldsets + (
828 (None, {
829 'fields': ('nom', 'type_paiement', 'nature_remuneration', )
830 }),
831 )
832
833 def _date_modification(self, obj):
834 return date(obj.date_modification) if obj.date_modification is not None else "(aucune)"
835 _date_modification.short_description = u'date modification'
836 _date_modification.admin_order_field = 'date_modification'
837
838
839 class TypeRevalorisationAdmin(AUFMetadataAdminMixin, admin.ModelAdmin):
840 list_display = ('nom', '_date_modification', 'user_modification', )
841 fieldsets = AUFMetadataAdminMixin.fieldsets + (
842 (None, {
843 'fields': ('nom', )
844 }),
845 )
846
847 def _date_modification(self, obj):
848 return date(obj.date_modification) if obj.date_modification is not None else "(aucune)"
849 _date_modification.short_description = u'date modification'
850 _date_modification.admin_order_field = 'date_modification'
851
852
853 class ValeurPointAdmin(AUFMetadataAdminMixin, admin.ModelAdmin):
854 list_display = ('_devise_code', '_devise_nom', 'annee', 'valeur', '_date_modification', 'user_modification', )
855 list_filter = ('annee', 'devise', )
856 fieldsets = AUFMetadataAdminMixin.fieldsets + (
857 (None, {
858 'fields': ('valeur', 'devise', 'implantation', 'annee', )
859 }),
860 )
861
862 def _date_modification(self, obj):
863 return date(obj.date_modification) if obj.date_modification is not None else "(aucune)"
864 _date_modification.short_description = u'date modification'
865 _date_modification.admin_order_field = 'date_modification'
866
867 def _devise_code(self, obj):
868 return obj.devise.code
869 _devise_code.short_description = "Code de la devise"
870
871 def _devise_nom(self, obj):
872 return obj.devise.nom
873 _devise_nom.short_description = "Nom de la devise"
874
875
876 admin.site.register(rh.Classement, ClassementAdmin)
877 admin.site.register(rh.Devise, DeviseAdmin)
878 admin.site.register(rh.Dossier, DossierAdmin)
879 admin.site.register(rh.Employe, EmployeAdmin)
880 admin.site.register(rh.FamilleEmploi, FamilleEmploiAdmin)
881 admin.site.register(rh.OrganismeBstg, OrganismeBstgAdmin)
882 admin.site.register(rh.Poste, PosteAdmin)
883 admin.site.register(rh.ResponsableImplantation, ResponsableImplantationAdmin)
884 admin.site.register(rh.Service, ServiceAdmin)
885 admin.site.register(rh.Statut, StatutAdmin)
886 admin.site.register(rh.TauxChange, TauxChangeAdmin)
887 admin.site.register(rh.TypeContrat, TypeContratAdmin)
888 admin.site.register(rh.TypePoste, TypePosteAdmin)
889 admin.site.register(rh.TypeRemuneration, TypeRemunerationAdmin)
890 admin.site.register(rh.TypeRevalorisation, TypeRevalorisationAdmin)
891 admin.site.register(rh.ValeurPoint, ValeurPointAdmin)