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