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