Test changes
[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',
458 ('regime_travail', 'regime_travail_nb_heure_semaine'),)}),
53ae644d 459 ('Occupation du Poste par cet Employe', {
22343fe7
OL
460 'fields': (('date_debut', 'date_fin'), )}
461 ),
53ae644d 462 )
22343fe7
OL
463 form = make_ajax_form(rh.Dossier, {
464 'employe': 'employes',
465 'poste': 'postes',
466 'remplacement_de': 'dossiers',
6bee05ff 467 }, superclass=DossierForm)
53ae644d
OL
468
469 def lookup_allowed(self, key, value):
470 if key in (
471 'employe__nom__istartswith',
b0cf30b8 472 'poste__implantation__zone_administrative__code__exact',
e8b6a20c 473 'poste__implantation__zone_administrative__in',
53ae644d
OL
474 'poste__implantation__id__exact',
475 'poste__type_poste__id__exact',
7bf28694 476 'poste__type_poste__categorie_emploi__id__exact',
53ae644d 477 'rh_contrats__type_contrat__id__exact',
6bee05ff
OL
478 'principal__exact',
479 'principal__isnull',
53ae644d
OL
480 ):
481 return True
482
e49ac947
JPC
483 def _id(self, obj):
484 return obj.id
485 _id.short_description = u"#"
486 _id.admin_order_field = "id"
487
e49ac947 488 def _apercu(self, d):
22343fe7
OL
489 apercu_link = u"""<a title="Aperçu du dossier"
490 onclick="return showAddAnotherPopup(this);"
491 href='%s'>
9533bd15 492 <img src="%simg/dossier-apercu.png" />
22343fe7 493 </a>""" % \
b10920ea 494 (reverse('dossier_apercu', args=(d.id,)),
822a2c33 495 settings.STATIC_URL,
b10920ea 496 )
e49ac947
JPC
497 return apercu_link
498 _apercu.allow_tags = True
499 _apercu.short_description = u""
53ae644d 500
5db1c5a3
DB
501 def _nom(self, obj):
502 return "Dossier"
503 _nom.allow_tags = True
504 _nom.short_description = u"Dossier"
53ae644d 505
5db1c5a3
DB
506 def _employe(self, obj):
507 employe = obj.employe
508 view_link = reverse('employe_apercu', args=(employe.id,))
509 edit_link = reverse('admin:rh_employe_change', args=(employe.id,))
5db1c5a3
DB
510 style = ""
511 view = u"""<a href="%s"
512 title="Aperçu l'employé"
513 onclick="return showAddAnotherPopup(this);">
514 <img src="%simg/employe-apercu.png" />
515 </a>""" % (view_link, settings.STATIC_URL,)
516 return u"""%s<a href='%s' style="%s;">%s</a>""" % \
517 (view, edit_link, style, employe)
518 _employe.allow_tags = True
519 _employe.short_description = u"Employé"
520 _employe.admin_order_field = "employe__nom"
53ae644d
OL
521
522 def _poste(self, dossier):
22343fe7
OL
523 link = u"""<a title="Aperçu du poste"
524 onclick="return showAddAnotherPopup(this);"
9533bd15 525 href='%s'><img src="%simg/poste-apercu.png" />
22343fe7 526 </a>
5db1c5a3 527 <a href="%s" title="Modifier le poste">%s [%d]</a>""" % \
53ae644d 528 (reverse('poste_apercu', args=(dossier.poste.id,)),
822a2c33 529 settings.STATIC_URL,
211a0e56 530 reverse('admin:rh_poste_change', args=(dossier.poste.id,)),
5db1c5a3
DB
531 dossier.poste.nom,
532 dossier.poste.id,
53ae644d
OL
533 )
534 return link
535 _poste.allow_tags = True
536 _poste.short_description = u'Poste'
537 _poste.admin_order_field = 'poste__nom'
538
b0cf30b8
EMS
539 def _zone_administrative(self, obj):
540 return obj.poste.implantation.zone_administrative.code
541 _zone_administrative.short_description = u"Zone administrative"
90440a65
EMS
542 _zone_administrative.admin_order_field = \
543 'poste__implantation__zone_administrative__code'
53ae644d 544
5db1c5a3
DB
545 def _implantation(self, obj):
546 return obj.poste.implantation.nom
547 _implantation.short_description = u"Implantation"
548 _implantation.admin_order_field = 'poste__implantation__nom'
549
550 def _date_debut(self, obj):
551 return date(obj.date_debut)
552
553 _date_debut.short_description = u'Début'
554 _date_debut.admin_order_field = 'date_debut'
555
556 def _date_fin(self, obj):
557 return date(obj.date_fin)
558 _date_fin.short_description = u'Fin'
559 _date_fin.admin_order_field = 'date_fin'
560
561 def _date_modification(self, obj):
562 return date(obj.date_modification) \
563 if obj.date_modification is not None else "(aucune)"
564 _date_modification.short_description = u'date modification'
565 _date_modification.admin_order_field = 'date_modification'
566
567 def _dae(self, d):
568 apercu_link = ""
569 dossiers_dae = d.dossiers_dae.all()
570 if len(dossiers_dae) > 0:
571 dossier_dae = dossiers_dae[0]
572 apercu_link = u"""<a title="Aperçu du dossier"
573 onclick="return showAddAnotherPopup(this);"
574 href='%s'>
575 <img src="%simg/loupe.png" />
576 </a>""" % \
577 (reverse('embauche_consulter', args=(dossier_dae.id,)),
578 settings.STATIC_URL,
579 )
580 return apercu_link
581 _dae.allow_tags = True
582 _dae.short_description = u"DAE"
22343fe7 583
53ae644d
OL
584 def save_formset(self, request, form, formset, change):
585 instances = formset.save(commit=False)
586 for instance in instances:
587 if instance.__class__ == rh.DossierCommentaire:
588 instance.owner = request.user
02e69aa2 589 instance.date_creation = datetime.datetime.now()
53ae644d
OL
590 instance.save()
591
592
45066657
EMS
593class EmployeAdminBase(DateRangeMixin, ProtectRegionMixin,
594 DerniereModificationAdmin, BaseAdmin):
7eb6b687 595 prefixe_recherche_temporelle = "rh_dossiers__"
53ae644d
OL
596 alphabet_filter = 'nom'
597 DEFAULT_ALPHABET = u'ABCDEFGHIJKLMNOPQRSTUVWXYZ'
e23da9c3
EMS
598 search_fields = (
599 'id', 'nom', 'prenom', 'nom_affichage',
600 'rh_dossiers__poste__nom',
601 'rh_dossiers__poste__nom_feminin'
602 )
53ae644d
OL
603 ordering = ('nom', )
604 form = EmployeAdminForm
22343fe7 605 list_display = (
f80b83c6 606 '_id', '_apercu', '_nom', '_dossiers_postes',
b0cf30b8 607 #'_zone_administrative',
f80b83c6
OL
608 #'_implantation',
609 'date_entree',
45066657
EMS
610 'derniere_modification'
611 )
e49ac947 612 list_display_links = ('_nom',)
22343fe7 613 list_filter = (
b0cf30b8 614 'rh_dossiers__poste__implantation__zone_administrative',
45066657
EMS
615 'rh_dossiers__poste__implantation', 'nb_postes'
616 )
617 inlines = (
340307bd 618 AyantDroitInline, DossierROInline, EmployePieceInline,
45066657
EMS
619 EmployeCommentaireInline
620 )
621 fieldsets = (
53ae644d 622 ('Identification', {
22343fe7
OL
623 'fields': (
624 ('nom', 'prenom'),
625 ('nom_affichage', 'genre'),
626 'nationalite',
627 'date_naissance',
45066657
EMS
628 )
629 }),
53ae644d 630 ('Informations personnelles', {
45066657
EMS
631 'fields': ('situation_famille', 'date_entree', )
632 }),
89a8df07 633 ('Coordonnées personnelles', {
22343fe7
OL
634 'fields': (
635 ('tel_domicile', 'tel_cellulaire'),
636 ('adresse', 'ville'),
637 ('code_postal', 'province'),
638 'pays',
89a8df07 639 'courriel_perso'
45066657
EMS
640 )
641 }),
642 )
53ae644d 643
5db1c5a3
DB
644 def _id(self, obj):
645 return obj.id
646 _id.short_description = u"#"
647 _id.admin_order_field = "id"
648
b10920ea 649 def _apercu(self, obj):
22343fe7
OL
650 return u"""<a title="Aperçu de l'employé"
651 onclick="return showAddAnotherPopup(this);"
652 href='%s'>
9533bd15 653 <img src="%simg/employe-apercu.png" />
22343fe7
OL
654 </a>""" % \
655 (reverse('employe_apercu', args=(obj.id,)), settings.STATIC_URL)
b10920ea
JPC
656 _apercu.allow_tags = True
657 _apercu.short_description = u""
b10920ea 658
53ae644d 659 def _nom(self, obj):
53ae644d 660 edit_link = reverse('admin:rh_employe_change', args=(obj.id,))
e6c107de 661 return u"""<a href='%s'><strong>%s</strong></a>""" % \
e49ac947 662 (edit_link, "%s %s" % (obj.nom.upper(), obj.prenom))
53ae644d 663 _nom.allow_tags = True
e49ac947 664 _nom.short_description = u"Employé"
53ae644d
OL
665 _nom.admin_order_field = "nom"
666
b0cf30b8 667 def _zone_administrative(self, obj):
5db1c5a3
DB
668 try:
669 d = rh.Dossier.objects.filter(employe=obj.id, principal=True)[0]
b0cf30b8 670 zone = d.poste.implantation.zone_administrative.code
5db1c5a3 671 except:
b0cf30b8
EMS
672 zone = None
673 return zone
674 _zone_administrative.short_description = u"Zone administrative"
e49ac947 675
5db1c5a3
DB
676 def _implantation(self, obj):
677 try:
678 d = rh.Dossier.objects.filter(employe=obj.id, principal=True)[0]
679 implantation = d.poste.implantation.nom
680 except:
681 implantation = None
682 return implantation
683 _implantation.short_description = u"Implantation"
33232787 684
a7f013f5 685 def _dossiers_postes(self, obj):
53ae644d
OL
686 l = []
687 for d in obj.rh_dossiers.all().order_by('-date_debut'):
5db1c5a3
DB
688 link_style = u''
689 list_style = u''
690 if d.date_fin is not None and d.date_fin < datetime.date.today():
5db1c5a3
DB
691 link_style = u' style="color:#666;"'
692 list_style = u' style="color:grey;"'
08ecf07e 693
22343fe7
OL
694 dossier = u"""<a title="Aperçu du dossier"
695 href="%s"
696 onclick="return showAddAnotherPopup(this);"
697 title="Aperçu du dossier">
9533bd15 698 <img src="%simg/dossier-apercu.png" />
22343fe7 699 </a>
5db1c5a3 700 <a href="%s"%s>Dossier</a>
22343fe7
OL
701 &nbsp;""" % \
702 (reverse('dossier_apercu', args=(d.id,)),
703 settings.STATIC_URL,
5db1c5a3
DB
704 reverse('admin:rh_dossier_change', args=(d.id,)),
705 link_style,)
22343fe7
OL
706
707 poste = u"""<a title="Aperçu du poste"
708 href="%s"
709 onclick="return showAddAnotherPopup(this);"
710 title="Aperçu du poste">
9533bd15 711 <img src="%simg/poste-apercu.png" />
22343fe7 712 </a>
5db1c5a3 713 <a href="%s"%s>%s [%d]</a>
22343fe7
OL
714 &nbsp;""" % \
715 (reverse('poste_apercu', args=(d.poste.id,)),
716 settings.STATIC_URL,
5db1c5a3
DB
717 reverse('admin:rh_poste_change', args=(d.poste.id,)),
718 link_style,
a7f013f5 719 d.poste.nom,
5db1c5a3 720 d.poste.id)
b5cc0357 721
5db1c5a3
DB
722 link = u"""<li%s>%s %s</li>""" % \
723 (list_style, dossier, poste)
b5cc0357 724
53ae644d
OL
725 l.append(link)
726 return "<ul>%s</ul>" % "\n".join(l)
a7f013f5
JPC
727 _dossiers_postes.allow_tags = True
728 _dossiers_postes.short_description = u"Dossiers et postes"
53ae644d 729
5db1c5a3
DB
730 def _date_modification(self, obj):
731 return date(obj.date_modification) \
732 if obj.date_modification is not None else "(aucune)"
733 _date_modification.short_description = u'date modification'
734 _date_modification.admin_order_field = 'date_modification'
735
53ae644d 736 def queryset(self, request):
45066657 737 qs = super(EmployeAdminBase, self).queryset(request)
53ae644d
OL
738 return qs.select_related(depth=1).order_by('nom')
739
740 def save_formset(self, request, form, formset, change):
741 instances = formset.save(commit=False)
742 for instance in instances:
743 if instance.__class__ == rh.EmployeCommentaire:
744 instance.owner = request.user
02e69aa2 745 instance.date_creation = datetime.datetime.now()
53ae644d
OL
746 instance.save()
747
22343fe7 748
45066657 749class EmployeAdmin(reversion.VersionAdmin, EmployeAdminBase):
b2d1cc93 750 change_list_template = "admin/rh/employe/change_list.html"
45066657 751 ignore_duplicate_revisions = True
d104b0ae
EMS
752
753
45066657 754class EmployeProxyAdmin(EmployeAdminBase):
22343fe7 755 list_display = ('_id', '_apercu', '_nom', '_organigramme')
664bdc2f 756 list_per_page = 500
bd917a45
JPC
757 actions = None
758
759 def __init__(self, *args, **kwargs):
760 super(EmployeProxyAdmin, self).__init__(*args, **kwargs)
761 self.list_display_links = (None, )
08faf06e 762
8f7b2d7b
DB
763 def queryset(self, request):
764 qs = super(ProtectRegionMixin, self).queryset(request)
765
766 if in_drh_or_admin(request.user) or \
767 user_gere_obj_de_sa_region(request.user):
768 return qs
769
770 return qs.none()
771
22343fe7
OL
772 def has_add_permission(self, obj):
773 return False
774
c5dab350 775 def has_change_permission(self, request, obj=None):
3383b2d1
OL
776 user_groups = [g.name for g in request.user.groups.all()]
777 if groups.CORRESPONDANT_RH in user_groups or \
778 groups.ADMINISTRATEURS in user_groups or \
779 groups.DIRECTEUR_DE_BUREAU in user_groups or \
c5dab350
OL
780 in_drh_or_admin(request.user):
781 return True
782 return False
783
08faf06e
JPC
784 def _organigramme(self, obj):
785 l = []
fc4bf968
EMS
786 for d in rh.Dossier.objects.filter(
787 Q(date_fin__gt=datetime.date.today()) | Q(date_fin=None),
788 Q(date_debut__lt=datetime.date.today()) | Q(date_debut=None),
789 employe=obj.id
790 ):
791 organigramme = \
792 u'Organigramme, niveau: ' \
793 u'<input type="text" id="level_%s" ' \
794 u'style="width:30px;height:15px;" /> ' \
795 u'<input type="button" value="Générer" ' \
796 u"""onclick="window.location='%s' + """ \
797 u"""document.getElementById('level_%s').value" />""" % (
798 d.poste.id,
799 reverse('rho_employe_sans_niveau', args=(d.poste.id,)),
800 d.poste.id
801 )
e4fa851f 802 link = u"""<li>%s [%s]:<br />%s</li>""" % (
fc4bf968 803 d.poste.nom,
e4fa851f 804 d.poste.id,
fc4bf968
EMS
805 organigramme
806 )
08faf06e
JPC
807 l.append(link)
808 return "<ul>%s</ul>" % "\n".join(l)
809
810 _organigramme.allow_tags = True
811 _organigramme.short_description = "Organigramme"
812
53ae644d 813
45066657
EMS
814class CategorieEmploiAdmin(reversion.VersionAdmin,
815 DerniereModificationAdmin, BaseAdmin):
816 ignore_duplicate_revisions = True
817 list_display = ('nom', 'derniere_modification')
53ae644d 818 inlines = (TypePosteInline,)
45066657
EMS
819 fieldsets = (
820 (None, {'fields': ('nom', )}),
821 )
53ae644d 822
22343fe7 823
45066657 824class OrganismeBstgAdmin(reversion.VersionAdmin, DerniereModificationAdmin,
d104b0ae 825 BaseAdmin):
45066657 826 ignore_duplicate_revisions = True
c5964dc2 827 search_fields = ('nom',)
45066657 828 list_display = ('nom', 'type', 'pays', 'derniere_modification')
c5964dc2 829 list_filter = ('type', )
340307bd 830 inlines = (DossierROInline,)
45066657 831 fieldsets = (
22343fe7 832 (None, {'fields': ('nom', 'type', 'pays',)}),
45066657 833 )
33232787 834
53ae644d 835
45066657
EMS
836class PosteAdmin(DateRangeMixin, ProtectRegionMixin, reversion.VersionAdmin,
837 AjaxSelect, DerniereModificationAdmin, BaseAdmin):
b2d1cc93 838 change_list_template = "admin/rh/poste/change_list.html"
45066657 839 ignore_duplicate_revisions = True
22343fe7
OL
840 form = make_ajax_form(rh.Poste, {
841 'implantation': 'implantations',
842 'type_poste': 'typepostes',
843 'responsable': 'postes',
844 'valeur_point_min': 'valeurpoints',
845 'valeur_point_max': 'valeurpoints',
53ae644d
OL
846 })
847 alphabet_filter = 'nom'
22343fe7 848 search_fields = (
45066657
EMS
849 'id',
850 'nom',
851 'implantation__nom',
b0cf30b8
EMS
852 'implantation__zone_administrative__code',
853 'implantation__zone_administrative__nom',
45066657
EMS
854 'rh_dossiers__employe__id',
855 'rh_dossiers__employe__nom',
856 'rh_dossiers__employe__prenom',
857 )
53ae644d 858 list_display = (
45066657
EMS
859 '_id', '_apercu', '_nom', '_occupe_par', 'implantation', '_service',
860 '_responsable', 'date_debut', 'date_fin', 'derniere_modification',
861 '_dae'
862 )
f614ca5c 863 list_filter = (
b0cf30b8 864 'implantation__zone_administrative',
53ae644d 865 'implantation',
22343fe7 866 'service',
53ae644d 867 'type_poste',
7bf28694 868 'type_poste__categorie_emploi',
118efe7a 869 'type_poste__famille_professionnelle',
4c53dda4 870 'vacant',
45066657 871 )
e49ac947 872 list_display_links = ('_nom',)
45066657 873 fieldsets = (
22343fe7
OL
874 (None, {'fields': (
875 ('nom', 'nom_feminin'),
876 'implantation',
877 'type_poste',
878 'service',
879 'responsable',
880 )}
881 ),
53ae644d 882 ('Contrat', {
22343fe7
OL
883 'fields': ((
884 'regime_travail',
885 'regime_travail_nb_heure_semaine'),
886 )}
887 ),
53ae644d 888 ('Recrutement', {
22343fe7
OL
889 'fields': (('local', 'expatrie', 'mise_a_disposition', 'appel'),)}
890 ),
53ae644d 891 ('Rémunération', {
22343fe7
OL
892 'fields': (('classement_min',
893 'valeur_point_min',
894 'devise_min',
895 'salaire_min',
896 'indemn_min',
897 'autre_min',),
898 ('classement_max',
899 'valeur_point_max',
900 'devise_max',
901 'salaire_max',
902 'indemn_max',
903 'autre_max',),
904 )}),
53ae644d
OL
905 ('Comparatifs de rémunération', {
906 'fields': ('devise_comparaison',
907 ('comp_locale_min', 'comp_locale_max'),
908 ('comp_universite_min', 'comp_universite_max'),
909 ('comp_fonctionpub_min', 'comp_fonctionpub_max'),
910 ('comp_ong_min', 'comp_ong_max'),
22343fe7
OL
911 ('comp_autre_min', 'comp_autre_max'))}
912 ),
53ae644d 913 ('Justification', {
22343fe7
OL
914 'fields': ('justification',)}
915 ),
48a6df80 916 ('Autres Méta-données', {
22343fe7
OL
917 'fields': ('date_debut', 'date_fin')}
918 ),
53ae644d
OL
919 )
920
921 inlines = (PosteFinancementInline,
922 PostePieceInline,
340307bd 923 DossierROInline,
6f037929 924 PosteComparaisonInline,
53ae644d
OL
925 PosteCommentaireInline, )
926
f614ca5c 927 def lookup_allowed(self, key, value):
118efe7a
EMS
928 return key in (
929 'date_debut__gte', 'date_debut__isnull', 'date_fin__lte',
90440a65
EMS
930 'date_fin__isnull',
931 'implantation__zone_administrative__code__exact',
118efe7a
EMS
932 'implantation__id__exact', 'type_poste__id__exact',
933 'type_poste__categorie_emploi__id__exact', 'service__id__exact',
90440a65 934 'service__isnull', 'vacant__exact', 'vacant__isnull'
118efe7a 935 ) or super(PosteAdmin, self).lookup_allowed(key, value)
f614ca5c 936
5db1c5a3
DB
937 def _id(self, obj):
938 return "%s" % obj.id
939 _id.short_description = '#'
940 _id.admin_order_field = 'id'
941
8f3ca727 942 def _apercu(self, poste):
22343fe7
OL
943 view_link = u"""<a onclick="return showAddAnotherPopup(this);"
944 title="Aperçu du poste"
945 href='%s'>
9533bd15 946 <img src="%simg/poste-apercu.png" />
22343fe7 947 </a>""" % \
8f3ca727 948 (reverse('poste_apercu', args=(poste.id,)),
22343fe7
OL
949 settings.STATIC_URL,)
950 return view_link
8f3ca727 951 _apercu.allow_tags = True
e49ac947
JPC
952 _apercu.short_description = ''
953
5db1c5a3
DB
954 def _nom(self, poste):
955 return """<a href="%s">%s</a>""" % \
956 (reverse('admin:rh_poste_change', args=(poste.id,)),
957 poste.nom)
958 _nom.allow_tags = True
959 _nom.short_description = u'Poste'
960 _nom.admin_order_field = 'nom'
a47ed016 961
5db1c5a3
DB
962 def _occupe_par(self, obj):
963 """Formatte la méthode Poste.occupe_par() pour l'admin"""
964 output = u"Vacant"
965 if obj.date_fin is not None and obj.date_fin < datetime.date.today():
966 return u"s/o"
967 employes = obj.occupe_par()
968 if employes:
969 l = []
970 for e in employes:
971 link = u"""<a href='%s'
972 title='Aperçu de l\'employé'
973 onclick='return showAddAnotherPopup(this)'>
974 <img src='%simg/employe-apercu.png' />
975 </a>
976 <a href='%s'>%s</a>""" % \
977 (reverse('employe_apercu', args=(e.id,)),
978 settings.STATIC_URL,
979 reverse('admin:rh_employe_change', args=(e.id,)),
980 e)
981 l.append(link)
982 output = "\n<br />".join(l)
983 return output
984 _occupe_par.allow_tags = True
985 _occupe_par.short_description = "Occupé par"
986
b0cf30b8
EMS
987 def _zone_administrative(self, poste):
988 return poste.implantation.zone_administrative.code
989 _zone_administrative.short_description = 'Zone administrative'
90440a65
EMS
990 _zone_administrative.admin_order_field = \
991 'implantation__zone_administrative__code'
5db1c5a3
DB
992
993 def _implantation(self, poste):
994 return poste.implantation.nom
995 _implantation.short_description = 'Implantation'
996 _implantation.admin_order_field = 'implantation'
8f3ca727 997
c5964dc2 998 def _service(self, obj):
45066657 999 return obj.service
6c2b1160 1000 _service.short_description = 'Service'
1b130b25 1001 _service.allow_tags = True
53ae644d 1002
1ce2ddb9
JPC
1003 def _responsable(self, obj):
1004 try:
22343fe7
OL
1005 responsable = u"""<a href="%s"
1006 onclick="return showAddAnotherPopup(this)">
9533bd15 1007 <img src="%simg/poste-apercu.png"
22343fe7
OL
1008 title="Aperçu du poste" />
1009 </a>
5db1c5a3 1010 <a href="%s">%s [%d]</a>
22343fe7
OL
1011 <br />""" % \
1012 (reverse('poste_apercu', args=(obj.responsable.id,)),
1013 settings.STATIC_URL,
1014 reverse('admin:rh_poste_change', args=(obj.responsable.id,)),
5db1c5a3
DB
1015 obj.responsable.nom,
1016 obj.responsable.id)
1ce2ddb9
JPC
1017 except:
1018 responsable = ''
1019
1020 try:
d104b0ae
EMS
1021 dossier = obj.responsable.rh_dossiers.all() \
1022 .order_by('-date_debut')[0]
60f34330 1023 employe_id = dossier.employe.id
fc4bf968 1024 employe_html = u"""<br />
22343fe7
OL
1025 <a href="%s"
1026 onclick="return showAddAnotherPopup(this)">
9533bd15 1027 <img src="%simg/employe-apercu.png"
22343fe7
OL
1028 title="Aperçu de l'employé">
1029 </a>
1030 <a href="%s">%s</a>""" % \
1031 (reverse('employe_apercu', args=(employe_id,)),
1032 settings.STATIC_URL,
1033 reverse('admin:rh_employe_change', args=(employe_id,)),
60f34330 1034 dossier.employe)
1ce2ddb9 1035 except:
fc4bf968 1036 employe_html = ""
1ce2ddb9 1037
fc4bf968 1038 return "%s %s" % (responsable, employe_html)
1ce2ddb9
JPC
1039 _responsable.short_description = 'Responsable'
1040 _responsable.allow_tags = True
1041
5db1c5a3
DB
1042 def _date_debut(self, obj):
1043 return date_format(obj.date_debut)
1044 _date_debut.short_description = u'Début'
1045 _date_debut.admin_order_field = 'date_debut'
f3e3ac6f 1046
5db1c5a3
DB
1047 def _date_fin(self, obj):
1048 return date_format(obj.date_fin)
1049 _date_fin.short_description = u'Fin'
1050 _date_fin.admin_order_field = 'date_fin'
53ae644d 1051
5db1c5a3
DB
1052 def _dae(self, poste):
1053 apercu_link = ""
1054 postes_dae = poste.postes_dae.all()
1055 if len(postes_dae) > 0:
1056 poste_dae = postes_dae[0]
1057 apercu_link = \
1058 u'<a title="Aperçu du dossier" href="%s" ' \
1059 u'onclick="return showAddAnotherPopup(this);">' \
1060 u'<img src="%simg/loupe.png" /></a>' % (reverse(
1061 'poste_consulter', args=("dae-%s" % poste_dae.id,)
1062 ), settings.STATIC_URL)
1063 return apercu_link
1064 _dae.allow_tags = True
1065 _dae.short_description = u"DAE"
53ae644d
OL
1066
1067 def save_formset(self, request, form, formset, change):
1068 instances = formset.save(commit=False)
1069 for instance in instances:
1070 if instance.__class__ == rh.PosteCommentaire:
1071 instance.owner = request.user
02e69aa2 1072 instance.date_creation = datetime.datetime.now()
53ae644d
OL
1073 instance.save()
1074 formset.save_m2m()
1075
1076
8c8ffc4f
OL
1077class ResponsableInline(admin.TabularInline):
1078 model = rh.ResponsableImplantation
1079 extra = 0
fc4bf968 1080 fk_name = "implantation"
6fb68b2f 1081 form = ResponsableInlineForm
fc4bf968 1082
22343fe7 1083
08a9b6fc 1084class ResponsableImplantationAdmin(BaseAdmin):
8c8ffc4f 1085 actions = None
6fb68b2f
DB
1086 fields = ('nom', )
1087 inlines = (ResponsableInline, )
b0cf30b8
EMS
1088 list_filter = ('zone_administrative', 'statut', )
1089 list_display = ('_zone_administrative', '_nom', 'statut', '_responsable', )
6fb68b2f 1090 list_display_links = ('_nom',)
664bdc2f 1091 list_per_page = 500
8c8ffc4f 1092 readonly_fields = ('nom', )
6fb68b2f
DB
1093 search_fields = (
1094 'nom',
1095 'responsable__employe__id',
1096 'responsable__employe__nom',
1097 'responsable__employe__prenom',
1098 )
1099 ordering = ('nom',)
8c8ffc4f 1100 inlines = (ResponsableInline, )
d104b0ae 1101
b0cf30b8
EMS
1102 def _zone_administrative(self, obj):
1103 return obj.zone_administrative.code
1104 _zone_administrative.short_description = u"Zone administrative"
1105 _zone_administrative.admin_order_field = 'zone_administrative__code'
d104b0ae 1106
30dabdc3
DB
1107 def _nom(self, obj):
1108 return obj.nom
1109 _nom.short_description = u"Implantation"
1110 _nom.admin_order_field = 'nom'
d104b0ae 1111
8c8ffc4f
OL
1112 def _responsable(self, obj):
1113 try:
da202402
OL
1114 employe = employe = obj.responsable.employe
1115 except Exception, e:
90440a65
EMS
1116 return (
1117 u"<span style='color: red;'>"
1118 u"Pas de responsable</span><!-- %s -->" % e
1119 )
da202402 1120 try:
8c8ffc4f
OL
1121 dossiers = employe.dossiers_encours()
1122 if len(dossiers) == 0:
1123 return u"<span style='color: red;'>%s %s </span>" % (
1124 employe, u"sans dossier actif")
1125 else:
1126 return employe
da202402
OL
1127 except Exception, e:
1128 return u"<!-- %s -->" % e
8c8ffc4f
OL
1129 _responsable.allow_tags = True
1130 _responsable.short_description = u"Responsable"
6fb68b2f 1131 _responsable.admin_order_field = 'responsable__employe__nom'
8c8ffc4f
OL
1132
1133 def has_add_permission(self, request=None):
1134 return False
1135
1136 def has_change_permission(self, request, obj=None):
1137 return in_drh_or_admin(request.user)
1138
1139 def has_delete_permission(self, request, obj=None):
1140 return False
53ae644d 1141
fc4bf968 1142
7013d234 1143class ServiceAdminBase(ArchivableAdmin, DerniereModificationAdmin, BaseAdmin):
b87e1b0e 1144 list_display = ('nom', 'derniere_modification', '_archive')
cbb0373e 1145 list_filter = ('archive', )
45066657
EMS
1146 fieldsets = (
1147 (None, {'fields': ('nom', 'archive')}),
1148 )
33232787 1149
fc4bf968 1150
45066657
EMS
1151class ServiceAdmin(reversion.VersionAdmin, ServiceAdminBase):
1152 ignore_duplicate_revisions = True
d104b0ae
EMS
1153
1154
45066657 1155class ServiceProxyAdmin(ServiceAdminBase):
cfd5ac68 1156 list_display = ('nom', '_organigramme', '_archive', )
8135fc65
JPC
1157 actions = None
1158
1159 def __init__(self, *args, **kwargs):
1160 super(ServiceProxyAdmin, self).__init__(*args, **kwargs)
1161 self.list_display_links = (None, )
5c0f1778 1162
f7badf51
EMS
1163 def queryset(self, request):
1164 return super(ServiceProxyAdmin, self).queryset(request) \
1165 .annotate(num_postes=Count('rh_postes')) \
1166 .filter(num_postes__gt=0)
1167
5c0f1778
JPC
1168 def has_add_permission(self, obj):
1169 return False
1170
aa2c508e 1171 def has_change_permission(self, request, obj=None):
3383b2d1
OL
1172 user_groups = [g.name for g in request.user.groups.all()]
1173 if groups.CORRESPONDANT_RH in user_groups or \
1174 groups.ADMINISTRATEURS in user_groups or \
1175 groups.DIRECTEUR_DE_BUREAU in user_groups or \
c5dab350
OL
1176 in_drh_or_admin(request.user):
1177 return True
1178 return False
aa2c508e 1179
5c0f1778 1180 def _organigramme(self, obj):
8135fc65
JPC
1181 return """<a href="%s"><strong>Organigramme</strong></a>""" % \
1182 (reverse('rho_service', args=(obj.id,)))
5c0f1778
JPC
1183 _organigramme.allow_tags = True
1184 _organigramme.short_description = "Organigramme"
1185
8135fc65 1186
15659516
BS
1187class StatutAdmin(reversion.VersionAdmin,
1188 ArchivableAdmin,
1189 DerniereModificationAdmin,
45066657
EMS
1190 BaseAdmin):
1191 ignore_duplicate_revisions = True
15659516
BS
1192 list_display = ('code', 'nom', 'derniere_modification', '_archive')
1193 list_filter = ('archive', )
45066657 1194 fieldsets = (
53ae644d 1195 (None, {
15659516 1196 'fields': ('code', 'nom', 'archive'),
53ae644d 1197 }),
45066657 1198 )
33232787 1199
22343fe7 1200
45066657
EMS
1201class TauxChangeAdmin(reversion.VersionAdmin, DerniereModificationAdmin,
1202 BaseAdmin):
1203 ignore_duplicate_revisions = True
1204 list_display = ('taux', 'devise', 'annee', 'derniere_modification')
1205 list_filter = ('devise',)
1206 fieldsets = (
53ae644d
OL
1207 (None, {
1208 'fields': ('taux', 'devise', 'annee', ),
1209 }),
45066657 1210 )
33232787 1211
22343fe7 1212
15659516
BS
1213class TypeContratAdmin(reversion.VersionAdmin,
1214 ArchivableAdmin,
1215 DerniereModificationAdmin,
45066657
EMS
1216 BaseAdmin):
1217 ignore_duplicate_revisions = True
15659516
BS
1218 list_display = ('nom', 'nom_long', 'derniere_modification', '_archive')
1219 list_filter = ('archive', )
45066657 1220 fieldsets = (
53ae644d 1221 (None, {
15659516 1222 'fields': ('nom', 'nom_long', 'archive'),
53ae644d 1223 }),
45066657 1224 )
33232787 1225
53ae644d 1226
15659516
BS
1227class TypePosteAdmin(reversion.VersionAdmin,
1228 ArchivableAdmin,
1229 DerniereModificationAdmin,
d104b0ae 1230 BaseAdmin):
45066657 1231 ignore_duplicate_revisions = True
53ae644d 1232 search_fields = ('nom', 'nom_feminin', )
15659516
BS
1233 list_display = ('nom', 'categorie_emploi',
1234 'derniere_modification', '_archive',)
1235 list_filter = ('categorie_emploi', 'famille_professionnelle', 'archive')
45066657 1236 fieldsets = (
53ae644d 1237 (None, {
22343fe7 1238 'fields': (
45066657 1239 'nom', 'nom_feminin', 'is_responsable', 'categorie_emploi',
321fe481 1240 'famille_professionnelle',
15659516 1241 'archive',
45066657
EMS
1242 )
1243 }),
1244 )
33232787 1245
53ae644d 1246
7013d234 1247class TypeRemunerationAdmin(reversion.VersionAdmin, ArchivableAdmin,
45066657
EMS
1248 DerniereModificationAdmin, BaseAdmin):
1249 ignore_duplicate_revisions = True
22343fe7 1250 list_display = (
b87e1b0e
BS
1251 'nom', 'type_paiement', 'nature_remuneration',
1252 'derniere_modification', '_archive'
45066657 1253 )
7ba822a6 1254 list_filter = ('archive', )
45066657
EMS
1255 fieldsets = (
1256 (None, {
1257 'fields': (
1258 'nom', 'type_paiement', 'nature_remuneration', 'archive'
1259 )
1260 }),
1261 )
53ae644d 1262
53ae644d 1263
45066657 1264class TypeRevalorisationAdmin(reversion.VersionAdmin,
15659516
BS
1265 ArchivableAdmin,
1266 DerniereModificationAdmin,
1267 BaseAdmin):
45066657 1268 ignore_duplicate_revisions = True
15659516
BS
1269 list_display = ('nom', 'derniere_modification', '_archive')
1270 list_filter = ('archive', )
45066657 1271 fieldsets = (
15659516 1272 (None, {'fields': ('nom', 'archive')}),
45066657 1273 )
33232787 1274
53ae644d 1275
15659516
BS
1276class ValeurPointAdmin(reversion.VersionAdmin,
1277 DerniereModificationAdmin,
d104b0ae 1278 BaseAdmin):
45066657 1279 ignore_duplicate_revisions = True
22343fe7 1280 list_display = (
45066657
EMS
1281 '_devise_code', '_devise_nom', 'annee', 'implantation',
1282 'valeur', 'derniere_modification'
1283 )
b0cf30b8 1284 list_filter = ('annee', 'devise', 'implantation__zone_administrative', )
45066657
EMS
1285 fieldsets = (
1286 (None, {'fields': ('valeur', 'devise', 'implantation', 'annee')}),
1287 )
33232787 1288
866bba57
EMS
1289 def queryset(self, request):
1290 return super(ValeurPointAdmin, self).queryset(request) \
1291 .select_related('devise', 'implantation')
1292
53ae644d
OL
1293 def _devise_code(self, obj):
1294 return obj.devise.code
1295 _devise_code.short_description = "Code de la devise"
1296
1297 def _devise_nom(self, obj):
1298 return obj.devise.nom
1299 _devise_nom.short_description = "Nom de la devise"
1300
fc4bf968 1301
08a9b6fc 1302class ImplantationProxyAdmin(BaseAdmin):
82af5c19 1303 list_display = ('nom', '_organigramme')
8135fc65
JPC
1304 actions = None
1305
1306 def __init__(self, *args, **kwargs):
1307 super(ImplantationProxyAdmin, self).__init__(*args, **kwargs)
1308 self.list_display_links = (None, )
82af5c19
JPC
1309
1310 def has_add_permission(self, obj):
1311 return False
1312
aa2c508e 1313 def has_change_permission(self, request, obj=None):
3383b2d1
OL
1314 user_groups = [g.name for g in request.user.groups.all()]
1315 if groups.CORRESPONDANT_RH in user_groups or \
1316 groups.ADMINISTRATEURS in user_groups or \
1317 groups.DIRECTEUR_DE_BUREAU in user_groups or \
c5dab350
OL
1318 in_drh_or_admin(request.user):
1319 return True
1320 return False
aa2c508e 1321
82af5c19 1322 def _organigramme(self, obj):
fc4bf968
EMS
1323 return '<a href="%s"><strong>Organigramme</strong></a>' % (
1324 reverse('rho_implantation', args=(obj.id,))
1325 )
82af5c19
JPC
1326 _organigramme.allow_tags = True
1327 _organigramme.short_description = "Organigramme"
1328
fc4bf968 1329
08a9b6fc 1330class RegionProxyAdmin(BaseAdmin):
9da4c195 1331 list_display = ('nom', '_organigramme')
8135fc65
JPC
1332 actions = None
1333
1334 def __init__(self, *args, **kwargs):
1335 super(RegionProxyAdmin, self).__init__(*args, **kwargs)
1336 self.list_display_links = (None, )
9da4c195
JPC
1337
1338 def has_add_permission(self, obj):
1339 return False
1340
aa2c508e 1341 def has_change_permission(self, request, obj=None):
3383b2d1
OL
1342 user_groups = [g.name for g in request.user.groups.all()]
1343 if groups.CORRESPONDANT_RH in user_groups or \
1344 groups.ADMINISTRATEURS in user_groups or \
1345 groups.DIRECTEUR_DE_BUREAU in user_groups or \
c5dab350
OL
1346 in_drh_or_admin(request.user):
1347 return True
1348 return False
aa2c508e 1349
9da4c195 1350 def _organigramme(self, obj):
fc4bf968
EMS
1351 return """<a href="%s"><strong>Organigramme</strong></a>""" % (
1352 reverse('rho_region', args=(obj.id,))
1353 )
9da4c195
JPC
1354 _organigramme.allow_tags = True
1355 _organigramme.short_description = "Organigramme"
1356
1357
e8b6a20c
BS
1358class ProfileInline(admin.StackedInline):
1359 model = rh.UserProfile
1360
1361
1362class RHUserAdmin(UserAdmin):
1363 inlines = list(UserAdmin.inlines) + [ProfileInline]
1364
1365
343cfd9c
BS
1366def _invalidate(modaladmin, req, qs):
1367 qs.update(valide=False)
1368_invalidate.short_description = 'Invalider'
1369
1370
1371def _communique(modaladmin, req, qs):
1372 url_prefix = ('https://' if req.is_secure() else 'http://') + (
1373 req.META['SERVER_NAME'] if 'SERVER_NAME' in req.META else
1374 'localhost') + (':%s' % (req.META['SERVER_PORT']) if 'SERVER_PORT'
1375 in req.META else '')
1376
1377 types = [x[0] for x in rh.TYPES_CHANGEMENT]
1378
1379 # make a list of all possible email types. It is reversed so that
1380 # we start with the largest combinations.
1381 combs = list(itertools.chain(*map(
1382 lambda x: itertools.combinations(types, x),
1383 range(1, len(types)+1))))
1384
1385 combs = reversed(combs)
1386
1387 recipient_list = ref.Employe.objects.filter(
1388 changement_notifications__in=
1389 rh.ChangementPersonnelNotifications.objects.all()).distinct()
1390
4e93fcf2
BS
1391 thead_colors = {
1392 'NO': 'ff99ff',
1393 'MO': 'ccccff',
1394 'DE': 'ff99ff',
1395 }
1396
343cfd9c
BS
1397
1398 for comb in combs:
1399 # qf c'est pour trouver les recipients.
1400 qf = reduce(
1401 lambda x, y: x & y,
1402 [Q(**{'changement_notifications__type': t}) for t in comb]
1403 )
1404 recipients = recipient_list.filter(qf)
1405
1406 recipient_list = recipient_list.exclude(
1407 id__in=recipients.values_list('id', flat=True))
1408
1409 types_dict = dict(rh.TYPES_CHANGEMENT)
1410
1411 if len(recipients):
4e93fcf2
BS
1412 ctx = {
1413 'types': [
1414 ]
1415 }
1416
343cfd9c 1417 for t in comb:
4e93fcf2
BS
1418 changements = []
1419 ctx['types'].append({
1420 'bgcolor': thead_colors[t],
1421 'name': types_dict[t],
1422 'changements': changements,
1423 })
1424
1425 for ch in qs.filter(type__in=[t]):
1426 changements.append(ch)
1427
1428
1429 template = loader.get_template('email/mouvement_employe.html')
1430 content = template.render(Context(ctx))
1431
1432 sujet = '[SGRH] ARRIVÉES - DÉPARTS - MOBILITÉS'
1433
1434 msg = EmailMessage(
343cfd9c 1435 sujet,
4e93fcf2 1436 content,
343cfd9c 1437 settings.SERVER_EMAIL,
5f3d4a59
BS
1438 ['benoit.clennett-sirois@auf.org'],
1439 # [x.courriel for x in recipients],
4e93fcf2
BS
1440 )
1441 msg.content_subtype = "html"
1442 msg.send()
343cfd9c 1443
0a2c697a
BS
1444 qs.update(
1445 communique=True,
1446 date_communication=datetime.datetime.now()
1447 )
343cfd9c
BS
1448
1449_communique.short_description = u'Envoyer aux desinataires prévus.'
1450
1451
1452class ChangementPersonnelAdmin(admin.ModelAdmin):
1453
1454 actions = (
1455 _invalidate,
1456 _communique,
1457 )
1458
828759ca
BS
1459 def _dossier(obj):
1460 return obj.dossier.__unicode__()
e0a465f2 1461 _dossier.short_description = u'Dossier'
828759ca 1462
343cfd9c 1463 list_display = (
828759ca 1464 'type', _dossier, 'valide', 'communique', 'date_communication'
343cfd9c
BS
1465 )
1466
1467 list_filter = (
1468 'type',
1469 'valide',
1470 'communique',
1471 )
1472
1473
e8b6a20c
BS
1474admin.site.unregister(User)
1475admin.site.register(User, RHUserAdmin)
1476
53ae644d
OL
1477admin.site.register(rh.Classement, ClassementAdmin)
1478admin.site.register(rh.Devise, DeviseAdmin)
1479admin.site.register(rh.Dossier, DossierAdmin)
22343fe7 1480admin.site.register(EmployeProxy, EmployeProxyAdmin)
5c0f1778 1481admin.site.register(ServiceProxy, ServiceProxyAdmin)
53ae644d 1482admin.site.register(rh.Employe, EmployeAdmin)
7bf28694 1483admin.site.register(rh.CategorieEmploi, CategorieEmploiAdmin)
321fe481 1484admin.site.register(rh.FamilleProfessionnelle)
53ae644d
OL
1485admin.site.register(rh.OrganismeBstg, OrganismeBstgAdmin)
1486admin.site.register(rh.Poste, PosteAdmin)
fc4bf968
EMS
1487admin.site.register(
1488 rh.ResponsableImplantationProxy, ResponsableImplantationAdmin
1489)
53ae644d 1490admin.site.register(rh.Service, ServiceAdmin)
c5964dc2 1491admin.site.register(rh.Statut, StatutAdmin)
53ae644d 1492admin.site.register(rh.TauxChange, TauxChangeAdmin)
c5964dc2 1493admin.site.register(rh.TypeContrat, TypeContratAdmin)
53ae644d
OL
1494admin.site.register(rh.TypePoste, TypePosteAdmin)
1495admin.site.register(rh.TypeRemuneration, TypeRemunerationAdmin)
1496admin.site.register(rh.TypeRevalorisation, TypeRevalorisationAdmin)
1497admin.site.register(rh.ValeurPoint, ValeurPointAdmin)
82af5c19 1498admin.site.register(ImplantationProxy, ImplantationProxyAdmin)
9da4c195 1499admin.site.register(RegionProxy, RegionProxyAdmin)
343cfd9c
BS
1500admin.site.register(rh.ChangementPersonnelNotifications)
1501admin.site.register(rh.ChangementPersonnel, ChangementPersonnelAdmin)