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