1 # -*- encoding: utf-8 -*-
6 from ajax_select
import make_ajax_form
7 from auf
.django
.references
import models
as ref
8 from django
.contrib
.auth
.admin
import UserAdmin
9 from django
.contrib
.auth
.models
import User
10 from django
import forms
11 from django
.core
.urlresolvers
import reverse
12 from django
.contrib
import admin
13 from django
.contrib
.contenttypes
.models
import ContentType
14 from django
.conf
import settings
15 from django
.db
.models
import Q
, Count
16 from django
.template
.defaultfilters
import date
17 from django
.utils
.formats
import date_format
19 from project
import groups
20 from project
.decorators
import in_drh_or_admin
21 from project
.rh
import models
as rh
22 from project
.permissions
import user_gere_obj_de_sa_region
, \
25 user_can_change_obj
, \
28 from project
.rh
.forms
import ContratForm
, AyantDroitForm
, EmployeAdminForm
, \
29 AjaxSelect
, DossierForm
, ResponsableInlineForm
30 from project
.rh
.change_list
import ChangeList
33 def listing_par_defaut(model
, request
):
35 Teste si la requete provient de la même page.
37 if not 'HTTP_REFERER' in request
.META
.keys():
39 referer
= request
.META
['HTTP_REFERER']
40 referer
= "/".join(referer
.split('/')[3:])
41 referer
= "/%s" % referer
.split('?')[0]
42 change_list_view
= 'admin:%s_%s_changelist' % (
43 model
._meta
.app_label
,
44 model
.__name__
.lower(),)
45 return referer
!= reverse(change_list_view
)
48 class BaseAdmin(admin
.ModelAdmin
):
52 'css/admin_custom.css',
53 'jquery-autocomplete/jquery.autocomplete.css',
56 'https://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js',
57 'jquery-autocomplete/jquery.autocomplete.min.js',
61 # Admin pour reversion
63 class ArchivableAdmin(admin
.ModelAdmin
):
65 Admin pour les modèles archivables
67 list_filter
= ('archive', )
69 def queryset(self
, request
):
70 return self
.model
.avec_archives
.all()
72 def _archive(self
, obj
):
77 _archive
.short_description
= u
'Archivé'
78 _archive
.admin_order_field
= 'archive'
81 class RegionProxy(ref
.Region
):
82 """ Proxy utilisé pour les organigrammes par région """
86 verbose_name
= u
"Organigramme par région"
87 verbose_name_plural
= u
"Organigramme par région"
90 class ImplantationProxy(ref
.Implantation
):
91 """ Proxy utilisé pour les organigrammes par implantation """
95 verbose_name
= u
"Organigramme par implantations"
96 verbose_name_plural
= u
"Organigramme par implantations"
99 class ServiceProxy(rh
.Service
):
100 """ Proxy utilisé pour les organigrammes par service """
105 verbose_name
= u
"Organigramme par services"
106 verbose_name_plural
= u
"Organigramme par services"
109 class EmployeProxy(rh
.Employe
):
110 """ Proxy utilisé pour les organigrammes des employés """
114 verbose_name
= u
"Organigramme des employés"
115 verbose_name_plural
= u
"Organigramme des employés"
118 class DateRangeMixin(object):
119 prefixe_recherche_temporelle
= ""
121 def get_changelist(self
, request
, **kwargs
):
123 On filtre par défaut sur les items 'actifs'.
124 Le changelist plug le filtrage temporel.
126 if listing_par_defaut(self
.model
, request
):
127 params
= request
.GET
.copy()
128 params
.update({'statut': 'Actif'})
133 # Override of the InlineModelAdmin to support the link in the tabular inline
134 class LinkedInline(admin
.options
.InlineModelAdmin
):
135 template
= "admin/linked.html"
136 admin_model_path
= None
138 def __init__(self
, *args
):
139 super(LinkedInline
, self
).__init__(*args
)
140 if self
.admin_model_path
is None:
141 self
.admin_model_path
= self
.model
.__name__
.lower()
144 class ProtectRegionMixin(object):
146 def changelist_view(self
, request
, extra_context
=None):
148 On filtre par défaut sur la ZA du user connecté
150 if listing_par_defaut(self
.model
, request
):
151 if user_gere_obj_de_sa_region(request
.user
):
152 params
= request
.GET
.copy()
153 zones
= groups
.get_zones_from_user(request
.user
)
154 prefix_za
= "%s__in" % self
.model
.prefix_implantation
155 params
.update({prefix_za
: zones
})
157 return super(ProtectRegionMixin
, self
) \
158 .changelist_view(request
, extra_context
)
160 def queryset(self
, request
):
161 qs
= super(ProtectRegionMixin
, self
).queryset(request
)
163 if in_drh_or_admin(request
.user
):
166 if user_gere_obj_de_sa_region(request
.user
):
167 zones
= groups
.get_zones_from_user(request
.user
)
168 qkey
= '%s__in' % self
.model
.prefix_implantation
169 q
= Q(**{qkey
: zones
})
170 qs
= qs
.filter(q
).distinct()
174 def has_add_permission(self
, request
):
175 return user_can_add_obj(request
.user
)
177 def has_change_permission(self
, request
, obj
=None):
179 return user_can_list_obj(request
.user
)
181 return user_can_change_obj(request
.user
, obj
)
183 def has_delete_permission(self
, request
, obj
=None):
184 return user_can_delete_obj(request
.user
, obj
) if obj
else True
187 class DerniereModificationAdmin(admin
.ModelAdmin
):
189 def queryset(self
, request
):
190 qs
= super(DerniereModificationAdmin
, self
).queryset(request
)
191 ct
= ContentType
.objects
.get_for_model(self
.model
)
192 db_table
= self
.model
._meta
.db_table
193 pk
= self
.model
._meta
.pk
.column
194 return qs
.extra(select
={
196 "SELECT action_time FROM django_admin_log "
197 "WHERE content_type_id = %d AND object_id = %s.%s "
198 "ORDER BY action_time DESC "
199 "LIMIT 1" % (ct
.id, db_table
, pk
),
203 "INNER JOIN django_admin_log l ON l.user_id = u.id "
204 "WHERE l.content_type_id = %d AND object_id = %s.%s "
205 "ORDER BY action_time DESC "
206 "LIMIT 1" % (ct
.id, db_table
, pk
),
209 def derniere_modification(self
, obj
):
211 if obj
.date_modification
:
212 text
+= obj
.date_modification
.strftime('%d-%m-%Y %H:%M')
213 if obj
.user_modification
:
214 text
+= ' par ' + obj
.user_modification
216 derniere_modification
.short_description
= u
'dernière modification'
217 derniere_modification
.admin_order_field
= 'date_modification'
222 class CommentaireInlineForm(forms
.ModelForm
):
224 def save(self
, commit
=True):
226 # Hack: reversion.VersionAdmin ne sauvegarde pas les champs qui ne
227 # sont pas explicitement dans le formulaire. Il plante cependant
228 # leur valeur dans `self.initial`. Ceci est un peu fragile. Si
229 # c'est possible, il serait plus approprié que Reversion se rende
230 # compte qu'il manque des champs.
231 instance
= super(CommentaireInlineForm
, self
).save(commit
=False)
232 if instance
.owner_id
is None and 'owner' in self
.initial
:
233 instance
.owner_id
= self
.initial
['owner']
234 if instance
.date_creation
is None and 'date_creation' in self
.initial
:
235 instance
.date_creation
= self
.initial
['date_creation']
242 class ReadOnlyInlineMixin(object):
244 def get_readonly_fields(self
, request
, obj
=None):
245 return [f
.name
for f
in self
.model
._meta
.fields
]
248 class AyantDroitInline(admin
.StackedInline
):
249 model
= rh
.AyantDroit
250 form
= AyantDroitForm
257 ('nom_affichage', 'genre'),
265 class AyantDroitCommentaireInline(admin
.TabularInline
):
266 readonly_fields
= ('owner',)
267 model
= rh
.AyantDroitCommentaire
269 form
= CommentaireInlineForm
272 class ContratInline(admin
.TabularInline
):
278 class DossierROInline(ReadOnlyInlineMixin
, LinkedInline
):
279 template
= "admin/rh/dossier/linked.html"
283 fields
= ('poste', 'date_debut', 'date_fin', )
285 def has_add_permission(self
, request
=None):
288 def has_change_permission(self
, request
, obj
=None):
291 def has_delete_permission(self
, request
, obj
=None):
295 class DossierCommentaireInline(admin
.TabularInline
):
296 readonly_fields
= ('owner',)
297 model
= rh
.DossierCommentaire
299 form
= CommentaireInlineForm
302 class DossierPieceInline(admin
.TabularInline
):
303 model
= rh
.DossierPiece
307 class EmployeInline(admin
.TabularInline
):
311 class EmployeCommentaireInline(admin
.TabularInline
):
312 readonly_fields
= ('owner',)
313 model
= rh
.EmployeCommentaire
315 form
= CommentaireInlineForm
318 class EmployePieceInline(admin
.TabularInline
):
319 model
= rh
.EmployePiece
323 class PosteCommentaireInline(admin
.TabularInline
):
324 readonly_fields
= ('owner',)
325 model
= rh
.PosteCommentaire
327 form
= CommentaireInlineForm
330 class PosteFinancementInline(admin
.TabularInline
):
331 model
= rh
.PosteFinancement
334 class PostePieceInline(admin
.TabularInline
):
335 model
= rh
.PostePiece
338 class RemunerationInline(admin
.TabularInline
):
339 model
= rh
.Remuneration
343 class RemunerationROInline(ReadOnlyInlineMixin
, RemunerationInline
):
347 class TypePosteInline(admin
.TabularInline
):
351 class PosteComparaisonInline(admin
.TabularInline
):
352 model
= rh
.PosteComparaison
355 class ClassementAdmin(reversion
.VersionAdmin
,
357 DerniereModificationAdmin
,
359 ignore_duplicate_revisions
= True
360 list_display
= ('_classement', 'derniere_modification', '_archive')
361 list_filter
= ('archive', )
365 'degre', 'coefficient', 'archive')}),
368 def _classement(self
, obj
):
370 _classement
.short_description
= u
"Classement"
373 class DeviseAdmin(reversion
.VersionAdmin
, ArchivableAdmin
,
374 DerniereModificationAdmin
, BaseAdmin
):
375 ignore_duplicate_revisions
= True
377 'code', 'nom', '_archive', 'derniere_modification',
379 list_filter
= ('archive', )
381 (None, {'fields': ('code', 'nom', 'archive', )}),
385 class DossierAdmin(DateRangeMixin
, ProtectRegionMixin
, reversion
.VersionAdmin
,
386 AjaxSelect
, DerniereModificationAdmin
, BaseAdmin
):
387 change_list_template
= "admin/rh/dossier/change_list.html"
388 ignore_duplicate_revisions
= True
389 alphabet_filter
= 'employe__nom'
397 'poste__nom_feminin',
398 'poste__implantation__nom',
406 '_zone_administrative',
410 'derniere_modification',
413 list_display_links
= ('_nom',)
415 'poste__implantation__zone_administrative',
416 'poste__implantation',
417 'poste__type_poste__categorie_emploi',
419 'rh_contrats__type_contrat',
422 inlines
= (DossierPieceInline
, ContratInline
,
424 DossierCommentaireInline
,
433 'organisme_bstg',)}),
438 'remplacement_de', )}),
442 ('regime_travail', 'regime_travail_nb_heure_semaine'),)}),
443 ('Occupation du Poste par cet Employe', {
444 'fields': (('date_debut', 'date_fin'), )}
447 form
= make_ajax_form(rh
.Dossier
, {
448 'employe': 'employes',
450 'remplacement_de': 'dossiers',
451 }, superclass
=DossierForm
)
453 def lookup_allowed(self
, key
, value
):
455 'employe__nom__istartswith',
456 'poste__implantation__zone_administrative__code__exact',
457 'poste__implantation__zone_administrative__in',
458 'poste__implantation__id__exact',
459 'poste__type_poste__id__exact',
460 'poste__type_poste__categorie_emploi__id__exact',
461 'rh_contrats__type_contrat__id__exact',
469 _id
.short_description
= u
"#"
470 _id
.admin_order_field
= "id"
472 def _apercu(self
, d
):
473 apercu_link
= u
"""<a title="Aperçu du dossier"
474 onclick="return showAddAnotherPopup(this);"
476 <img src="%simg/dossier-apercu.png" />
478 (reverse('dossier_apercu', args
=(d
.id,)),
482 _apercu
.allow_tags
= True
483 _apercu
.short_description
= u
""
487 _nom
.allow_tags
= True
488 _nom
.short_description
= u
"Dossier"
490 def _employe(self
, obj
):
491 employe
= obj
.employe
492 view_link
= reverse('employe_apercu', args
=(employe
.id,))
493 edit_link
= reverse('admin:rh_employe_change', args
=(employe
.id,))
495 view
= u
"""<a href="%s"
496 title="Aperçu l'employé"
497 onclick="return showAddAnotherPopup(this);">
498 <img src="%simg/employe-apercu.png" />
499 </a>""" % (view_link
, settings
.STATIC_URL
,)
500 return u
"""%s<a href='%s' style="%s;">%s</a>""" % \
501 (view
, edit_link
, style
, employe
)
502 _employe
.allow_tags
= True
503 _employe
.short_description
= u
"Employé"
504 _employe
.admin_order_field
= "employe__nom"
506 def _poste(self
, dossier
):
507 link
= u
"""<a title="Aperçu du poste"
508 onclick="return showAddAnotherPopup(this);"
509 href='%s'><img src="%simg/poste-apercu.png" />
511 <a href="%s" title="Modifier le poste">%s [%d]</a>""" % \
512 (reverse('poste_apercu', args
=(dossier
.poste
.id,)),
514 reverse('admin:rh_poste_change', args
=(dossier
.poste
.id,)),
519 _poste
.allow_tags
= True
520 _poste
.short_description
= u
'Poste'
521 _poste
.admin_order_field
= 'poste__nom'
523 def _zone_administrative(self
, obj
):
524 return obj
.poste
.implantation
.zone_administrative
.code
525 _zone_administrative
.short_description
= u
"Zone administrative"
526 _zone_administrative
.admin_order_field
= \
527 'poste__implantation__zone_administrative__code'
529 def _implantation(self
, obj
):
530 return obj
.poste
.implantation
.nom
531 _implantation
.short_description
= u
"Implantation"
532 _implantation
.admin_order_field
= 'poste__implantation__nom'
534 def _date_debut(self
, obj
):
535 return date(obj
.date_debut
)
537 _date_debut
.short_description
= u
'Début'
538 _date_debut
.admin_order_field
= 'date_debut'
540 def _date_fin(self
, obj
):
541 return date(obj
.date_fin
)
542 _date_fin
.short_description
= u
'Fin'
543 _date_fin
.admin_order_field
= 'date_fin'
545 def _date_modification(self
, obj
):
546 return date(obj
.date_modification
) \
547 if obj
.date_modification
is not None else "(aucune)"
548 _date_modification
.short_description
= u
'date modification'
549 _date_modification
.admin_order_field
= 'date_modification'
553 dossiers_dae
= d
.dossiers_dae
.all()
554 if len(dossiers_dae
) > 0:
555 dossier_dae
= dossiers_dae
[0]
556 apercu_link
= u
"""<a title="Aperçu du dossier"
557 onclick="return showAddAnotherPopup(this);"
559 <img src="%simg/loupe.png" />
561 (reverse('embauche_consulter', args
=(dossier_dae
.id,)),
565 _dae
.allow_tags
= True
566 _dae
.short_description
= u
"DAE"
568 def save_formset(self
, request
, form
, formset
, change
):
569 instances
= formset
.save(commit
=False)
570 for instance
in instances
:
571 if instance
.__class__
== rh
.DossierCommentaire
:
572 instance
.owner
= request
.user
573 instance
.date_creation
= datetime
.datetime
.now()
577 class EmployeAdminBase(DateRangeMixin
, ProtectRegionMixin
,
578 DerniereModificationAdmin
, BaseAdmin
):
579 prefixe_recherche_temporelle
= "rh_dossiers__"
580 alphabet_filter
= 'nom'
581 DEFAULT_ALPHABET
= u
'ABCDEFGHIJKLMNOPQRSTUVWXYZ'
583 'id', 'nom', 'prenom', 'nom_affichage',
584 'rh_dossiers__poste__nom',
585 'rh_dossiers__poste__nom_feminin'
588 form
= EmployeAdminForm
590 '_id', '_apercu', '_nom', '_dossiers_postes',
591 #'_zone_administrative',
594 'derniere_modification'
596 list_display_links
= ('_nom',)
598 'rh_dossiers__poste__implantation__zone_administrative',
599 'rh_dossiers__poste__implantation', 'nb_postes'
602 AyantDroitInline
, DossierROInline
, EmployePieceInline
,
603 EmployeCommentaireInline
609 ('nom_affichage', 'genre'),
614 ('Informations personnelles', {
615 'fields': ('situation_famille', 'date_entree', )
617 ('Coordonnées personnelles', {
619 ('tel_domicile', 'tel_cellulaire'),
620 ('adresse', 'ville'),
621 ('code_postal', 'province'),
630 _id
.short_description
= u
"#"
631 _id
.admin_order_field
= "id"
633 def _apercu(self
, obj
):
634 return u
"""<a title="Aperçu de l'employé"
635 onclick="return showAddAnotherPopup(this);"
637 <img src="%simg/employe-apercu.png" />
639 (reverse('employe_apercu', args
=(obj
.id,)), settings
.STATIC_URL
)
640 _apercu
.allow_tags
= True
641 _apercu
.short_description
= u
""
644 edit_link
= reverse('admin:rh_employe_change', args
=(obj
.id,))
645 return u
"""<a href='%s'><strong>%s</strong></a>""" % \
646 (edit_link
, "%s %s" % (obj
.nom
.upper(), obj
.prenom
))
647 _nom
.allow_tags
= True
648 _nom
.short_description
= u
"Employé"
649 _nom
.admin_order_field
= "nom"
651 def _zone_administrative(self
, obj
):
653 d
= rh
.Dossier
.objects
.filter(employe
=obj
.id, principal
=True)[0]
654 zone
= d
.poste
.implantation
.zone_administrative
.code
658 _zone_administrative
.short_description
= u
"Zone administrative"
660 def _implantation(self
, obj
):
662 d
= rh
.Dossier
.objects
.filter(employe
=obj
.id, principal
=True)[0]
663 implantation
= d
.poste
.implantation
.nom
667 _implantation
.short_description
= u
"Implantation"
669 def _dossiers_postes(self
, obj
):
671 for d
in obj
.rh_dossiers
.all().order_by('-date_debut'):
674 if d
.date_fin
is not None and d
.date_fin
< datetime
.date
.today():
675 link_style
= u
' style="color:#666;"'
676 list_style
= u
' style="color:grey;"'
678 dossier
= u
"""<a title="Aperçu du dossier"
680 onclick="return showAddAnotherPopup(this);"
681 title="Aperçu du dossier">
682 <img src="%simg/dossier-apercu.png" />
684 <a href="%s"%s>Dossier</a>
686 (reverse('dossier_apercu', args
=(d
.id,)),
688 reverse('admin:rh_dossier_change', args
=(d
.id,)),
691 poste
= u
"""<a title="Aperçu du poste"
693 onclick="return showAddAnotherPopup(this);"
694 title="Aperçu du poste">
695 <img src="%simg/poste-apercu.png" />
697 <a href="%s"%s>%s [%d]</a>
699 (reverse('poste_apercu', args
=(d
.poste
.id,)),
701 reverse('admin:rh_poste_change', args
=(d
.poste
.id,)),
706 link
= u
"""<li%s>%s %s</li>""" % \
707 (list_style
, dossier
, poste
)
710 return "<ul>%s</ul>" % "\n".join(l
)
711 _dossiers_postes
.allow_tags
= True
712 _dossiers_postes
.short_description
= u
"Dossiers et postes"
714 def _date_modification(self
, obj
):
715 return date(obj
.date_modification
) \
716 if obj
.date_modification
is not None else "(aucune)"
717 _date_modification
.short_description
= u
'date modification'
718 _date_modification
.admin_order_field
= 'date_modification'
720 def queryset(self
, request
):
721 qs
= super(EmployeAdminBase
, self
).queryset(request
)
722 return qs
.select_related(depth
=1).order_by('nom')
724 def save_formset(self
, request
, form
, formset
, change
):
725 instances
= formset
.save(commit
=False)
726 for instance
in instances
:
727 if instance
.__class__
== rh
.EmployeCommentaire
:
728 instance
.owner
= request
.user
729 instance
.date_creation
= datetime
.datetime
.now()
733 class EmployeAdmin(reversion
.VersionAdmin
, EmployeAdminBase
):
734 change_list_template
= "admin/rh/employe/change_list.html"
735 ignore_duplicate_revisions
= True
738 class EmployeProxyAdmin(EmployeAdminBase
):
739 list_display
= ('_id', '_apercu', '_nom', '_organigramme')
743 def __init__(self
, *args
, **kwargs
):
744 super(EmployeProxyAdmin
, self
).__init__(*args
, **kwargs
)
745 self
.list_display_links
= (None, )
747 def queryset(self
, request
):
748 qs
= super(ProtectRegionMixin
, self
).queryset(request
)
750 if in_drh_or_admin(request
.user
) or \
751 user_gere_obj_de_sa_region(request
.user
):
756 def has_add_permission(self
, obj
):
759 def has_change_permission(self
, request
, obj
=None):
760 user_groups
= [g
.name
for g
in request
.user
.groups
.all()]
761 if groups
.CORRESPONDANT_RH
in user_groups
or \
762 groups
.ADMINISTRATEURS
in user_groups
or \
763 groups
.DIRECTEUR_DE_BUREAU
in user_groups
or \
764 in_drh_or_admin(request
.user
):
768 def _organigramme(self
, obj
):
770 for d
in rh
.Dossier
.objects
.filter(
771 Q(date_fin__gt
=datetime
.date
.today()) |
Q(date_fin
=None),
772 Q(date_debut__lt
=datetime
.date
.today()) |
Q(date_debut
=None),
776 u
'Organigramme, niveau: ' \
777 u
'<input type="text" id="level_%s" ' \
778 u
'style="width:30px;height:15px;" /> ' \
779 u
'<input type="button" value="Générer" ' \
780 u
"""onclick="window.location='%s' + """ \
781 u
"""document.getElementById('level_%s').value" />""" % (
783 reverse('rho_employe_sans_niveau', args
=(d
.poste
.id,)),
786 link
= u
"""<li>%s [%s]:<br />%s</li>""" % (
792 return "<ul>%s</ul>" % "\n".join(l
)
794 _organigramme
.allow_tags
= True
795 _organigramme
.short_description
= "Organigramme"
798 class CategorieEmploiAdmin(reversion
.VersionAdmin
,
799 DerniereModificationAdmin
, BaseAdmin
):
800 ignore_duplicate_revisions
= True
801 list_display
= ('nom', 'derniere_modification')
802 inlines
= (TypePosteInline
,)
804 (None, {'fields': ('nom', )}),
808 class OrganismeBstgAdmin(reversion
.VersionAdmin
, DerniereModificationAdmin
,
810 ignore_duplicate_revisions
= True
811 search_fields
= ('nom',)
812 list_display
= ('nom', 'type', 'pays', 'derniere_modification')
813 list_filter
= ('type', )
814 inlines
= (DossierROInline
,)
816 (None, {'fields': ('nom', 'type', 'pays',)}),
820 class PosteAdmin(DateRangeMixin
, ProtectRegionMixin
, reversion
.VersionAdmin
,
821 AjaxSelect
, DerniereModificationAdmin
, BaseAdmin
):
822 change_list_template
= "admin/rh/poste/change_list.html"
823 ignore_duplicate_revisions
= True
824 form
= make_ajax_form(rh
.Poste
, {
825 'implantation': 'implantations',
826 'type_poste': 'typepostes',
827 'responsable': 'postes',
828 'valeur_point_min': 'valeurpoints',
829 'valeur_point_max': 'valeurpoints',
831 alphabet_filter
= 'nom'
836 'implantation__zone_administrative__code',
837 'implantation__zone_administrative__nom',
838 'rh_dossiers__employe__id',
839 'rh_dossiers__employe__nom',
840 'rh_dossiers__employe__prenom',
843 '_id', '_apercu', '_nom', '_occupe_par', 'implantation', '_service',
844 '_responsable', 'date_debut', 'date_fin', 'derniere_modification',
848 'implantation__zone_administrative',
852 'type_poste__categorie_emploi',
853 'type_poste__famille_professionnelle',
856 list_display_links
= ('_nom',)
859 ('nom', 'nom_feminin'),
869 'regime_travail_nb_heure_semaine'),
873 'fields': (('local', 'expatrie', 'mise_a_disposition', 'appel'),)}
876 'fields': (('classement_min',
889 ('Comparatifs de rémunération', {
890 'fields': ('devise_comparaison',
891 ('comp_locale_min', 'comp_locale_max'),
892 ('comp_universite_min', 'comp_universite_max'),
893 ('comp_fonctionpub_min', 'comp_fonctionpub_max'),
894 ('comp_ong_min', 'comp_ong_max'),
895 ('comp_autre_min', 'comp_autre_max'))}
898 'fields': ('justification',)}
900 ('Autres Méta-données', {
901 'fields': ('date_debut', 'date_fin')}
905 inlines
= (PosteFinancementInline
,
908 PosteComparaisonInline
,
909 PosteCommentaireInline
, )
911 def lookup_allowed(self
, key
, value
):
913 'date_debut__gte', 'date_debut__isnull', 'date_fin__lte',
915 'implantation__zone_administrative__code__exact',
916 'implantation__id__exact', 'type_poste__id__exact',
917 'type_poste__categorie_emploi__id__exact', 'service__id__exact',
918 'service__isnull', 'vacant__exact', 'vacant__isnull'
919 ) or super(PosteAdmin
, self
).lookup_allowed(key
, value
)
923 _id
.short_description
= '#'
924 _id
.admin_order_field
= 'id'
926 def _apercu(self
, poste
):
927 view_link
= u
"""<a onclick="return showAddAnotherPopup(this);"
928 title="Aperçu du poste"
930 <img src="%simg/poste-apercu.png" />
932 (reverse('poste_apercu', args
=(poste
.id,)),
933 settings
.STATIC_URL
,)
935 _apercu
.allow_tags
= True
936 _apercu
.short_description
= ''
938 def _nom(self
, poste
):
939 return """<a href="%s">%s</a>""" % \
940 (reverse('admin:rh_poste_change', args
=(poste
.id,)),
942 _nom
.allow_tags
= True
943 _nom
.short_description
= u
'Poste'
944 _nom
.admin_order_field
= 'nom'
946 def _occupe_par(self
, obj
):
947 """Formatte la méthode Poste.occupe_par() pour l'admin"""
949 if obj
.date_fin
is not None and obj
.date_fin
< datetime
.date
.today():
951 employes
= obj
.occupe_par()
955 link
= u
"""<a href='%s'
956 title='Aperçu de l\'employé'
957 onclick='return showAddAnotherPopup(this)'>
958 <img src='%simg/employe-apercu.png' />
960 <a href='%s'>%s</a>""" % \
961 (reverse('employe_apercu', args
=(e
.id,)),
963 reverse('admin:rh_employe_change', args
=(e
.id,)),
966 output
= "\n<br />".join(l
)
968 _occupe_par
.allow_tags
= True
969 _occupe_par
.short_description
= "Occupé par"
971 def _zone_administrative(self
, poste
):
972 return poste
.implantation
.zone_administrative
.code
973 _zone_administrative
.short_description
= 'Zone administrative'
974 _zone_administrative
.admin_order_field
= \
975 'implantation__zone_administrative__code'
977 def _implantation(self
, poste
):
978 return poste
.implantation
.nom
979 _implantation
.short_description
= 'Implantation'
980 _implantation
.admin_order_field
= 'implantation'
982 def _service(self
, obj
):
984 _service
.short_description
= 'Service'
985 _service
.allow_tags
= True
987 def _responsable(self
, obj
):
989 responsable
= u
"""<a href="%s"
990 onclick="return showAddAnotherPopup(this)">
991 <img src="%simg/poste-apercu.png"
992 title="Aperçu du poste" />
994 <a href="%s">%s [%d]</a>
996 (reverse('poste_apercu', args
=(obj
.responsable
.id,)),
998 reverse('admin:rh_poste_change', args
=(obj
.responsable
.id,)),
1005 dossier
= obj
.responsable
.rh_dossiers
.all() \
1006 .order_by('-date_debut')[0]
1007 employe_id
= dossier
.employe
.id
1008 employe_html
= u
"""<br />
1010 onclick="return showAddAnotherPopup(this)">
1011 <img src="%simg/employe-apercu.png"
1012 title="Aperçu de l'employé">
1014 <a href="%s">%s</a>""" % \
1015 (reverse('employe_apercu', args
=(employe_id
,)),
1016 settings
.STATIC_URL
,
1017 reverse('admin:rh_employe_change', args
=(employe_id
,)),
1022 return "%s %s" % (responsable
, employe_html
)
1023 _responsable
.short_description
= 'Responsable'
1024 _responsable
.allow_tags
= True
1026 def _date_debut(self
, obj
):
1027 return date_format(obj
.date_debut
)
1028 _date_debut
.short_description
= u
'Début'
1029 _date_debut
.admin_order_field
= 'date_debut'
1031 def _date_fin(self
, obj
):
1032 return date_format(obj
.date_fin
)
1033 _date_fin
.short_description
= u
'Fin'
1034 _date_fin
.admin_order_field
= 'date_fin'
1036 def _dae(self
, poste
):
1038 postes_dae
= poste
.postes_dae
.all()
1039 if len(postes_dae
) > 0:
1040 poste_dae
= postes_dae
[0]
1042 u
'<a title="Aperçu du dossier" href="%s" ' \
1043 u
'onclick="return showAddAnotherPopup(this);">' \
1044 u
'<img src="%simg/loupe.png" /></a>' % (reverse(
1045 'poste_consulter', args
=("dae-%s" % poste_dae
.id,)
1046 ), settings
.STATIC_URL
)
1048 _dae
.allow_tags
= True
1049 _dae
.short_description
= u
"DAE"
1051 def save_formset(self
, request
, form
, formset
, change
):
1052 instances
= formset
.save(commit
=False)
1053 for instance
in instances
:
1054 if instance
.__class__
== rh
.PosteCommentaire
:
1055 instance
.owner
= request
.user
1056 instance
.date_creation
= datetime
.datetime
.now()
1061 class ResponsableInline(admin
.TabularInline
):
1062 model
= rh
.ResponsableImplantation
1064 fk_name
= "implantation"
1065 form
= ResponsableInlineForm
1068 class ResponsableImplantationAdmin(BaseAdmin
):
1071 inlines
= (ResponsableInline
, )
1072 list_filter
= ('zone_administrative', 'statut', )
1073 list_display
= ('_zone_administrative', '_nom', 'statut', '_responsable', )
1074 list_display_links
= ('_nom',)
1076 readonly_fields
= ('nom', )
1079 'responsable__employe__id',
1080 'responsable__employe__nom',
1081 'responsable__employe__prenom',
1084 inlines
= (ResponsableInline
, )
1086 def _zone_administrative(self
, obj
):
1087 return obj
.zone_administrative
.code
1088 _zone_administrative
.short_description
= u
"Zone administrative"
1089 _zone_administrative
.admin_order_field
= 'zone_administrative__code'
1091 def _nom(self
, obj
):
1093 _nom
.short_description
= u
"Implantation"
1094 _nom
.admin_order_field
= 'nom'
1096 def _responsable(self
, obj
):
1098 employe
= employe
= obj
.responsable
.employe
1099 except Exception, e
:
1101 u
"<span style='color: red;'>"
1102 u
"Pas de responsable</span><!-- %s -->" % e
1105 dossiers
= employe
.dossiers_encours()
1106 if len(dossiers
) == 0:
1107 return u
"<span style='color: red;'>%s %s </span>" % (
1108 employe
, u
"sans dossier actif")
1111 except Exception, e
:
1112 return u
"<!-- %s -->" % e
1113 _responsable
.allow_tags
= True
1114 _responsable
.short_description
= u
"Responsable"
1115 _responsable
.admin_order_field
= 'responsable__employe__nom'
1117 def has_add_permission(self
, request
=None):
1120 def has_change_permission(self
, request
, obj
=None):
1121 return in_drh_or_admin(request
.user
)
1123 def has_delete_permission(self
, request
, obj
=None):
1127 class ServiceAdminBase(ArchivableAdmin
, DerniereModificationAdmin
, BaseAdmin
):
1128 list_display
= ('nom', '_archive', 'derniere_modification')
1129 list_filter
= ('archive', )
1131 (None, {'fields': ('nom', 'archive')}),
1135 class ServiceAdmin(reversion
.VersionAdmin
, ServiceAdminBase
):
1136 ignore_duplicate_revisions
= True
1139 class ServiceProxyAdmin(ServiceAdminBase
):
1140 list_display
= ('nom', '_organigramme', '_archive', )
1143 def __init__(self
, *args
, **kwargs
):
1144 super(ServiceProxyAdmin
, self
).__init__(*args
, **kwargs
)
1145 self
.list_display_links
= (None, )
1147 def queryset(self
, request
):
1148 return super(ServiceProxyAdmin
, self
).queryset(request
) \
1149 .annotate(num_postes
=Count('rh_postes')) \
1150 .filter(num_postes__gt
=0)
1152 def has_add_permission(self
, obj
):
1155 def has_change_permission(self
, request
, obj
=None):
1156 user_groups
= [g
.name
for g
in request
.user
.groups
.all()]
1157 if groups
.CORRESPONDANT_RH
in user_groups
or \
1158 groups
.ADMINISTRATEURS
in user_groups
or \
1159 groups
.DIRECTEUR_DE_BUREAU
in user_groups
or \
1160 in_drh_or_admin(request
.user
):
1164 def _organigramme(self
, obj
):
1165 return """<a href="%s"><strong>Organigramme</strong></a>""" % \
1166 (reverse('rho_service', args
=(obj
.id,)))
1167 _organigramme
.allow_tags
= True
1168 _organigramme
.short_description
= "Organigramme"
1171 class StatutAdmin(reversion
.VersionAdmin
,
1173 DerniereModificationAdmin
,
1175 ignore_duplicate_revisions
= True
1176 list_display
= ('code', 'nom', 'derniere_modification', '_archive')
1177 list_filter
= ('archive', )
1180 'fields': ('code', 'nom', 'archive'),
1185 class TauxChangeAdmin(reversion
.VersionAdmin
, DerniereModificationAdmin
,
1187 ignore_duplicate_revisions
= True
1188 list_display
= ('taux', 'devise', 'annee', 'derniere_modification')
1189 list_filter
= ('devise',)
1192 'fields': ('taux', 'devise', 'annee', ),
1197 class TypeContratAdmin(reversion
.VersionAdmin
,
1199 DerniereModificationAdmin
,
1201 ignore_duplicate_revisions
= True
1202 list_display
= ('nom', 'nom_long', 'derniere_modification', '_archive')
1203 list_filter
= ('archive', )
1206 'fields': ('nom', 'nom_long', 'archive'),
1211 class TypePosteAdmin(reversion
.VersionAdmin
,
1213 DerniereModificationAdmin
,
1215 ignore_duplicate_revisions
= True
1216 search_fields
= ('nom', 'nom_feminin', )
1217 list_display
= ('nom', 'categorie_emploi',
1218 'derniere_modification', '_archive',)
1219 list_filter
= ('categorie_emploi', 'famille_professionnelle', 'archive')
1223 'nom', 'nom_feminin', 'is_responsable', 'categorie_emploi',
1224 'famille_professionnelle',
1231 class TypeRemunerationAdmin(reversion
.VersionAdmin
, ArchivableAdmin
,
1232 DerniereModificationAdmin
, BaseAdmin
):
1233 ignore_duplicate_revisions
= True
1235 'nom', 'type_paiement', 'nature_remuneration', '_archive',
1236 'derniere_modification'
1238 list_filter
= ('archive', )
1242 'nom', 'type_paiement', 'nature_remuneration', 'archive'
1248 class TypeRevalorisationAdmin(reversion
.VersionAdmin
,
1250 DerniereModificationAdmin
,
1252 ignore_duplicate_revisions
= True
1253 list_display
= ('nom', 'derniere_modification', '_archive')
1254 list_filter
= ('archive', )
1256 (None, {'fields': ('nom', 'archive')}),
1260 class ValeurPointAdmin(reversion
.VersionAdmin
,
1261 DerniereModificationAdmin
,
1263 ignore_duplicate_revisions
= True
1265 '_devise_code', '_devise_nom', 'annee', 'implantation',
1266 'valeur', 'derniere_modification'
1268 list_filter
= ('annee', 'devise', 'implantation__zone_administrative', )
1270 (None, {'fields': ('valeur', 'devise', 'implantation', 'annee')}),
1273 def queryset(self
, request
):
1274 return super(ValeurPointAdmin
, self
).queryset(request
) \
1275 .select_related('devise', 'implantation')
1277 def _devise_code(self
, obj
):
1278 return obj
.devise
.code
1279 _devise_code
.short_description
= "Code de la devise"
1281 def _devise_nom(self
, obj
):
1282 return obj
.devise
.nom
1283 _devise_nom
.short_description
= "Nom de la devise"
1286 class ImplantationProxyAdmin(BaseAdmin
):
1287 list_display
= ('nom', '_organigramme')
1290 def __init__(self
, *args
, **kwargs
):
1291 super(ImplantationProxyAdmin
, self
).__init__(*args
, **kwargs
)
1292 self
.list_display_links
= (None, )
1294 def has_add_permission(self
, obj
):
1297 def has_change_permission(self
, request
, obj
=None):
1298 user_groups
= [g
.name
for g
in request
.user
.groups
.all()]
1299 if groups
.CORRESPONDANT_RH
in user_groups
or \
1300 groups
.ADMINISTRATEURS
in user_groups
or \
1301 groups
.DIRECTEUR_DE_BUREAU
in user_groups
or \
1302 in_drh_or_admin(request
.user
):
1306 def _organigramme(self
, obj
):
1307 return '<a href="%s"><strong>Organigramme</strong></a>' % (
1308 reverse('rho_implantation', args
=(obj
.id,))
1310 _organigramme
.allow_tags
= True
1311 _organigramme
.short_description
= "Organigramme"
1314 class RegionProxyAdmin(BaseAdmin
):
1315 list_display
= ('nom', '_organigramme')
1318 def __init__(self
, *args
, **kwargs
):
1319 super(RegionProxyAdmin
, self
).__init__(*args
, **kwargs
)
1320 self
.list_display_links
= (None, )
1322 def has_add_permission(self
, obj
):
1325 def has_change_permission(self
, request
, obj
=None):
1326 user_groups
= [g
.name
for g
in request
.user
.groups
.all()]
1327 if groups
.CORRESPONDANT_RH
in user_groups
or \
1328 groups
.ADMINISTRATEURS
in user_groups
or \
1329 groups
.DIRECTEUR_DE_BUREAU
in user_groups
or \
1330 in_drh_or_admin(request
.user
):
1334 def _organigramme(self
, obj
):
1335 return """<a href="%s"><strong>Organigramme</strong></a>""" % (
1336 reverse('rho_region', args
=(obj
.id,))
1338 _organigramme
.allow_tags
= True
1339 _organigramme
.short_description
= "Organigramme"
1342 class ProfileInline(admin
.StackedInline
):
1343 model
= rh
.UserProfile
1346 class RHUserAdmin(UserAdmin
):
1347 inlines
= list(UserAdmin
.inlines
) + [ProfileInline
]
1350 admin
.site
.unregister(User
)
1351 admin
.site
.register(User
, RHUserAdmin
)
1353 admin
.site
.register(rh
.Classement
, ClassementAdmin
)
1354 admin
.site
.register(rh
.Devise
, DeviseAdmin
)
1355 admin
.site
.register(rh
.Dossier
, DossierAdmin
)
1356 admin
.site
.register(EmployeProxy
, EmployeProxyAdmin
)
1357 admin
.site
.register(ServiceProxy
, ServiceProxyAdmin
)
1358 admin
.site
.register(rh
.Employe
, EmployeAdmin
)
1359 admin
.site
.register(rh
.CategorieEmploi
, CategorieEmploiAdmin
)
1360 admin
.site
.register(rh
.FamilleProfessionnelle
)
1361 admin
.site
.register(rh
.OrganismeBstg
, OrganismeBstgAdmin
)
1362 admin
.site
.register(rh
.Poste
, PosteAdmin
)
1363 admin
.site
.register(
1364 rh
.ResponsableImplantationProxy
, ResponsableImplantationAdmin
1366 admin
.site
.register(rh
.Service
, ServiceAdmin
)
1367 admin
.site
.register(rh
.Statut
, StatutAdmin
)
1368 admin
.site
.register(rh
.TauxChange
, TauxChangeAdmin
)
1369 admin
.site
.register(rh
.TypeContrat
, TypeContratAdmin
)
1370 admin
.site
.register(rh
.TypePoste
, TypePosteAdmin
)
1371 admin
.site
.register(rh
.TypeRemuneration
, TypeRemunerationAdmin
)
1372 admin
.site
.register(rh
.TypeRevalorisation
, TypeRevalorisationAdmin
)
1373 admin
.site
.register(rh
.ValeurPoint
, ValeurPointAdmin
)
1374 admin
.site
.register(ImplantationProxy
, ImplantationProxyAdmin
)
1375 admin
.site
.register(RegionProxy
, RegionProxyAdmin
)