Done with feature
[auf_rh_dae.git] / project / rh / admin.py
CommitLineData
53ae644d
OL
1# -*- encoding: utf-8 -*-
2
53ae644d 3import datetime
d104b0ae 4import reversion
343cfd9c 5import itertools
d104b0ae 6from ajax_select import make_ajax_form
d104b0ae 7from auf.django.references import models as ref
343cfd9c 8from django.core.mail import send_mail
e8b6a20c
BS
9from django.contrib.auth.admin import UserAdmin
10from django.contrib.auth.models import User
45066657 11from django import forms
53ae644d 12from django.core.urlresolvers import reverse
50fa9bc1 13from django.contrib import admin
45066657 14from django.contrib.contenttypes.models import ContentType
53ae644d 15from django.conf import settings
f7badf51 16from django.db.models import Q, Count
5f36f262 17from django.template.defaultfilters import date
5db1c5a3 18from django.utils.formats import date_format
fc4bf968 19
82c5e37d 20from project import groups
018c8eaf 21from project.decorators import in_drh_or_admin
d104b0ae 22from project.rh import models as rh
798ebe68 23from project.permissions import user_gere_obj_de_sa_region, \
25f2c148 24 user_can_list_obj, \
7000b7b3
DB
25 user_can_add_obj, \
26 user_can_change_obj, \
e8b6a20c 27 user_can_delete_obj
d41d8e47 28
6fb68b2f 29from project.rh.forms import ContratForm, AyantDroitForm, EmployeAdminForm, \
614b143d
OL
30 AjaxSelect, DossierForm, ResponsableInlineForm
31from project.rh.change_list import ChangeList
fc4bf968 32
90440a65 33
57b4a22f
OL
34def listing_par_defaut(model, request):
35 """
36 Teste si la requete provient de la même page.
37 """
38 if not 'HTTP_REFERER' in request.META.keys():
39 return False
40 referer = request.META['HTTP_REFERER']
41 referer = "/".join(referer.split('/')[3:])
42 referer = "/%s" % referer.split('?')[0]
43 change_list_view = 'admin:%s_%s_changelist' % (
44 model._meta.app_label,
45 model.__name__.lower(),)
46 return referer != reverse(change_list_view)
82af5c19 47
90440a65 48
08a9b6fc
EMS
49class BaseAdmin(admin.ModelAdmin):
50
51 class Media:
dd6c0df2
EMS
52 css = {'screen': (
53 'css/admin_custom.css',
54 'jquery-autocomplete/jquery.autocomplete.css',
55 )}
56 js = (
57 'https://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js',
58 'jquery-autocomplete/jquery.autocomplete.min.js',
59 )
08a9b6fc 60
b0cf30b8 61
45066657
EMS
62# Admin pour reversion
63
7013d234 64class ArchivableAdmin(admin.ModelAdmin):
7ba822a6 65 """
7013d234 66 Admin pour les modèles archivables
7ba822a6 67 """
7013d234 68 list_filter = ('archive', )
7ba822a6
OL
69
70 def queryset(self, request):
7013d234 71 return self.model.avec_archives.all()
7ba822a6
OL
72
73 def _archive(self, obj):
74 if obj.archive:
75 return "oui"
76 else:
77 return "non"
78 _archive.short_description = u'Archivé'
79 _archive.admin_order_field = 'archive'
80
fc4bf968 81
9da4c195
JPC
82class RegionProxy(ref.Region):
83 """ Proxy utilisé pour les organigrammes par région """
84 class Meta:
d7bf0cd3 85 managed = False
9da4c195
JPC
86 proxy = True
87 verbose_name = u"Organigramme par région"
88 verbose_name_plural = u"Organigramme par région"
89
90
82af5c19
JPC
91class ImplantationProxy(ref.Implantation):
92 """ Proxy utilisé pour les organigrammes par implantation """
93 class Meta:
d7bf0cd3 94 managed = False
82af5c19
JPC
95 proxy = True
96 verbose_name = u"Organigramme par implantations"
97 verbose_name_plural = u"Organigramme par implantations"
98
22343fe7 99
5c0f1778 100class ServiceProxy(rh.Service):
22e06da4 101 """ Proxy utilisé pour les organigrammes par service """
f7badf51 102
5c0f1778 103 class Meta:
d7bf0cd3 104 managed = False
5c0f1778
JPC
105 proxy = True
106 verbose_name = u"Organigramme par services"
107 verbose_name_plural = u"Organigramme par services"
108
22343fe7 109
5c0f1778
JPC
110class EmployeProxy(rh.Employe):
111 """ Proxy utilisé pour les organigrammes des employés """
22343fe7 112 class Meta:
d7bf0cd3 113 managed = False
22343fe7
OL
114 proxy = True
115 verbose_name = u"Organigramme des employés"
116 verbose_name_plural = u"Organigramme des employés"
117
f614ca5c 118
40b35603 119class DateRangeMixin(object):
a17e2236 120 prefixe_recherche_temporelle = ""
22343fe7 121
40b35603 122 def get_changelist(self, request, **kwargs):
57b4a22f
OL
123 """
124 On filtre par défaut sur les items 'actifs'.
125 Le changelist plug le filtrage temporel.
126 """
127 if listing_par_defaut(self.model, request):
128 params = request.GET.copy()
129 params.update({'statut': 'Actif'})
130 request.GET = params
40b35603 131 return ChangeList
3195667e 132
22343fe7 133
53ae644d
OL
134# Override of the InlineModelAdmin to support the link in the tabular inline
135class LinkedInline(admin.options.InlineModelAdmin):
136 template = "admin/linked.html"
137 admin_model_path = None
138
139 def __init__(self, *args):
140 super(LinkedInline, self).__init__(*args)
141 if self.admin_model_path is None:
142 self.admin_model_path = self.model.__name__.lower()
143
144
145class ProtectRegionMixin(object):
146
57b4a22f
OL
147 def changelist_view(self, request, extra_context=None):
148 """
149 On filtre par défaut sur la ZA du user connecté
150 """
151 if listing_par_defaut(self.model, request):
152 if user_gere_obj_de_sa_region(request.user):
153 params = request.GET.copy()
e8b6a20c
BS
154 zones = groups.get_zones_from_user(request.user)
155 prefix_za = "%s__in" % self.model.prefix_implantation
156 params.update({prefix_za: zones})
57b4a22f 157 request.GET = params
90440a65
EMS
158 return super(ProtectRegionMixin, self) \
159 .changelist_view(request, extra_context)
57b4a22f 160
53ae644d 161 def queryset(self, request):
53ae644d
OL
162 qs = super(ProtectRegionMixin, self).queryset(request)
163
a12ddd52 164 if in_drh_or_admin(request.user):
53ae644d
OL
165 return qs
166
93965eb0 167 if user_gere_obj_de_sa_region(request.user):
e8b6a20c
BS
168 zones = groups.get_zones_from_user(request.user)
169 qkey = '%s__in' % self.model.prefix_implantation
170 q = Q(**{qkey: zones})
93965eb0
OL
171 qs = qs.filter(q).distinct()
172 return qs
53ae644d
OL
173 return qs.none()
174
c0be8705 175 def has_add_permission(self, request):
93965eb0 176 return user_can_add_obj(request.user)
c0be8705 177
53ae644d 178 def has_change_permission(self, request, obj=None):
25f2c148
OL
179 if obj is None:
180 return user_can_list_obj(request.user)
181 else:
182 return user_can_change_obj(request.user, obj)
a0d365ed 183
7000b7b3 184 def has_delete_permission(self, request, obj=None):
93965eb0 185 return user_can_delete_obj(request.user, obj) if obj else True
53ae644d
OL
186
187
45066657
EMS
188class DerniereModificationAdmin(admin.ModelAdmin):
189
190 def queryset(self, request):
191 qs = super(DerniereModificationAdmin, self).queryset(request)
192 ct = ContentType.objects.get_for_model(self.model)
193 db_table = self.model._meta.db_table
194 pk = self.model._meta.pk.column
195 return qs.extra(select={
196 'date_modification':
197 "SELECT action_time FROM django_admin_log "
198 "WHERE content_type_id = %d AND object_id = %s.%s "
199 "ORDER BY action_time DESC "
200 "LIMIT 1" % (ct.id, db_table, pk),
201 'user_modification':
202 "SELECT u.username "
203 "FROM auth_user u "
204 "INNER JOIN django_admin_log l ON l.user_id = u.id "
205 "WHERE l.content_type_id = %d AND object_id = %s.%s "
206 "ORDER BY action_time DESC "
207 "LIMIT 1" % (ct.id, db_table, pk),
208 })
209
210 def derniere_modification(self, obj):
211 text = ''
212 if obj.date_modification:
213 text += obj.date_modification.strftime('%d-%m-%Y %H:%M')
214 if obj.user_modification:
215 text += ' par ' + obj.user_modification
216 return text
217 derniere_modification.short_description = u'dernière modification'
218 derniere_modification.admin_order_field = 'date_modification'
219
220
53ae644d
OL
221# Inlines
222
45066657
EMS
223class CommentaireInlineForm(forms.ModelForm):
224
225 def save(self, commit=True):
226
227 # Hack: reversion.VersionAdmin ne sauvegarde pas les champs qui ne
228 # sont pas explicitement dans le formulaire. Il plante cependant
229 # leur valeur dans `self.initial`. Ceci est un peu fragile. Si
230 # c'est possible, il serait plus approprié que Reversion se rende
231 # compte qu'il manque des champs.
232 instance = super(CommentaireInlineForm, self).save(commit=False)
233 if instance.owner_id is None and 'owner' in self.initial:
234 instance.owner_id = self.initial['owner']
235 if instance.date_creation is None and 'date_creation' in self.initial:
236 instance.date_creation = self.initial['date_creation']
237 if commit:
238 instance.save()
239 self.save_m2m()
240 return instance
241
242
53ae644d 243class ReadOnlyInlineMixin(object):
22343fe7 244
53ae644d 245 def get_readonly_fields(self, request, obj=None):
45066657 246 return [f.name for f in self.model._meta.fields]
53ae644d
OL
247
248
45066657 249class AyantDroitInline(admin.StackedInline):
53ae644d
OL
250 model = rh.AyantDroit
251 form = AyantDroitForm
252 extra = 0
253
254 fieldsets = (
255 (None, {
22343fe7
OL
256 'fields': (
257 ('nom', 'prenom'),
258 ('nom_affichage', 'genre'),
259 'nationalite',
260 'date_naissance',
261 'lien_parente',
262 )}),
53ae644d
OL
263 )
264
265
45066657
EMS
266class AyantDroitCommentaireInline(admin.TabularInline):
267 readonly_fields = ('owner',)
53ae644d
OL
268 model = rh.AyantDroitCommentaire
269 extra = 1
45066657 270 form = CommentaireInlineForm
53ae644d
OL
271
272
45066657 273class ContratInline(admin.TabularInline):
53ae644d
OL
274 form = ContratForm
275 model = rh.Contrat
276 extra = 1
277
278
340307bd
OL
279class DossierROInline(ReadOnlyInlineMixin, LinkedInline):
280 template = "admin/rh/dossier/linked.html"
281 model = rh.Dossier
282 extra = 0
283 can_delete = False
eadfe123 284 fields = ('poste', 'date_debut', 'date_fin', )
340307bd
OL
285
286 def has_add_permission(self, request=None):
287 return False
288
289 def has_change_permission(self, request, obj=None):
290 return False
291
292 def has_delete_permission(self, request, obj=None):
293 return False
294
295
45066657
EMS
296class DossierCommentaireInline(admin.TabularInline):
297 readonly_fields = ('owner',)
53ae644d
OL
298 model = rh.DossierCommentaire
299 extra = 1
45066657 300 form = CommentaireInlineForm
53ae644d
OL
301
302
303class DossierPieceInline(admin.TabularInline):
304 model = rh.DossierPiece
305 extra = 4
306
307
308class EmployeInline(admin.TabularInline):
309 model = rh.Employe
310
22343fe7 311
45066657
EMS
312class EmployeCommentaireInline(admin.TabularInline):
313 readonly_fields = ('owner',)
53ae644d
OL
314 model = rh.EmployeCommentaire
315 extra = 1
45066657 316 form = CommentaireInlineForm
53ae644d
OL
317
318
319class EmployePieceInline(admin.TabularInline):
320 model = rh.EmployePiece
321 extra = 4
322
323
45066657
EMS
324class PosteCommentaireInline(admin.TabularInline):
325 readonly_fields = ('owner',)
53ae644d
OL
326 model = rh.PosteCommentaire
327 extra = 1
45066657 328 form = CommentaireInlineForm
53ae644d
OL
329
330
331class PosteFinancementInline(admin.TabularInline):
332 model = rh.PosteFinancement
333
334
335class PostePieceInline(admin.TabularInline):
336 model = rh.PostePiece
337
338
45066657 339class RemunerationInline(admin.TabularInline):
53ae644d
OL
340 model = rh.Remuneration
341 extra = 1
342
343
344class RemunerationROInline(ReadOnlyInlineMixin, RemunerationInline):
345 pass
346
347
45066657 348class TypePosteInline(admin.TabularInline):
53ae644d
OL
349 model = rh.TypePoste
350
351
45066657 352class PosteComparaisonInline(admin.TabularInline):
6f037929
OL
353 model = rh.PosteComparaison
354
53ae644d 355
15659516
BS
356class ClassementAdmin(reversion.VersionAdmin,
357 ArchivableAdmin,
358 DerniereModificationAdmin,
45066657
EMS
359 BaseAdmin):
360 ignore_duplicate_revisions = True
15659516
BS
361 list_display = ('_classement', 'derniere_modification', '_archive')
362 list_filter = ('archive', )
45066657 363 fieldsets = (
15659516
BS
364 (None, {'fields': (
365 'type', 'echelon',
366 'degre', 'coefficient', 'archive')}),
53ae644d
OL
367 )
368
c5964dc2
OL
369 def _classement(self, obj):
370 return unicode(obj)
371 _classement.short_description = u"Classement"
53ae644d 372
d104b0ae 373
7013d234 374class DeviseAdmin(reversion.VersionAdmin, ArchivableAdmin,
45066657
EMS
375 DerniereModificationAdmin, BaseAdmin):
376 ignore_duplicate_revisions = True
22343fe7 377 list_display = (
45066657
EMS
378 'code', 'nom', '_archive', 'derniere_modification',
379 )
edb35076 380 list_filter = ('archive', )
45066657
EMS
381 fieldsets = (
382 (None, {'fields': ('code', 'nom', 'archive', )}),
53ae644d
OL
383 )
384
22343fe7 385
45066657
EMS
386class DossierAdmin(DateRangeMixin, ProtectRegionMixin, reversion.VersionAdmin,
387 AjaxSelect, DerniereModificationAdmin, BaseAdmin):
b2d1cc93 388 change_list_template = "admin/rh/dossier/change_list.html"
45066657 389 ignore_duplicate_revisions = True
53ae644d 390 alphabet_filter = 'employe__nom'
22343fe7 391 search_fields = (
35cff4a7
EMS
392 'id',
393 'employe__id',
394 'poste__id',
395 'employe__nom',
396 'employe__prenom',
397 'poste__nom',
398 'poste__nom_feminin',
399 'poste__implantation__nom',
400 )
53ae644d
OL
401 list_display = (
402 '_id',
e49ac947
JPC
403 '_apercu',
404 '_nom',
53ae644d 405 '_employe',
5db1c5a3 406 '_poste',
b0cf30b8 407 '_zone_administrative',
5db1c5a3 408 '_implantation',
53ae644d
OL
409 '_date_debut',
410 '_date_fin',
45066657 411 'derniere_modification',
a47ed016 412 '_dae',
53ae644d 413 )
e49ac947 414 list_display_links = ('_nom',)
53ae644d 415 list_filter = (
b0cf30b8 416 'poste__implantation__zone_administrative',
53ae644d 417 'poste__implantation',
7bf28694 418 'poste__type_poste__categorie_emploi',
7baa5523 419 'poste__type_poste',
53ae644d 420 'rh_contrats__type_contrat',
6bee05ff 421 'principal',
53ae644d
OL
422 )
423 inlines = (DossierPieceInline, ContratInline,
424 RemunerationInline,
53ae644d
OL
425 DossierCommentaireInline,
426 )
45066657 427 fieldsets = (
53ae644d 428 (None, {
22343fe7
OL
429 'fields': (
430 'employe',
431 'poste',
6bee05ff 432 'principal',
84934747 433 'est_cadre',
22343fe7
OL
434 'statut',
435 'organisme_bstg',)}),
53ae644d 436 ('Recrutement', {
22343fe7
OL
437 'fields': (
438 'statut_residence',
439 'remplacement',
440 'remplacement_de', )}),
53ae644d 441 ('Rémunération', {
22343fe7
OL
442 'fields': (
443 'classement',
444 ('regime_travail', 'regime_travail_nb_heure_semaine'),)}),
53ae644d 445 ('Occupation du Poste par cet Employe', {
22343fe7
OL
446 'fields': (('date_debut', 'date_fin'), )}
447 ),
53ae644d 448 )
22343fe7
OL
449 form = make_ajax_form(rh.Dossier, {
450 'employe': 'employes',
451 'poste': 'postes',
452 'remplacement_de': 'dossiers',
6bee05ff 453 }, superclass=DossierForm)
53ae644d
OL
454
455 def lookup_allowed(self, key, value):
456 if key in (
457 'employe__nom__istartswith',
b0cf30b8 458 'poste__implantation__zone_administrative__code__exact',
e8b6a20c 459 'poste__implantation__zone_administrative__in',
53ae644d
OL
460 'poste__implantation__id__exact',
461 'poste__type_poste__id__exact',
7bf28694 462 'poste__type_poste__categorie_emploi__id__exact',
53ae644d 463 'rh_contrats__type_contrat__id__exact',
6bee05ff
OL
464 'principal__exact',
465 'principal__isnull',
53ae644d
OL
466 ):
467 return True
468
e49ac947
JPC
469 def _id(self, obj):
470 return obj.id
471 _id.short_description = u"#"
472 _id.admin_order_field = "id"
473
e49ac947 474 def _apercu(self, d):
22343fe7
OL
475 apercu_link = u"""<a title="Aperçu du dossier"
476 onclick="return showAddAnotherPopup(this);"
477 href='%s'>
9533bd15 478 <img src="%simg/dossier-apercu.png" />
22343fe7 479 </a>""" % \
b10920ea 480 (reverse('dossier_apercu', args=(d.id,)),
822a2c33 481 settings.STATIC_URL,
b10920ea 482 )
e49ac947
JPC
483 return apercu_link
484 _apercu.allow_tags = True
485 _apercu.short_description = u""
53ae644d 486
5db1c5a3
DB
487 def _nom(self, obj):
488 return "Dossier"
489 _nom.allow_tags = True
490 _nom.short_description = u"Dossier"
53ae644d 491
5db1c5a3
DB
492 def _employe(self, obj):
493 employe = obj.employe
494 view_link = reverse('employe_apercu', args=(employe.id,))
495 edit_link = reverse('admin:rh_employe_change', args=(employe.id,))
5db1c5a3
DB
496 style = ""
497 view = u"""<a href="%s"
498 title="Aperçu l'employé"
499 onclick="return showAddAnotherPopup(this);">
500 <img src="%simg/employe-apercu.png" />
501 </a>""" % (view_link, settings.STATIC_URL,)
502 return u"""%s<a href='%s' style="%s;">%s</a>""" % \
503 (view, edit_link, style, employe)
504 _employe.allow_tags = True
505 _employe.short_description = u"Employé"
506 _employe.admin_order_field = "employe__nom"
53ae644d
OL
507
508 def _poste(self, dossier):
22343fe7
OL
509 link = u"""<a title="Aperçu du poste"
510 onclick="return showAddAnotherPopup(this);"
9533bd15 511 href='%s'><img src="%simg/poste-apercu.png" />
22343fe7 512 </a>
5db1c5a3 513 <a href="%s" title="Modifier le poste">%s [%d]</a>""" % \
53ae644d 514 (reverse('poste_apercu', args=(dossier.poste.id,)),
822a2c33 515 settings.STATIC_URL,
211a0e56 516 reverse('admin:rh_poste_change', args=(dossier.poste.id,)),
5db1c5a3
DB
517 dossier.poste.nom,
518 dossier.poste.id,
53ae644d
OL
519 )
520 return link
521 _poste.allow_tags = True
522 _poste.short_description = u'Poste'
523 _poste.admin_order_field = 'poste__nom'
524
b0cf30b8
EMS
525 def _zone_administrative(self, obj):
526 return obj.poste.implantation.zone_administrative.code
527 _zone_administrative.short_description = u"Zone administrative"
90440a65
EMS
528 _zone_administrative.admin_order_field = \
529 'poste__implantation__zone_administrative__code'
53ae644d 530
5db1c5a3
DB
531 def _implantation(self, obj):
532 return obj.poste.implantation.nom
533 _implantation.short_description = u"Implantation"
534 _implantation.admin_order_field = 'poste__implantation__nom'
535
536 def _date_debut(self, obj):
537 return date(obj.date_debut)
538
539 _date_debut.short_description = u'Début'
540 _date_debut.admin_order_field = 'date_debut'
541
542 def _date_fin(self, obj):
543 return date(obj.date_fin)
544 _date_fin.short_description = u'Fin'
545 _date_fin.admin_order_field = 'date_fin'
546
547 def _date_modification(self, obj):
548 return date(obj.date_modification) \
549 if obj.date_modification is not None else "(aucune)"
550 _date_modification.short_description = u'date modification'
551 _date_modification.admin_order_field = 'date_modification'
552
553 def _dae(self, d):
554 apercu_link = ""
555 dossiers_dae = d.dossiers_dae.all()
556 if len(dossiers_dae) > 0:
557 dossier_dae = dossiers_dae[0]
558 apercu_link = u"""<a title="Aperçu du dossier"
559 onclick="return showAddAnotherPopup(this);"
560 href='%s'>
561 <img src="%simg/loupe.png" />
562 </a>""" % \
563 (reverse('embauche_consulter', args=(dossier_dae.id,)),
564 settings.STATIC_URL,
565 )
566 return apercu_link
567 _dae.allow_tags = True
568 _dae.short_description = u"DAE"
22343fe7 569
53ae644d
OL
570 def save_formset(self, request, form, formset, change):
571 instances = formset.save(commit=False)
572 for instance in instances:
573 if instance.__class__ == rh.DossierCommentaire:
574 instance.owner = request.user
02e69aa2 575 instance.date_creation = datetime.datetime.now()
53ae644d
OL
576 instance.save()
577
578
45066657
EMS
579class EmployeAdminBase(DateRangeMixin, ProtectRegionMixin,
580 DerniereModificationAdmin, BaseAdmin):
7eb6b687 581 prefixe_recherche_temporelle = "rh_dossiers__"
53ae644d
OL
582 alphabet_filter = 'nom'
583 DEFAULT_ALPHABET = u'ABCDEFGHIJKLMNOPQRSTUVWXYZ'
e23da9c3
EMS
584 search_fields = (
585 'id', 'nom', 'prenom', 'nom_affichage',
586 'rh_dossiers__poste__nom',
587 'rh_dossiers__poste__nom_feminin'
588 )
53ae644d
OL
589 ordering = ('nom', )
590 form = EmployeAdminForm
22343fe7 591 list_display = (
f80b83c6 592 '_id', '_apercu', '_nom', '_dossiers_postes',
b0cf30b8 593 #'_zone_administrative',
f80b83c6
OL
594 #'_implantation',
595 'date_entree',
45066657
EMS
596 'derniere_modification'
597 )
e49ac947 598 list_display_links = ('_nom',)
22343fe7 599 list_filter = (
b0cf30b8 600 'rh_dossiers__poste__implantation__zone_administrative',
45066657
EMS
601 'rh_dossiers__poste__implantation', 'nb_postes'
602 )
603 inlines = (
340307bd 604 AyantDroitInline, DossierROInline, EmployePieceInline,
45066657
EMS
605 EmployeCommentaireInline
606 )
607 fieldsets = (
53ae644d 608 ('Identification', {
22343fe7
OL
609 'fields': (
610 ('nom', 'prenom'),
611 ('nom_affichage', 'genre'),
612 'nationalite',
613 'date_naissance',
45066657
EMS
614 )
615 }),
53ae644d 616 ('Informations personnelles', {
45066657
EMS
617 'fields': ('situation_famille', 'date_entree', )
618 }),
89a8df07 619 ('Coordonnées personnelles', {
22343fe7
OL
620 'fields': (
621 ('tel_domicile', 'tel_cellulaire'),
622 ('adresse', 'ville'),
623 ('code_postal', 'province'),
624 'pays',
89a8df07 625 'courriel_perso'
45066657
EMS
626 )
627 }),
628 )
53ae644d 629
5db1c5a3
DB
630 def _id(self, obj):
631 return obj.id
632 _id.short_description = u"#"
633 _id.admin_order_field = "id"
634
b10920ea 635 def _apercu(self, obj):
22343fe7
OL
636 return u"""<a title="Aperçu de l'employé"
637 onclick="return showAddAnotherPopup(this);"
638 href='%s'>
9533bd15 639 <img src="%simg/employe-apercu.png" />
22343fe7
OL
640 </a>""" % \
641 (reverse('employe_apercu', args=(obj.id,)), settings.STATIC_URL)
b10920ea
JPC
642 _apercu.allow_tags = True
643 _apercu.short_description = u""
b10920ea 644
53ae644d 645 def _nom(self, obj):
53ae644d 646 edit_link = reverse('admin:rh_employe_change', args=(obj.id,))
e6c107de 647 return u"""<a href='%s'><strong>%s</strong></a>""" % \
e49ac947 648 (edit_link, "%s %s" % (obj.nom.upper(), obj.prenom))
53ae644d 649 _nom.allow_tags = True
e49ac947 650 _nom.short_description = u"Employé"
53ae644d
OL
651 _nom.admin_order_field = "nom"
652
b0cf30b8 653 def _zone_administrative(self, obj):
5db1c5a3
DB
654 try:
655 d = rh.Dossier.objects.filter(employe=obj.id, principal=True)[0]
b0cf30b8 656 zone = d.poste.implantation.zone_administrative.code
5db1c5a3 657 except:
b0cf30b8
EMS
658 zone = None
659 return zone
660 _zone_administrative.short_description = u"Zone administrative"
e49ac947 661
5db1c5a3
DB
662 def _implantation(self, obj):
663 try:
664 d = rh.Dossier.objects.filter(employe=obj.id, principal=True)[0]
665 implantation = d.poste.implantation.nom
666 except:
667 implantation = None
668 return implantation
669 _implantation.short_description = u"Implantation"
33232787 670
a7f013f5 671 def _dossiers_postes(self, obj):
53ae644d
OL
672 l = []
673 for d in obj.rh_dossiers.all().order_by('-date_debut'):
5db1c5a3
DB
674 link_style = u''
675 list_style = u''
676 if d.date_fin is not None and d.date_fin < datetime.date.today():
5db1c5a3
DB
677 link_style = u' style="color:#666;"'
678 list_style = u' style="color:grey;"'
08ecf07e 679
22343fe7
OL
680 dossier = u"""<a title="Aperçu du dossier"
681 href="%s"
682 onclick="return showAddAnotherPopup(this);"
683 title="Aperçu du dossier">
9533bd15 684 <img src="%simg/dossier-apercu.png" />
22343fe7 685 </a>
5db1c5a3 686 <a href="%s"%s>Dossier</a>
22343fe7
OL
687 &nbsp;""" % \
688 (reverse('dossier_apercu', args=(d.id,)),
689 settings.STATIC_URL,
5db1c5a3
DB
690 reverse('admin:rh_dossier_change', args=(d.id,)),
691 link_style,)
22343fe7
OL
692
693 poste = u"""<a title="Aperçu du poste"
694 href="%s"
695 onclick="return showAddAnotherPopup(this);"
696 title="Aperçu du poste">
9533bd15 697 <img src="%simg/poste-apercu.png" />
22343fe7 698 </a>
5db1c5a3 699 <a href="%s"%s>%s [%d]</a>
22343fe7
OL
700 &nbsp;""" % \
701 (reverse('poste_apercu', args=(d.poste.id,)),
702 settings.STATIC_URL,
5db1c5a3
DB
703 reverse('admin:rh_poste_change', args=(d.poste.id,)),
704 link_style,
a7f013f5 705 d.poste.nom,
5db1c5a3 706 d.poste.id)
b5cc0357 707
5db1c5a3
DB
708 link = u"""<li%s>%s %s</li>""" % \
709 (list_style, dossier, poste)
b5cc0357 710
53ae644d
OL
711 l.append(link)
712 return "<ul>%s</ul>" % "\n".join(l)
a7f013f5
JPC
713 _dossiers_postes.allow_tags = True
714 _dossiers_postes.short_description = u"Dossiers et postes"
53ae644d 715
5db1c5a3
DB
716 def _date_modification(self, obj):
717 return date(obj.date_modification) \
718 if obj.date_modification is not None else "(aucune)"
719 _date_modification.short_description = u'date modification'
720 _date_modification.admin_order_field = 'date_modification'
721
53ae644d 722 def queryset(self, request):
45066657 723 qs = super(EmployeAdminBase, self).queryset(request)
53ae644d
OL
724 return qs.select_related(depth=1).order_by('nom')
725
726 def save_formset(self, request, form, formset, change):
727 instances = formset.save(commit=False)
728 for instance in instances:
729 if instance.__class__ == rh.EmployeCommentaire:
730 instance.owner = request.user
02e69aa2 731 instance.date_creation = datetime.datetime.now()
53ae644d
OL
732 instance.save()
733
22343fe7 734
45066657 735class EmployeAdmin(reversion.VersionAdmin, EmployeAdminBase):
b2d1cc93 736 change_list_template = "admin/rh/employe/change_list.html"
45066657 737 ignore_duplicate_revisions = True
d104b0ae
EMS
738
739
45066657 740class EmployeProxyAdmin(EmployeAdminBase):
22343fe7 741 list_display = ('_id', '_apercu', '_nom', '_organigramme')
664bdc2f 742 list_per_page = 500
bd917a45
JPC
743 actions = None
744
745 def __init__(self, *args, **kwargs):
746 super(EmployeProxyAdmin, self).__init__(*args, **kwargs)
747 self.list_display_links = (None, )
08faf06e 748
8f7b2d7b
DB
749 def queryset(self, request):
750 qs = super(ProtectRegionMixin, self).queryset(request)
751
752 if in_drh_or_admin(request.user) or \
753 user_gere_obj_de_sa_region(request.user):
754 return qs
755
756 return qs.none()
757
22343fe7
OL
758 def has_add_permission(self, obj):
759 return False
760
c5dab350 761 def has_change_permission(self, request, obj=None):
3383b2d1
OL
762 user_groups = [g.name for g in request.user.groups.all()]
763 if groups.CORRESPONDANT_RH in user_groups or \
764 groups.ADMINISTRATEURS in user_groups or \
765 groups.DIRECTEUR_DE_BUREAU in user_groups or \
c5dab350
OL
766 in_drh_or_admin(request.user):
767 return True
768 return False
769
08faf06e
JPC
770 def _organigramme(self, obj):
771 l = []
fc4bf968
EMS
772 for d in rh.Dossier.objects.filter(
773 Q(date_fin__gt=datetime.date.today()) | Q(date_fin=None),
774 Q(date_debut__lt=datetime.date.today()) | Q(date_debut=None),
775 employe=obj.id
776 ):
777 organigramme = \
778 u'Organigramme, niveau: ' \
779 u'<input type="text" id="level_%s" ' \
780 u'style="width:30px;height:15px;" /> ' \
781 u'<input type="button" value="Générer" ' \
782 u"""onclick="window.location='%s' + """ \
783 u"""document.getElementById('level_%s').value" />""" % (
784 d.poste.id,
785 reverse('rho_employe_sans_niveau', args=(d.poste.id,)),
786 d.poste.id
787 )
e4fa851f 788 link = u"""<li>%s [%s]:<br />%s</li>""" % (
fc4bf968 789 d.poste.nom,
e4fa851f 790 d.poste.id,
fc4bf968
EMS
791 organigramme
792 )
08faf06e
JPC
793 l.append(link)
794 return "<ul>%s</ul>" % "\n".join(l)
795
796 _organigramme.allow_tags = True
797 _organigramme.short_description = "Organigramme"
798
53ae644d 799
45066657
EMS
800class CategorieEmploiAdmin(reversion.VersionAdmin,
801 DerniereModificationAdmin, BaseAdmin):
802 ignore_duplicate_revisions = True
803 list_display = ('nom', 'derniere_modification')
53ae644d 804 inlines = (TypePosteInline,)
45066657
EMS
805 fieldsets = (
806 (None, {'fields': ('nom', )}),
807 )
53ae644d 808
22343fe7 809
45066657 810class OrganismeBstgAdmin(reversion.VersionAdmin, DerniereModificationAdmin,
d104b0ae 811 BaseAdmin):
45066657 812 ignore_duplicate_revisions = True
c5964dc2 813 search_fields = ('nom',)
45066657 814 list_display = ('nom', 'type', 'pays', 'derniere_modification')
c5964dc2 815 list_filter = ('type', )
340307bd 816 inlines = (DossierROInline,)
45066657 817 fieldsets = (
22343fe7 818 (None, {'fields': ('nom', 'type', 'pays',)}),
45066657 819 )
33232787 820
53ae644d 821
45066657
EMS
822class PosteAdmin(DateRangeMixin, ProtectRegionMixin, reversion.VersionAdmin,
823 AjaxSelect, DerniereModificationAdmin, BaseAdmin):
b2d1cc93 824 change_list_template = "admin/rh/poste/change_list.html"
45066657 825 ignore_duplicate_revisions = True
22343fe7
OL
826 form = make_ajax_form(rh.Poste, {
827 'implantation': 'implantations',
828 'type_poste': 'typepostes',
829 'responsable': 'postes',
830 'valeur_point_min': 'valeurpoints',
831 'valeur_point_max': 'valeurpoints',
53ae644d
OL
832 })
833 alphabet_filter = 'nom'
22343fe7 834 search_fields = (
45066657
EMS
835 'id',
836 'nom',
837 'implantation__nom',
b0cf30b8
EMS
838 'implantation__zone_administrative__code',
839 'implantation__zone_administrative__nom',
45066657
EMS
840 'rh_dossiers__employe__id',
841 'rh_dossiers__employe__nom',
842 'rh_dossiers__employe__prenom',
843 )
53ae644d 844 list_display = (
45066657
EMS
845 '_id', '_apercu', '_nom', '_occupe_par', 'implantation', '_service',
846 '_responsable', 'date_debut', 'date_fin', 'derniere_modification',
847 '_dae'
848 )
f614ca5c 849 list_filter = (
b0cf30b8 850 'implantation__zone_administrative',
53ae644d 851 'implantation',
22343fe7 852 'service',
53ae644d 853 'type_poste',
7bf28694 854 'type_poste__categorie_emploi',
118efe7a 855 'type_poste__famille_professionnelle',
4c53dda4 856 'vacant',
45066657 857 )
e49ac947 858 list_display_links = ('_nom',)
45066657 859 fieldsets = (
22343fe7
OL
860 (None, {'fields': (
861 ('nom', 'nom_feminin'),
862 'implantation',
863 'type_poste',
864 'service',
865 'responsable',
866 )}
867 ),
53ae644d 868 ('Contrat', {
22343fe7
OL
869 'fields': ((
870 'regime_travail',
871 'regime_travail_nb_heure_semaine'),
872 )}
873 ),
53ae644d 874 ('Recrutement', {
22343fe7
OL
875 'fields': (('local', 'expatrie', 'mise_a_disposition', 'appel'),)}
876 ),
53ae644d 877 ('Rémunération', {
22343fe7
OL
878 'fields': (('classement_min',
879 'valeur_point_min',
880 'devise_min',
881 'salaire_min',
882 'indemn_min',
883 'autre_min',),
884 ('classement_max',
885 'valeur_point_max',
886 'devise_max',
887 'salaire_max',
888 'indemn_max',
889 'autre_max',),
890 )}),
53ae644d
OL
891 ('Comparatifs de rémunération', {
892 'fields': ('devise_comparaison',
893 ('comp_locale_min', 'comp_locale_max'),
894 ('comp_universite_min', 'comp_universite_max'),
895 ('comp_fonctionpub_min', 'comp_fonctionpub_max'),
896 ('comp_ong_min', 'comp_ong_max'),
22343fe7
OL
897 ('comp_autre_min', 'comp_autre_max'))}
898 ),
53ae644d 899 ('Justification', {
22343fe7
OL
900 'fields': ('justification',)}
901 ),
48a6df80 902 ('Autres Méta-données', {
22343fe7
OL
903 'fields': ('date_debut', 'date_fin')}
904 ),
53ae644d
OL
905 )
906
907 inlines = (PosteFinancementInline,
908 PostePieceInline,
340307bd 909 DossierROInline,
6f037929 910 PosteComparaisonInline,
53ae644d
OL
911 PosteCommentaireInline, )
912
f614ca5c 913 def lookup_allowed(self, key, value):
118efe7a
EMS
914 return key in (
915 'date_debut__gte', 'date_debut__isnull', 'date_fin__lte',
90440a65
EMS
916 'date_fin__isnull',
917 'implantation__zone_administrative__code__exact',
118efe7a
EMS
918 'implantation__id__exact', 'type_poste__id__exact',
919 'type_poste__categorie_emploi__id__exact', 'service__id__exact',
90440a65 920 'service__isnull', 'vacant__exact', 'vacant__isnull'
118efe7a 921 ) or super(PosteAdmin, self).lookup_allowed(key, value)
f614ca5c 922
5db1c5a3
DB
923 def _id(self, obj):
924 return "%s" % obj.id
925 _id.short_description = '#'
926 _id.admin_order_field = 'id'
927
8f3ca727 928 def _apercu(self, poste):
22343fe7
OL
929 view_link = u"""<a onclick="return showAddAnotherPopup(this);"
930 title="Aperçu du poste"
931 href='%s'>
9533bd15 932 <img src="%simg/poste-apercu.png" />
22343fe7 933 </a>""" % \
8f3ca727 934 (reverse('poste_apercu', args=(poste.id,)),
22343fe7
OL
935 settings.STATIC_URL,)
936 return view_link
8f3ca727 937 _apercu.allow_tags = True
e49ac947
JPC
938 _apercu.short_description = ''
939
5db1c5a3
DB
940 def _nom(self, poste):
941 return """<a href="%s">%s</a>""" % \
942 (reverse('admin:rh_poste_change', args=(poste.id,)),
943 poste.nom)
944 _nom.allow_tags = True
945 _nom.short_description = u'Poste'
946 _nom.admin_order_field = 'nom'
a47ed016 947
5db1c5a3
DB
948 def _occupe_par(self, obj):
949 """Formatte la méthode Poste.occupe_par() pour l'admin"""
950 output = u"Vacant"
951 if obj.date_fin is not None and obj.date_fin < datetime.date.today():
952 return u"s/o"
953 employes = obj.occupe_par()
954 if employes:
955 l = []
956 for e in employes:
957 link = u"""<a href='%s'
958 title='Aperçu de l\'employé'
959 onclick='return showAddAnotherPopup(this)'>
960 <img src='%simg/employe-apercu.png' />
961 </a>
962 <a href='%s'>%s</a>""" % \
963 (reverse('employe_apercu', args=(e.id,)),
964 settings.STATIC_URL,
965 reverse('admin:rh_employe_change', args=(e.id,)),
966 e)
967 l.append(link)
968 output = "\n<br />".join(l)
969 return output
970 _occupe_par.allow_tags = True
971 _occupe_par.short_description = "Occupé par"
972
b0cf30b8
EMS
973 def _zone_administrative(self, poste):
974 return poste.implantation.zone_administrative.code
975 _zone_administrative.short_description = 'Zone administrative'
90440a65
EMS
976 _zone_administrative.admin_order_field = \
977 'implantation__zone_administrative__code'
5db1c5a3
DB
978
979 def _implantation(self, poste):
980 return poste.implantation.nom
981 _implantation.short_description = 'Implantation'
982 _implantation.admin_order_field = 'implantation'
8f3ca727 983
c5964dc2 984 def _service(self, obj):
45066657 985 return obj.service
6c2b1160 986 _service.short_description = 'Service'
1b130b25 987 _service.allow_tags = True
53ae644d 988
1ce2ddb9
JPC
989 def _responsable(self, obj):
990 try:
22343fe7
OL
991 responsable = u"""<a href="%s"
992 onclick="return showAddAnotherPopup(this)">
9533bd15 993 <img src="%simg/poste-apercu.png"
22343fe7
OL
994 title="Aperçu du poste" />
995 </a>
5db1c5a3 996 <a href="%s">%s [%d]</a>
22343fe7
OL
997 <br />""" % \
998 (reverse('poste_apercu', args=(obj.responsable.id,)),
999 settings.STATIC_URL,
1000 reverse('admin:rh_poste_change', args=(obj.responsable.id,)),
5db1c5a3
DB
1001 obj.responsable.nom,
1002 obj.responsable.id)
1ce2ddb9
JPC
1003 except:
1004 responsable = ''
1005
1006 try:
d104b0ae
EMS
1007 dossier = obj.responsable.rh_dossiers.all() \
1008 .order_by('-date_debut')[0]
60f34330 1009 employe_id = dossier.employe.id
fc4bf968 1010 employe_html = u"""<br />
22343fe7
OL
1011 <a href="%s"
1012 onclick="return showAddAnotherPopup(this)">
9533bd15 1013 <img src="%simg/employe-apercu.png"
22343fe7
OL
1014 title="Aperçu de l'employé">
1015 </a>
1016 <a href="%s">%s</a>""" % \
1017 (reverse('employe_apercu', args=(employe_id,)),
1018 settings.STATIC_URL,
1019 reverse('admin:rh_employe_change', args=(employe_id,)),
60f34330 1020 dossier.employe)
1ce2ddb9 1021 except:
fc4bf968 1022 employe_html = ""
1ce2ddb9 1023
fc4bf968 1024 return "%s %s" % (responsable, employe_html)
1ce2ddb9
JPC
1025 _responsable.short_description = 'Responsable'
1026 _responsable.allow_tags = True
1027
5db1c5a3
DB
1028 def _date_debut(self, obj):
1029 return date_format(obj.date_debut)
1030 _date_debut.short_description = u'Début'
1031 _date_debut.admin_order_field = 'date_debut'
f3e3ac6f 1032
5db1c5a3
DB
1033 def _date_fin(self, obj):
1034 return date_format(obj.date_fin)
1035 _date_fin.short_description = u'Fin'
1036 _date_fin.admin_order_field = 'date_fin'
53ae644d 1037
5db1c5a3
DB
1038 def _dae(self, poste):
1039 apercu_link = ""
1040 postes_dae = poste.postes_dae.all()
1041 if len(postes_dae) > 0:
1042 poste_dae = postes_dae[0]
1043 apercu_link = \
1044 u'<a title="Aperçu du dossier" href="%s" ' \
1045 u'onclick="return showAddAnotherPopup(this);">' \
1046 u'<img src="%simg/loupe.png" /></a>' % (reverse(
1047 'poste_consulter', args=("dae-%s" % poste_dae.id,)
1048 ), settings.STATIC_URL)
1049 return apercu_link
1050 _dae.allow_tags = True
1051 _dae.short_description = u"DAE"
53ae644d
OL
1052
1053 def save_formset(self, request, form, formset, change):
1054 instances = formset.save(commit=False)
1055 for instance in instances:
1056 if instance.__class__ == rh.PosteCommentaire:
1057 instance.owner = request.user
02e69aa2 1058 instance.date_creation = datetime.datetime.now()
53ae644d
OL
1059 instance.save()
1060 formset.save_m2m()
1061
1062
8c8ffc4f
OL
1063class ResponsableInline(admin.TabularInline):
1064 model = rh.ResponsableImplantation
1065 extra = 0
fc4bf968 1066 fk_name = "implantation"
6fb68b2f 1067 form = ResponsableInlineForm
fc4bf968 1068
22343fe7 1069
08a9b6fc 1070class ResponsableImplantationAdmin(BaseAdmin):
8c8ffc4f 1071 actions = None
6fb68b2f
DB
1072 fields = ('nom', )
1073 inlines = (ResponsableInline, )
b0cf30b8
EMS
1074 list_filter = ('zone_administrative', 'statut', )
1075 list_display = ('_zone_administrative', '_nom', 'statut', '_responsable', )
6fb68b2f 1076 list_display_links = ('_nom',)
664bdc2f 1077 list_per_page = 500
8c8ffc4f 1078 readonly_fields = ('nom', )
6fb68b2f
DB
1079 search_fields = (
1080 'nom',
1081 'responsable__employe__id',
1082 'responsable__employe__nom',
1083 'responsable__employe__prenom',
1084 )
1085 ordering = ('nom',)
8c8ffc4f 1086 inlines = (ResponsableInline, )
d104b0ae 1087
b0cf30b8
EMS
1088 def _zone_administrative(self, obj):
1089 return obj.zone_administrative.code
1090 _zone_administrative.short_description = u"Zone administrative"
1091 _zone_administrative.admin_order_field = 'zone_administrative__code'
d104b0ae 1092
30dabdc3
DB
1093 def _nom(self, obj):
1094 return obj.nom
1095 _nom.short_description = u"Implantation"
1096 _nom.admin_order_field = 'nom'
d104b0ae 1097
8c8ffc4f
OL
1098 def _responsable(self, obj):
1099 try:
da202402
OL
1100 employe = employe = obj.responsable.employe
1101 except Exception, e:
90440a65
EMS
1102 return (
1103 u"<span style='color: red;'>"
1104 u"Pas de responsable</span><!-- %s -->" % e
1105 )
da202402 1106 try:
8c8ffc4f
OL
1107 dossiers = employe.dossiers_encours()
1108 if len(dossiers) == 0:
1109 return u"<span style='color: red;'>%s %s </span>" % (
1110 employe, u"sans dossier actif")
1111 else:
1112 return employe
da202402
OL
1113 except Exception, e:
1114 return u"<!-- %s -->" % e
8c8ffc4f
OL
1115 _responsable.allow_tags = True
1116 _responsable.short_description = u"Responsable"
6fb68b2f 1117 _responsable.admin_order_field = 'responsable__employe__nom'
8c8ffc4f
OL
1118
1119 def has_add_permission(self, request=None):
1120 return False
1121
1122 def has_change_permission(self, request, obj=None):
1123 return in_drh_or_admin(request.user)
1124
1125 def has_delete_permission(self, request, obj=None):
1126 return False
53ae644d 1127
fc4bf968 1128
7013d234 1129class ServiceAdminBase(ArchivableAdmin, DerniereModificationAdmin, BaseAdmin):
45066657 1130 list_display = ('nom', '_archive', 'derniere_modification')
cbb0373e 1131 list_filter = ('archive', )
45066657
EMS
1132 fieldsets = (
1133 (None, {'fields': ('nom', 'archive')}),
1134 )
33232787 1135
fc4bf968 1136
45066657
EMS
1137class ServiceAdmin(reversion.VersionAdmin, ServiceAdminBase):
1138 ignore_duplicate_revisions = True
d104b0ae
EMS
1139
1140
45066657 1141class ServiceProxyAdmin(ServiceAdminBase):
cfd5ac68 1142 list_display = ('nom', '_organigramme', '_archive', )
8135fc65
JPC
1143 actions = None
1144
1145 def __init__(self, *args, **kwargs):
1146 super(ServiceProxyAdmin, self).__init__(*args, **kwargs)
1147 self.list_display_links = (None, )
5c0f1778 1148
f7badf51
EMS
1149 def queryset(self, request):
1150 return super(ServiceProxyAdmin, self).queryset(request) \
1151 .annotate(num_postes=Count('rh_postes')) \
1152 .filter(num_postes__gt=0)
1153
5c0f1778
JPC
1154 def has_add_permission(self, obj):
1155 return False
1156
aa2c508e 1157 def has_change_permission(self, request, obj=None):
3383b2d1
OL
1158 user_groups = [g.name for g in request.user.groups.all()]
1159 if groups.CORRESPONDANT_RH in user_groups or \
1160 groups.ADMINISTRATEURS in user_groups or \
1161 groups.DIRECTEUR_DE_BUREAU in user_groups or \
c5dab350
OL
1162 in_drh_or_admin(request.user):
1163 return True
1164 return False
aa2c508e 1165
5c0f1778 1166 def _organigramme(self, obj):
8135fc65
JPC
1167 return """<a href="%s"><strong>Organigramme</strong></a>""" % \
1168 (reverse('rho_service', args=(obj.id,)))
5c0f1778
JPC
1169 _organigramme.allow_tags = True
1170 _organigramme.short_description = "Organigramme"
1171
8135fc65 1172
15659516
BS
1173class StatutAdmin(reversion.VersionAdmin,
1174 ArchivableAdmin,
1175 DerniereModificationAdmin,
45066657
EMS
1176 BaseAdmin):
1177 ignore_duplicate_revisions = True
15659516
BS
1178 list_display = ('code', 'nom', 'derniere_modification', '_archive')
1179 list_filter = ('archive', )
45066657 1180 fieldsets = (
53ae644d 1181 (None, {
15659516 1182 'fields': ('code', 'nom', 'archive'),
53ae644d 1183 }),
45066657 1184 )
33232787 1185
22343fe7 1186
45066657
EMS
1187class TauxChangeAdmin(reversion.VersionAdmin, DerniereModificationAdmin,
1188 BaseAdmin):
1189 ignore_duplicate_revisions = True
1190 list_display = ('taux', 'devise', 'annee', 'derniere_modification')
1191 list_filter = ('devise',)
1192 fieldsets = (
53ae644d
OL
1193 (None, {
1194 'fields': ('taux', 'devise', 'annee', ),
1195 }),
45066657 1196 )
33232787 1197
22343fe7 1198
15659516
BS
1199class TypeContratAdmin(reversion.VersionAdmin,
1200 ArchivableAdmin,
1201 DerniereModificationAdmin,
45066657
EMS
1202 BaseAdmin):
1203 ignore_duplicate_revisions = True
15659516
BS
1204 list_display = ('nom', 'nom_long', 'derniere_modification', '_archive')
1205 list_filter = ('archive', )
45066657 1206 fieldsets = (
53ae644d 1207 (None, {
15659516 1208 'fields': ('nom', 'nom_long', 'archive'),
53ae644d 1209 }),
45066657 1210 )
33232787 1211
53ae644d 1212
15659516
BS
1213class TypePosteAdmin(reversion.VersionAdmin,
1214 ArchivableAdmin,
1215 DerniereModificationAdmin,
d104b0ae 1216 BaseAdmin):
45066657 1217 ignore_duplicate_revisions = True
53ae644d 1218 search_fields = ('nom', 'nom_feminin', )
15659516
BS
1219 list_display = ('nom', 'categorie_emploi',
1220 'derniere_modification', '_archive',)
1221 list_filter = ('categorie_emploi', 'famille_professionnelle', 'archive')
45066657 1222 fieldsets = (
53ae644d 1223 (None, {
22343fe7 1224 'fields': (
45066657 1225 'nom', 'nom_feminin', 'is_responsable', 'categorie_emploi',
321fe481 1226 'famille_professionnelle',
15659516 1227 'archive',
45066657
EMS
1228 )
1229 }),
1230 )
33232787 1231
53ae644d 1232
7013d234 1233class TypeRemunerationAdmin(reversion.VersionAdmin, ArchivableAdmin,
45066657
EMS
1234 DerniereModificationAdmin, BaseAdmin):
1235 ignore_duplicate_revisions = True
22343fe7 1236 list_display = (
45066657
EMS
1237 'nom', 'type_paiement', 'nature_remuneration', '_archive',
1238 'derniere_modification'
1239 )
7ba822a6 1240 list_filter = ('archive', )
45066657
EMS
1241 fieldsets = (
1242 (None, {
1243 'fields': (
1244 'nom', 'type_paiement', 'nature_remuneration', 'archive'
1245 )
1246 }),
1247 )
53ae644d 1248
53ae644d 1249
45066657 1250class TypeRevalorisationAdmin(reversion.VersionAdmin,
15659516
BS
1251 ArchivableAdmin,
1252 DerniereModificationAdmin,
1253 BaseAdmin):
45066657 1254 ignore_duplicate_revisions = True
15659516
BS
1255 list_display = ('nom', 'derniere_modification', '_archive')
1256 list_filter = ('archive', )
45066657 1257 fieldsets = (
15659516 1258 (None, {'fields': ('nom', 'archive')}),
45066657 1259 )
33232787 1260
53ae644d 1261
15659516
BS
1262class ValeurPointAdmin(reversion.VersionAdmin,
1263 DerniereModificationAdmin,
d104b0ae 1264 BaseAdmin):
45066657 1265 ignore_duplicate_revisions = True
22343fe7 1266 list_display = (
45066657
EMS
1267 '_devise_code', '_devise_nom', 'annee', 'implantation',
1268 'valeur', 'derniere_modification'
1269 )
b0cf30b8 1270 list_filter = ('annee', 'devise', 'implantation__zone_administrative', )
45066657
EMS
1271 fieldsets = (
1272 (None, {'fields': ('valeur', 'devise', 'implantation', 'annee')}),
1273 )
33232787 1274
866bba57
EMS
1275 def queryset(self, request):
1276 return super(ValeurPointAdmin, self).queryset(request) \
1277 .select_related('devise', 'implantation')
1278
53ae644d
OL
1279 def _devise_code(self, obj):
1280 return obj.devise.code
1281 _devise_code.short_description = "Code de la devise"
1282
1283 def _devise_nom(self, obj):
1284 return obj.devise.nom
1285 _devise_nom.short_description = "Nom de la devise"
1286
fc4bf968 1287
08a9b6fc 1288class ImplantationProxyAdmin(BaseAdmin):
82af5c19 1289 list_display = ('nom', '_organigramme')
8135fc65
JPC
1290 actions = None
1291
1292 def __init__(self, *args, **kwargs):
1293 super(ImplantationProxyAdmin, self).__init__(*args, **kwargs)
1294 self.list_display_links = (None, )
82af5c19
JPC
1295
1296 def has_add_permission(self, obj):
1297 return False
1298
aa2c508e 1299 def has_change_permission(self, request, obj=None):
3383b2d1
OL
1300 user_groups = [g.name for g in request.user.groups.all()]
1301 if groups.CORRESPONDANT_RH in user_groups or \
1302 groups.ADMINISTRATEURS in user_groups or \
1303 groups.DIRECTEUR_DE_BUREAU in user_groups or \
c5dab350
OL
1304 in_drh_or_admin(request.user):
1305 return True
1306 return False
aa2c508e 1307
82af5c19 1308 def _organigramme(self, obj):
fc4bf968
EMS
1309 return '<a href="%s"><strong>Organigramme</strong></a>' % (
1310 reverse('rho_implantation', args=(obj.id,))
1311 )
82af5c19
JPC
1312 _organigramme.allow_tags = True
1313 _organigramme.short_description = "Organigramme"
1314
fc4bf968 1315
08a9b6fc 1316class RegionProxyAdmin(BaseAdmin):
9da4c195 1317 list_display = ('nom', '_organigramme')
8135fc65
JPC
1318 actions = None
1319
1320 def __init__(self, *args, **kwargs):
1321 super(RegionProxyAdmin, self).__init__(*args, **kwargs)
1322 self.list_display_links = (None, )
9da4c195
JPC
1323
1324 def has_add_permission(self, obj):
1325 return False
1326
aa2c508e 1327 def has_change_permission(self, request, obj=None):
3383b2d1
OL
1328 user_groups = [g.name for g in request.user.groups.all()]
1329 if groups.CORRESPONDANT_RH in user_groups or \
1330 groups.ADMINISTRATEURS in user_groups or \
1331 groups.DIRECTEUR_DE_BUREAU in user_groups or \
c5dab350
OL
1332 in_drh_or_admin(request.user):
1333 return True
1334 return False
aa2c508e 1335
9da4c195 1336 def _organigramme(self, obj):
fc4bf968
EMS
1337 return """<a href="%s"><strong>Organigramme</strong></a>""" % (
1338 reverse('rho_region', args=(obj.id,))
1339 )
9da4c195
JPC
1340 _organigramme.allow_tags = True
1341 _organigramme.short_description = "Organigramme"
1342
1343
e8b6a20c
BS
1344class ProfileInline(admin.StackedInline):
1345 model = rh.UserProfile
1346
1347
1348class RHUserAdmin(UserAdmin):
1349 inlines = list(UserAdmin.inlines) + [ProfileInline]
1350
1351
343cfd9c
BS
1352def _invalidate(modaladmin, req, qs):
1353 qs.update(valide=False)
1354_invalidate.short_description = 'Invalider'
1355
1356
1357def _communique(modaladmin, req, qs):
1358 url_prefix = ('https://' if req.is_secure() else 'http://') + (
1359 req.META['SERVER_NAME'] if 'SERVER_NAME' in req.META else
1360 'localhost') + (':%s' % (req.META['SERVER_PORT']) if 'SERVER_PORT'
1361 in req.META else '')
1362
1363 types = [x[0] for x in rh.TYPES_CHANGEMENT]
1364
1365 # make a list of all possible email types. It is reversed so that
1366 # we start with the largest combinations.
1367 combs = list(itertools.chain(*map(
1368 lambda x: itertools.combinations(types, x),
1369 range(1, len(types)+1))))
1370
1371 combs = reversed(combs)
1372
1373 recipient_list = ref.Employe.objects.filter(
1374 changement_notifications__in=
1375 rh.ChangementPersonnelNotifications.objects.all()).distinct()
1376
1377
1378 for comb in combs:
1379 # qf c'est pour trouver les recipients.
1380 qf = reduce(
1381 lambda x, y: x & y,
1382 [Q(**{'changement_notifications__type': t}) for t in comb]
1383 )
1384 recipients = recipient_list.filter(qf)
1385
1386 recipient_list = recipient_list.exclude(
1387 id__in=recipients.values_list('id', flat=True))
1388
1389 types_dict = dict(rh.TYPES_CHANGEMENT)
1390
1391 if len(recipients):
1392 sujet = '[SGRH] Rapport des employés de type: %s' % (
1393 ', '.join(
1394 [types_dict[c].lower() for c in
1395 comb]))
1396 message = u''
1397 for t in comb:
1398 message += u'%s: \n' % (types_dict[t].decode('utf8'))
1399 message += '\n'.join([u'\t%s %s, %s' % (
1400 x.dossier.employe.prenom,
1401 x.dossier.employe.nom,
1402 url_prefix + reverse(
1403 'admin:rh_dossier_change', args=[x.dossier.id]))
1404 for x in qs.filter(type__in=[t])])
1405 send_mail(
1406 sujet,
1407 message,
1408 settings.SERVER_EMAIL,
1409 [x.courriel for x in recipients],
1410 fail_silently=False)
1411
1412 qs.update(communique=True)
1413
1414_communique.short_description = u'Envoyer aux desinataires prévus.'
1415
1416
1417class ChangementPersonnelAdmin(admin.ModelAdmin):
1418
1419 actions = (
1420 _invalidate,
1421 _communique,
1422 )
1423
1424 list_display = (
1425 'type', 'dossier', 'valide', 'communique', 'date_communication'
1426 )
1427
1428 list_filter = (
1429 'type',
1430 'valide',
1431 'communique',
1432 )
1433
1434
e8b6a20c
BS
1435admin.site.unregister(User)
1436admin.site.register(User, RHUserAdmin)
1437
53ae644d
OL
1438admin.site.register(rh.Classement, ClassementAdmin)
1439admin.site.register(rh.Devise, DeviseAdmin)
1440admin.site.register(rh.Dossier, DossierAdmin)
22343fe7 1441admin.site.register(EmployeProxy, EmployeProxyAdmin)
5c0f1778 1442admin.site.register(ServiceProxy, ServiceProxyAdmin)
53ae644d 1443admin.site.register(rh.Employe, EmployeAdmin)
7bf28694 1444admin.site.register(rh.CategorieEmploi, CategorieEmploiAdmin)
321fe481 1445admin.site.register(rh.FamilleProfessionnelle)
53ae644d
OL
1446admin.site.register(rh.OrganismeBstg, OrganismeBstgAdmin)
1447admin.site.register(rh.Poste, PosteAdmin)
fc4bf968
EMS
1448admin.site.register(
1449 rh.ResponsableImplantationProxy, ResponsableImplantationAdmin
1450)
53ae644d 1451admin.site.register(rh.Service, ServiceAdmin)
c5964dc2 1452admin.site.register(rh.Statut, StatutAdmin)
53ae644d 1453admin.site.register(rh.TauxChange, TauxChangeAdmin)
c5964dc2 1454admin.site.register(rh.TypeContrat, TypeContratAdmin)
53ae644d
OL
1455admin.site.register(rh.TypePoste, TypePosteAdmin)
1456admin.site.register(rh.TypeRemuneration, TypeRemunerationAdmin)
1457admin.site.register(rh.TypeRevalorisation, TypeRevalorisationAdmin)
1458admin.site.register(rh.ValeurPoint, ValeurPointAdmin)
82af5c19 1459admin.site.register(ImplantationProxy, ImplantationProxyAdmin)
9da4c195 1460admin.site.register(RegionProxy, RegionProxyAdmin)
343cfd9c
BS
1461admin.site.register(rh.ChangementPersonnelNotifications)
1462admin.site.register(rh.ChangementPersonnel, ChangementPersonnelAdmin)