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