1 # -*- encoding: utf-8 -*-
6 from ajax_select
import make_ajax_form
7 from auf
.django
.references
import models
as ref
8 from django
import forms
9 from django
.core
.urlresolvers
import reverse
10 from django
.contrib
import admin
11 from django
.contrib
.contenttypes
.models
import ContentType
12 from django
.conf
import settings
13 from django
.db
.models
import Q
, Count
14 from django
.template
.defaultfilters
import date
15 from django
.utils
.formats
import date_format
17 from project
import groups
18 from project
.decorators
import in_drh_or_admin
19 from project
.rh
import models
as rh
20 from project
.permissions
import user_gere_obj_de_sa_region
, \
23 user_can_change_obj
, \
24 user_can_delete_obj
, \
27 from project
.rh
.forms
import ContratForm
, AyantDroitForm
, EmployeAdminForm
, \
28 AjaxSelect
, DossierForm
, ResponsableInlineForm
29 from project
.rh
.change_list
import ChangeList
32 def listing_par_defaut(model
, request
):
34 Teste si la requete provient de la même page.
36 if not 'HTTP_REFERER' in request
.META
.keys():
38 referer
= request
.META
['HTTP_REFERER']
39 referer
= "/".join(referer
.split('/')[3:])
40 referer
= "/%s" % referer
.split('?')[0]
41 change_list_view
= 'admin:%s_%s_changelist' % (
42 model
._meta
.app_label
,
43 model
.__name__
.lower(),)
44 return referer
!= reverse(change_list_view
)
47 class BaseAdmin(admin
.ModelAdmin
):
51 'css/admin_custom.css',
52 'jquery-autocomplete/jquery.autocomplete.css',
55 'https://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js',
56 'jquery-autocomplete/jquery.autocomplete.min.js',
60 # Admin pour reversion
62 class ArchivableAdmin(admin
.ModelAdmin
):
64 Admin pour les modèles archivables
66 list_filter
= ('archive', )
68 def queryset(self
, request
):
69 return self
.model
.avec_archives
.all()
71 def _archive(self
, obj
):
76 _archive
.short_description
= u
'Archivé'
77 _archive
.admin_order_field
= 'archive'
80 class RegionProxy(ref
.Region
):
81 """ Proxy utilisé pour les organigrammes par région """
85 verbose_name
= u
"Organigramme par région"
86 verbose_name_plural
= u
"Organigramme par région"
89 class ImplantationProxy(ref
.Implantation
):
90 """ Proxy utilisé pour les organigrammes par implantation """
94 verbose_name
= u
"Organigramme par implantations"
95 verbose_name_plural
= u
"Organigramme par implantations"
98 class ServiceProxy(rh
.Service
):
99 """ Proxy utilisé pour les organigrammes par service """
104 verbose_name
= u
"Organigramme par services"
105 verbose_name_plural
= u
"Organigramme par services"
108 class EmployeProxy(rh
.Employe
):
109 """ Proxy utilisé pour les organigrammes des employés """
113 verbose_name
= u
"Organigramme des employés"
114 verbose_name_plural
= u
"Organigramme des employés"
117 class DateRangeMixin(object):
118 prefixe_recherche_temporelle
= ""
120 def get_changelist(self
, request
, **kwargs
):
122 On filtre par défaut sur les items 'actifs'.
123 Le changelist plug le filtrage temporel.
125 if listing_par_defaut(self
.model
, request
):
126 params
= request
.GET
.copy()
127 params
.update({'statut': 'Actif'})
132 # Override of the InlineModelAdmin to support the link in the tabular inline
133 class LinkedInline(admin
.options
.InlineModelAdmin
):
134 template
= "admin/linked.html"
135 admin_model_path
= None
137 def __init__(self
, *args
):
138 super(LinkedInline
, self
).__init__(*args
)
139 if self
.admin_model_path
is None:
140 self
.admin_model_path
= self
.model
.__name__
.lower()
143 class ProtectRegionMixin(object):
145 def changelist_view(self
, request
, extra_context
=None):
147 On filtre par défaut sur la ZA du user connecté
149 if listing_par_defaut(self
.model
, request
):
150 if user_gere_obj_de_sa_region(request
.user
):
151 params
= request
.GET
.copy()
152 employe
= groups
.get_employe_from_user(request
.user
)
153 za
= employe
.implantation
.zone_administrative
.code
154 prefix_za
= "%s__code__exact" % self
.model
.prefix_implantation
155 params
.update({prefix_za
: za
})
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 region_user
= get_region_user(request
.user
)
168 q
= Q(**{self
.model
.prefix_implantation
: \
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
, DerniereModificationAdmin
,
357 ignore_duplicate_revisions
= True
358 list_display
= ('_classement', 'derniere_modification')
360 (None, {'fields': ('type', 'echelon', 'degre', 'coefficient',)}),
363 def _classement(self
, obj
):
365 _classement
.short_description
= u
"Classement"
368 class DeviseAdmin(reversion
.VersionAdmin
, ArchivableAdmin
,
369 DerniereModificationAdmin
, BaseAdmin
):
370 ignore_duplicate_revisions
= True
372 'code', 'nom', '_archive', 'derniere_modification',
374 list_filter
= ('archive', )
376 (None, {'fields': ('code', 'nom', 'archive', )}),
380 class DossierAdmin(DateRangeMixin
, ProtectRegionMixin
, reversion
.VersionAdmin
,
381 AjaxSelect
, DerniereModificationAdmin
, BaseAdmin
):
382 change_list_template
= "admin/rh/dossier/change_list.html"
383 ignore_duplicate_revisions
= True
384 alphabet_filter
= 'employe__nom'
392 'poste__nom_feminin',
393 'poste__implantation__nom',
401 '_zone_administrative',
405 'derniere_modification',
408 list_display_links
= ('_nom',)
410 'poste__implantation__zone_administrative',
411 'poste__implantation',
412 'poste__type_poste__categorie_emploi',
414 'rh_contrats__type_contrat',
417 inlines
= (DossierPieceInline
, ContratInline
,
419 DossierCommentaireInline
,
428 'organisme_bstg',)}),
433 'remplacement_de', )}),
437 ('regime_travail', 'regime_travail_nb_heure_semaine'),)}),
438 ('Occupation du Poste par cet Employe', {
439 'fields': (('date_debut', 'date_fin'), )}
442 form
= make_ajax_form(rh
.Dossier
, {
443 'employe': 'employes',
445 'remplacement_de': 'dossiers',
446 }, superclass
=DossierForm
)
448 def lookup_allowed(self
, key
, value
):
450 'employe__nom__istartswith',
451 'poste__implantation__zone_administrative__code__exact',
452 'poste__implantation__id__exact',
453 'poste__type_poste__id__exact',
454 'poste__type_poste__categorie_emploi__id__exact',
455 'rh_contrats__type_contrat__id__exact',
463 _id
.short_description
= u
"#"
464 _id
.admin_order_field
= "id"
466 def _apercu(self
, d
):
467 apercu_link
= u
"""<a title="Aperçu du dossier"
468 onclick="return showAddAnotherPopup(this);"
470 <img src="%simg/dossier-apercu.png" />
472 (reverse('dossier_apercu', args
=(d
.id,)),
476 _apercu
.allow_tags
= True
477 _apercu
.short_description
= u
""
481 _nom
.allow_tags
= True
482 _nom
.short_description
= u
"Dossier"
484 def _employe(self
, obj
):
485 employe
= obj
.employe
486 view_link
= reverse('employe_apercu', args
=(employe
.id,))
487 edit_link
= reverse('admin:rh_employe_change', args
=(employe
.id,))
489 view
= u
"""<a href="%s"
490 title="Aperçu l'employé"
491 onclick="return showAddAnotherPopup(this);">
492 <img src="%simg/employe-apercu.png" />
493 </a>""" % (view_link
, settings
.STATIC_URL
,)
494 return u
"""%s<a href='%s' style="%s;">%s</a>""" % \
495 (view
, edit_link
, style
, employe
)
496 _employe
.allow_tags
= True
497 _employe
.short_description
= u
"Employé"
498 _employe
.admin_order_field
= "employe__nom"
500 def _poste(self
, dossier
):
501 link
= u
"""<a title="Aperçu du poste"
502 onclick="return showAddAnotherPopup(this);"
503 href='%s'><img src="%simg/poste-apercu.png" />
505 <a href="%s" title="Modifier le poste">%s [%d]</a>""" % \
506 (reverse('poste_apercu', args
=(dossier
.poste
.id,)),
508 reverse('admin:rh_poste_change', args
=(dossier
.poste
.id,)),
513 _poste
.allow_tags
= True
514 _poste
.short_description
= u
'Poste'
515 _poste
.admin_order_field
= 'poste__nom'
517 def _zone_administrative(self
, obj
):
518 return obj
.poste
.implantation
.zone_administrative
.code
519 _zone_administrative
.short_description
= u
"Zone administrative"
520 _zone_administrative
.admin_order_field
= \
521 'poste__implantation__zone_administrative__code'
523 def _implantation(self
, obj
):
524 return obj
.poste
.implantation
.nom
525 _implantation
.short_description
= u
"Implantation"
526 _implantation
.admin_order_field
= 'poste__implantation__nom'
528 def _date_debut(self
, obj
):
529 return date(obj
.date_debut
)
531 _date_debut
.short_description
= u
'Début'
532 _date_debut
.admin_order_field
= 'date_debut'
534 def _date_fin(self
, obj
):
535 return date(obj
.date_fin
)
536 _date_fin
.short_description
= u
'Fin'
537 _date_fin
.admin_order_field
= 'date_fin'
539 def _date_modification(self
, obj
):
540 return date(obj
.date_modification
) \
541 if obj
.date_modification
is not None else "(aucune)"
542 _date_modification
.short_description
= u
'date modification'
543 _date_modification
.admin_order_field
= 'date_modification'
547 dossiers_dae
= d
.dossiers_dae
.all()
548 if len(dossiers_dae
) > 0:
549 dossier_dae
= dossiers_dae
[0]
550 apercu_link
= u
"""<a title="Aperçu du dossier"
551 onclick="return showAddAnotherPopup(this);"
553 <img src="%simg/loupe.png" />
555 (reverse('embauche_consulter', args
=(dossier_dae
.id,)),
559 _dae
.allow_tags
= True
560 _dae
.short_description
= u
"DAE"
562 def save_formset(self
, request
, form
, formset
, change
):
563 instances
= formset
.save(commit
=False)
564 for instance
in instances
:
565 if instance
.__class__
== rh
.DossierCommentaire
:
566 instance
.owner
= request
.user
567 instance
.date_creation
= datetime
.datetime
.now()
571 class EmployeAdminBase(DateRangeMixin
, ProtectRegionMixin
,
572 DerniereModificationAdmin
, BaseAdmin
):
573 prefixe_recherche_temporelle
= "rh_dossiers__"
574 alphabet_filter
= 'nom'
575 DEFAULT_ALPHABET
= u
'ABCDEFGHIJKLMNOPQRSTUVWXYZ'
577 'id', 'nom', 'prenom', 'nom_affichage',
578 'rh_dossiers__poste__nom',
579 'rh_dossiers__poste__nom_feminin'
582 form
= EmployeAdminForm
584 '_id', '_apercu', '_nom', '_dossiers_postes',
585 #'_zone_administrative',
588 'derniere_modification'
590 list_display_links
= ('_nom',)
592 'rh_dossiers__poste__implantation__zone_administrative',
593 'rh_dossiers__poste__implantation', 'nb_postes'
596 AyantDroitInline
, DossierROInline
, EmployePieceInline
,
597 EmployeCommentaireInline
603 ('nom_affichage', 'genre'),
608 ('Informations personnelles', {
609 'fields': ('situation_famille', 'date_entree', )
611 ('Coordonnées personnelles', {
613 ('tel_domicile', 'tel_cellulaire'),
614 ('adresse', 'ville'),
615 ('code_postal', 'province'),
624 _id
.short_description
= u
"#"
625 _id
.admin_order_field
= "id"
627 def _apercu(self
, obj
):
628 return u
"""<a title="Aperçu de l'employé"
629 onclick="return showAddAnotherPopup(this);"
631 <img src="%simg/employe-apercu.png" />
633 (reverse('employe_apercu', args
=(obj
.id,)), settings
.STATIC_URL
)
634 _apercu
.allow_tags
= True
635 _apercu
.short_description
= u
""
638 edit_link
= reverse('admin:rh_employe_change', args
=(obj
.id,))
639 return u
"""<a href='%s'><strong>%s</strong></a>""" % \
640 (edit_link
, "%s %s" % (obj
.nom
.upper(), obj
.prenom
))
641 _nom
.allow_tags
= True
642 _nom
.short_description
= u
"Employé"
643 _nom
.admin_order_field
= "nom"
645 def _zone_administrative(self
, obj
):
647 d
= rh
.Dossier
.objects
.filter(employe
=obj
.id, principal
=True)[0]
648 zone
= d
.poste
.implantation
.zone_administrative
.code
652 _zone_administrative
.short_description
= u
"Zone administrative"
654 def _implantation(self
, obj
):
656 d
= rh
.Dossier
.objects
.filter(employe
=obj
.id, principal
=True)[0]
657 implantation
= d
.poste
.implantation
.nom
661 _implantation
.short_description
= u
"Implantation"
663 def _dossiers_postes(self
, obj
):
665 for d
in obj
.rh_dossiers
.all().order_by('-date_debut'):
668 if d
.date_fin
is not None and d
.date_fin
< datetime
.date
.today():
669 link_style
= u
' style="color:#666;"'
670 list_style
= u
' style="color:grey;"'
672 dossier
= u
"""<a title="Aperçu du dossier"
674 onclick="return showAddAnotherPopup(this);"
675 title="Aperçu du dossier">
676 <img src="%simg/dossier-apercu.png" />
678 <a href="%s"%s>Dossier</a>
680 (reverse('dossier_apercu', args
=(d
.id,)),
682 reverse('admin:rh_dossier_change', args
=(d
.id,)),
685 poste
= u
"""<a title="Aperçu du poste"
687 onclick="return showAddAnotherPopup(this);"
688 title="Aperçu du poste">
689 <img src="%simg/poste-apercu.png" />
691 <a href="%s"%s>%s [%d]</a>
693 (reverse('poste_apercu', args
=(d
.poste
.id,)),
695 reverse('admin:rh_poste_change', args
=(d
.poste
.id,)),
700 link
= u
"""<li%s>%s %s</li>""" % \
701 (list_style
, dossier
, poste
)
704 return "<ul>%s</ul>" % "\n".join(l
)
705 _dossiers_postes
.allow_tags
= True
706 _dossiers_postes
.short_description
= u
"Dossiers et postes"
708 def _date_modification(self
, obj
):
709 return date(obj
.date_modification
) \
710 if obj
.date_modification
is not None else "(aucune)"
711 _date_modification
.short_description
= u
'date modification'
712 _date_modification
.admin_order_field
= 'date_modification'
714 def queryset(self
, request
):
715 qs
= super(EmployeAdminBase
, self
).queryset(request
)
716 return qs
.select_related(depth
=1).order_by('nom')
718 def save_formset(self
, request
, form
, formset
, change
):
719 instances
= formset
.save(commit
=False)
720 for instance
in instances
:
721 if instance
.__class__
== rh
.EmployeCommentaire
:
722 instance
.owner
= request
.user
723 instance
.date_creation
= datetime
.datetime
.now()
727 class EmployeAdmin(reversion
.VersionAdmin
, EmployeAdminBase
):
728 change_list_template
= "admin/rh/employe/change_list.html"
729 ignore_duplicate_revisions
= True
732 class EmployeProxyAdmin(EmployeAdminBase
):
733 list_display
= ('_id', '_apercu', '_nom', '_organigramme')
737 def __init__(self
, *args
, **kwargs
):
738 super(EmployeProxyAdmin
, self
).__init__(*args
, **kwargs
)
739 self
.list_display_links
= (None, )
741 def queryset(self
, request
):
742 qs
= super(ProtectRegionMixin
, self
).queryset(request
)
744 if in_drh_or_admin(request
.user
) or \
745 user_gere_obj_de_sa_region(request
.user
):
750 def has_add_permission(self
, obj
):
753 def has_change_permission(self
, request
, obj
=None):
754 user_groups
= [g
.name
for g
in request
.user
.groups
.all()]
755 if groups
.CORRESPONDANT_RH
in user_groups
or \
756 groups
.ADMINISTRATEURS
in user_groups
or \
757 groups
.DIRECTEUR_DE_BUREAU
in user_groups
or \
758 in_drh_or_admin(request
.user
):
762 def _organigramme(self
, obj
):
764 for d
in rh
.Dossier
.objects
.filter(
765 Q(date_fin__gt
=datetime
.date
.today()) |
Q(date_fin
=None),
766 Q(date_debut__lt
=datetime
.date
.today()) |
Q(date_debut
=None),
770 u
'Organigramme, niveau: ' \
771 u
'<input type="text" id="level_%s" ' \
772 u
'style="width:30px;height:15px;" /> ' \
773 u
'<input type="button" value="Générer" ' \
774 u
"""onclick="window.location='%s' + """ \
775 u
"""document.getElementById('level_%s').value" />""" % (
777 reverse('rho_employe_sans_niveau', args
=(d
.poste
.id,)),
780 link
= u
"""<li>%s [%s]:<br />%s</li>""" % (
786 return "<ul>%s</ul>" % "\n".join(l
)
788 _organigramme
.allow_tags
= True
789 _organigramme
.short_description
= "Organigramme"
792 class CategorieEmploiAdmin(reversion
.VersionAdmin
,
793 DerniereModificationAdmin
, BaseAdmin
):
794 ignore_duplicate_revisions
= True
795 list_display
= ('nom', 'derniere_modification')
796 inlines
= (TypePosteInline
,)
798 (None, {'fields': ('nom', )}),
802 class OrganismeBstgAdmin(reversion
.VersionAdmin
, DerniereModificationAdmin
,
804 ignore_duplicate_revisions
= True
805 search_fields
= ('nom',)
806 list_display
= ('nom', 'type', 'pays', 'derniere_modification')
807 list_filter
= ('type', )
808 inlines
= (DossierROInline
,)
810 (None, {'fields': ('nom', 'type', 'pays',)}),
814 class PosteAdmin(DateRangeMixin
, ProtectRegionMixin
, reversion
.VersionAdmin
,
815 AjaxSelect
, DerniereModificationAdmin
, BaseAdmin
):
816 change_list_template
= "admin/rh/poste/change_list.html"
817 ignore_duplicate_revisions
= True
818 form
= make_ajax_form(rh
.Poste
, {
819 'implantation': 'implantations',
820 'type_poste': 'typepostes',
821 'responsable': 'postes',
822 'valeur_point_min': 'valeurpoints',
823 'valeur_point_max': 'valeurpoints',
825 alphabet_filter
= 'nom'
830 'implantation__zone_administrative__code',
831 'implantation__zone_administrative__nom',
832 'rh_dossiers__employe__id',
833 'rh_dossiers__employe__nom',
834 'rh_dossiers__employe__prenom',
837 '_id', '_apercu', '_nom', '_occupe_par', 'implantation', '_service',
838 '_responsable', 'date_debut', 'date_fin', 'derniere_modification',
842 'implantation__zone_administrative',
846 'type_poste__categorie_emploi',
847 'type_poste__famille_professionnelle',
850 list_display_links
= ('_nom',)
853 ('nom', 'nom_feminin'),
863 'regime_travail_nb_heure_semaine'),
867 'fields': (('local', 'expatrie', 'mise_a_disposition', 'appel'),)}
870 'fields': (('classement_min',
883 ('Comparatifs de rémunération', {
884 'fields': ('devise_comparaison',
885 ('comp_locale_min', 'comp_locale_max'),
886 ('comp_universite_min', 'comp_universite_max'),
887 ('comp_fonctionpub_min', 'comp_fonctionpub_max'),
888 ('comp_ong_min', 'comp_ong_max'),
889 ('comp_autre_min', 'comp_autre_max'))}
892 'fields': ('justification',)}
894 ('Autres Méta-données', {
895 'fields': ('date_debut', 'date_fin')}
899 inlines
= (PosteFinancementInline
,
902 PosteComparaisonInline
,
903 PosteCommentaireInline
, )
905 def lookup_allowed(self
, key
, value
):
907 'date_debut__gte', 'date_debut__isnull', 'date_fin__lte',
909 'implantation__zone_administrative__code__exact',
910 'implantation__id__exact', 'type_poste__id__exact',
911 'type_poste__categorie_emploi__id__exact', 'service__id__exact',
912 'service__isnull', 'vacant__exact', 'vacant__isnull'
913 ) or super(PosteAdmin
, self
).lookup_allowed(key
, value
)
917 _id
.short_description
= '#'
918 _id
.admin_order_field
= 'id'
920 def _apercu(self
, poste
):
921 view_link
= u
"""<a onclick="return showAddAnotherPopup(this);"
922 title="Aperçu du poste"
924 <img src="%simg/poste-apercu.png" />
926 (reverse('poste_apercu', args
=(poste
.id,)),
927 settings
.STATIC_URL
,)
929 _apercu
.allow_tags
= True
930 _apercu
.short_description
= ''
932 def _nom(self
, poste
):
933 return """<a href="%s">%s</a>""" % \
934 (reverse('admin:rh_poste_change', args
=(poste
.id,)),
936 _nom
.allow_tags
= True
937 _nom
.short_description
= u
'Poste'
938 _nom
.admin_order_field
= 'nom'
940 def _occupe_par(self
, obj
):
941 """Formatte la méthode Poste.occupe_par() pour l'admin"""
943 if obj
.date_fin
is not None and obj
.date_fin
< datetime
.date
.today():
945 employes
= obj
.occupe_par()
949 link
= u
"""<a href='%s'
950 title='Aperçu de l\'employé'
951 onclick='return showAddAnotherPopup(this)'>
952 <img src='%simg/employe-apercu.png' />
954 <a href='%s'>%s</a>""" % \
955 (reverse('employe_apercu', args
=(e
.id,)),
957 reverse('admin:rh_employe_change', args
=(e
.id,)),
960 output
= "\n<br />".join(l
)
962 _occupe_par
.allow_tags
= True
963 _occupe_par
.short_description
= "Occupé par"
965 def _zone_administrative(self
, poste
):
966 return poste
.implantation
.zone_administrative
.code
967 _zone_administrative
.short_description
= 'Zone administrative'
968 _zone_administrative
.admin_order_field
= \
969 'implantation__zone_administrative__code'
971 def _implantation(self
, poste
):
972 return poste
.implantation
.nom
973 _implantation
.short_description
= 'Implantation'
974 _implantation
.admin_order_field
= 'implantation'
976 def _service(self
, obj
):
978 _service
.short_description
= 'Service'
979 _service
.allow_tags
= True
981 def _responsable(self
, obj
):
983 responsable
= u
"""<a href="%s"
984 onclick="return showAddAnotherPopup(this)">
985 <img src="%simg/poste-apercu.png"
986 title="Aperçu du poste" />
988 <a href="%s">%s [%d]</a>
990 (reverse('poste_apercu', args
=(obj
.responsable
.id,)),
992 reverse('admin:rh_poste_change', args
=(obj
.responsable
.id,)),
999 dossier
= obj
.responsable
.rh_dossiers
.all() \
1000 .order_by('-date_debut')[0]
1001 employe_id
= dossier
.employe
.id
1002 employe_html
= u
"""<br />
1004 onclick="return showAddAnotherPopup(this)">
1005 <img src="%simg/employe-apercu.png"
1006 title="Aperçu de l'employé">
1008 <a href="%s">%s</a>""" % \
1009 (reverse('employe_apercu', args
=(employe_id
,)),
1010 settings
.STATIC_URL
,
1011 reverse('admin:rh_employe_change', args
=(employe_id
,)),
1016 return "%s %s" % (responsable
, employe_html
)
1017 _responsable
.short_description
= 'Responsable'
1018 _responsable
.allow_tags
= True
1020 def _date_debut(self
, obj
):
1021 return date_format(obj
.date_debut
)
1022 _date_debut
.short_description
= u
'Début'
1023 _date_debut
.admin_order_field
= 'date_debut'
1025 def _date_fin(self
, obj
):
1026 return date_format(obj
.date_fin
)
1027 _date_fin
.short_description
= u
'Fin'
1028 _date_fin
.admin_order_field
= 'date_fin'
1030 def _dae(self
, poste
):
1032 postes_dae
= poste
.postes_dae
.all()
1033 if len(postes_dae
) > 0:
1034 poste_dae
= postes_dae
[0]
1036 u
'<a title="Aperçu du dossier" href="%s" ' \
1037 u
'onclick="return showAddAnotherPopup(this);">' \
1038 u
'<img src="%simg/loupe.png" /></a>' % (reverse(
1039 'poste_consulter', args
=("dae-%s" % poste_dae
.id,)
1040 ), settings
.STATIC_URL
)
1042 _dae
.allow_tags
= True
1043 _dae
.short_description
= u
"DAE"
1045 def save_formset(self
, request
, form
, formset
, change
):
1046 instances
= formset
.save(commit
=False)
1047 for instance
in instances
:
1048 if instance
.__class__
== rh
.PosteCommentaire
:
1049 instance
.owner
= request
.user
1050 instance
.date_creation
= datetime
.datetime
.now()
1055 class ResponsableInline(admin
.TabularInline
):
1056 model
= rh
.ResponsableImplantation
1058 fk_name
= "implantation"
1059 form
= ResponsableInlineForm
1062 class ResponsableImplantationAdmin(BaseAdmin
):
1065 inlines
= (ResponsableInline
, )
1066 list_filter
= ('zone_administrative', 'statut', )
1067 list_display
= ('_zone_administrative', '_nom', 'statut', '_responsable', )
1068 list_display_links
= ('_nom',)
1070 readonly_fields
= ('nom', )
1073 'responsable__employe__id',
1074 'responsable__employe__nom',
1075 'responsable__employe__prenom',
1078 inlines
= (ResponsableInline
, )
1080 def _zone_administrative(self
, obj
):
1081 return obj
.zone_administrative
.code
1082 _zone_administrative
.short_description
= u
"Zone administrative"
1083 _zone_administrative
.admin_order_field
= 'zone_administrative__code'
1085 def _nom(self
, obj
):
1087 _nom
.short_description
= u
"Implantation"
1088 _nom
.admin_order_field
= 'nom'
1090 def _responsable(self
, obj
):
1092 employe
= employe
= obj
.responsable
.employe
1093 except Exception, e
:
1095 u
"<span style='color: red;'>"
1096 u
"Pas de responsable</span><!-- %s -->" % e
1099 dossiers
= employe
.dossiers_encours()
1100 if len(dossiers
) == 0:
1101 return u
"<span style='color: red;'>%s %s </span>" % (
1102 employe
, u
"sans dossier actif")
1105 except Exception, e
:
1106 return u
"<!-- %s -->" % e
1107 _responsable
.allow_tags
= True
1108 _responsable
.short_description
= u
"Responsable"
1109 _responsable
.admin_order_field
= 'responsable__employe__nom'
1111 def has_add_permission(self
, request
=None):
1114 def has_change_permission(self
, request
, obj
=None):
1115 return in_drh_or_admin(request
.user
)
1117 def has_delete_permission(self
, request
, obj
=None):
1121 class ServiceAdminBase(ArchivableAdmin
, DerniereModificationAdmin
, BaseAdmin
):
1122 list_display
= ('nom', '_archive', 'derniere_modification')
1123 list_filter
= ('archive', )
1125 (None, {'fields': ('nom', 'archive')}),
1129 class ServiceAdmin(reversion
.VersionAdmin
, ServiceAdminBase
):
1130 ignore_duplicate_revisions
= True
1133 class ServiceProxyAdmin(ServiceAdminBase
):
1134 list_display
= ('nom', '_organigramme', '_archive', )
1137 def __init__(self
, *args
, **kwargs
):
1138 super(ServiceProxyAdmin
, self
).__init__(*args
, **kwargs
)
1139 self
.list_display_links
= (None, )
1141 def queryset(self
, request
):
1142 return super(ServiceProxyAdmin
, self
).queryset(request
) \
1143 .annotate(num_postes
=Count('rh_postes')) \
1144 .filter(num_postes__gt
=0)
1146 def has_add_permission(self
, obj
):
1149 def has_change_permission(self
, request
, obj
=None):
1150 user_groups
= [g
.name
for g
in request
.user
.groups
.all()]
1151 if groups
.CORRESPONDANT_RH
in user_groups
or \
1152 groups
.ADMINISTRATEURS
in user_groups
or \
1153 groups
.DIRECTEUR_DE_BUREAU
in user_groups
or \
1154 in_drh_or_admin(request
.user
):
1158 def _organigramme(self
, obj
):
1159 return """<a href="%s"><strong>Organigramme</strong></a>""" % \
1160 (reverse('rho_service', args
=(obj
.id,)))
1161 _organigramme
.allow_tags
= True
1162 _organigramme
.short_description
= "Organigramme"
1165 class StatutAdmin(reversion
.VersionAdmin
, DerniereModificationAdmin
,
1167 ignore_duplicate_revisions
= True
1168 list_display
= ('code', 'nom', 'derniere_modification')
1171 'fields': ('code', 'nom', ),
1176 class TauxChangeAdmin(reversion
.VersionAdmin
, DerniereModificationAdmin
,
1178 ignore_duplicate_revisions
= True
1179 list_display
= ('taux', 'devise', 'annee', 'derniere_modification')
1180 list_filter
= ('devise',)
1183 'fields': ('taux', 'devise', 'annee', ),
1188 class TypeContratAdmin(reversion
.VersionAdmin
, DerniereModificationAdmin
,
1190 ignore_duplicate_revisions
= True
1191 list_display
= ('nom', 'nom_long', 'derniere_modification')
1194 'fields': ('nom', 'nom_long', ),
1199 class TypePosteAdmin(reversion
.VersionAdmin
, DerniereModificationAdmin
,
1201 ignore_duplicate_revisions
= True
1202 search_fields
= ('nom', 'nom_feminin', )
1203 list_display
= ('nom', 'categorie_emploi', 'derniere_modification')
1204 list_filter
= ('categorie_emploi', 'famille_professionnelle')
1208 'nom', 'nom_feminin', 'is_responsable', 'categorie_emploi',
1209 'famille_professionnelle',
1215 class TypeRemunerationAdmin(reversion
.VersionAdmin
, ArchivableAdmin
,
1216 DerniereModificationAdmin
, BaseAdmin
):
1217 ignore_duplicate_revisions
= True
1219 'nom', 'type_paiement', 'nature_remuneration', '_archive',
1220 'derniere_modification'
1222 list_filter
= ('archive', )
1226 'nom', 'type_paiement', 'nature_remuneration', 'archive'
1232 class TypeRevalorisationAdmin(reversion
.VersionAdmin
,
1233 DerniereModificationAdmin
, BaseAdmin
):
1234 ignore_duplicate_revisions
= True
1235 list_display
= ('nom', 'derniere_modification')
1237 (None, {'fields': ('nom',)}),
1241 class ValeurPointAdmin(reversion
.VersionAdmin
, DerniereModificationAdmin
,
1243 ignore_duplicate_revisions
= True
1245 '_devise_code', '_devise_nom', 'annee', 'implantation',
1246 'valeur', 'derniere_modification'
1248 list_filter
= ('annee', 'devise', 'implantation__zone_administrative', )
1250 (None, {'fields': ('valeur', 'devise', 'implantation', 'annee')}),
1253 def queryset(self
, request
):
1254 return super(ValeurPointAdmin
, self
).queryset(request
) \
1255 .select_related('devise', 'implantation')
1257 def _devise_code(self
, obj
):
1258 return obj
.devise
.code
1259 _devise_code
.short_description
= "Code de la devise"
1261 def _devise_nom(self
, obj
):
1262 return obj
.devise
.nom
1263 _devise_nom
.short_description
= "Nom de la devise"
1266 class ImplantationProxyAdmin(BaseAdmin
):
1267 list_display
= ('nom', '_organigramme')
1270 def __init__(self
, *args
, **kwargs
):
1271 super(ImplantationProxyAdmin
, self
).__init__(*args
, **kwargs
)
1272 self
.list_display_links
= (None, )
1274 def has_add_permission(self
, obj
):
1277 def has_change_permission(self
, request
, obj
=None):
1278 user_groups
= [g
.name
for g
in request
.user
.groups
.all()]
1279 if groups
.CORRESPONDANT_RH
in user_groups
or \
1280 groups
.ADMINISTRATEURS
in user_groups
or \
1281 groups
.DIRECTEUR_DE_BUREAU
in user_groups
or \
1282 in_drh_or_admin(request
.user
):
1286 def _organigramme(self
, obj
):
1287 return '<a href="%s"><strong>Organigramme</strong></a>' % (
1288 reverse('rho_implantation', args
=(obj
.id,))
1290 _organigramme
.allow_tags
= True
1291 _organigramme
.short_description
= "Organigramme"
1294 class RegionProxyAdmin(BaseAdmin
):
1295 list_display
= ('nom', '_organigramme')
1298 def __init__(self
, *args
, **kwargs
):
1299 super(RegionProxyAdmin
, self
).__init__(*args
, **kwargs
)
1300 self
.list_display_links
= (None, )
1302 def has_add_permission(self
, obj
):
1305 def has_change_permission(self
, request
, obj
=None):
1306 user_groups
= [g
.name
for g
in request
.user
.groups
.all()]
1307 if groups
.CORRESPONDANT_RH
in user_groups
or \
1308 groups
.ADMINISTRATEURS
in user_groups
or \
1309 groups
.DIRECTEUR_DE_BUREAU
in user_groups
or \
1310 in_drh_or_admin(request
.user
):
1314 def _organigramme(self
, obj
):
1315 return """<a href="%s"><strong>Organigramme</strong></a>""" % (
1316 reverse('rho_region', args
=(obj
.id,))
1318 _organigramme
.allow_tags
= True
1319 _organigramme
.short_description
= "Organigramme"
1322 admin
.site
.register(rh
.Classement
, ClassementAdmin
)
1323 admin
.site
.register(rh
.Devise
, DeviseAdmin
)
1324 admin
.site
.register(rh
.Dossier
, DossierAdmin
)
1325 admin
.site
.register(EmployeProxy
, EmployeProxyAdmin
)
1326 admin
.site
.register(ServiceProxy
, ServiceProxyAdmin
)
1327 admin
.site
.register(rh
.Employe
, EmployeAdmin
)
1328 admin
.site
.register(rh
.CategorieEmploi
, CategorieEmploiAdmin
)
1329 admin
.site
.register(rh
.FamilleProfessionnelle
)
1330 admin
.site
.register(rh
.OrganismeBstg
, OrganismeBstgAdmin
)
1331 admin
.site
.register(rh
.Poste
, PosteAdmin
)
1332 admin
.site
.register(
1333 rh
.ResponsableImplantationProxy
, ResponsableImplantationAdmin
1335 admin
.site
.register(rh
.Service
, ServiceAdmin
)
1336 admin
.site
.register(rh
.Statut
, StatutAdmin
)
1337 admin
.site
.register(rh
.TauxChange
, TauxChangeAdmin
)
1338 admin
.site
.register(rh
.TypeContrat
, TypeContratAdmin
)
1339 admin
.site
.register(rh
.TypePoste
, TypePosteAdmin
)
1340 admin
.site
.register(rh
.TypeRemuneration
, TypeRemunerationAdmin
)
1341 admin
.site
.register(rh
.TypeRevalorisation
, TypeRevalorisationAdmin
)
1342 admin
.site
.register(rh
.ValeurPoint
, ValeurPointAdmin
)
1343 admin
.site
.register(ImplantationProxy
, ImplantationProxyAdmin
)
1344 admin
.site
.register(RegionProxy
, RegionProxyAdmin
)