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
31 def listing_par_defaut(model
, request
):
33 Teste si la requete provient de la même page.
35 if not 'HTTP_REFERER' in request
.META
.keys():
37 referer
= request
.META
['HTTP_REFERER']
38 referer
= "/".join(referer
.split('/')[3:])
39 referer
= "/%s" % referer
.split('?')[0]
40 change_list_view
= 'admin:%s_%s_changelist' % (
41 model
._meta
.app_label
,
42 model
.__name__
.lower(),)
43 return referer
!= reverse(change_list_view
)
45 class BaseAdmin(admin
.ModelAdmin
):
49 'css/admin_custom.css',
50 'jquery-autocomplete/jquery.autocomplete.css',
53 'https://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js',
54 'jquery-autocomplete/jquery.autocomplete.min.js',
58 # Admin pour reversion
60 class ArchivableAdmin(admin
.ModelAdmin
):
62 Admin pour les modèles archivables
64 list_filter
= ('archive', )
66 def queryset(self
, request
):
67 return self
.model
.avec_archives
.all()
69 def _archive(self
, obj
):
74 _archive
.short_description
= u
'Archivé'
75 _archive
.admin_order_field
= 'archive'
78 class RegionProxy(ref
.Region
):
79 """ Proxy utilisé pour les organigrammes par région """
83 verbose_name
= u
"Organigramme par région"
84 verbose_name_plural
= u
"Organigramme par région"
87 class ImplantationProxy(ref
.Implantation
):
88 """ Proxy utilisé pour les organigrammes par implantation """
92 verbose_name
= u
"Organigramme par implantations"
93 verbose_name_plural
= u
"Organigramme par implantations"
96 class ServiceProxy(rh
.Service
):
97 """ Proxy utilisé pour les organigrammes par service """
102 verbose_name
= u
"Organigramme par services"
103 verbose_name_plural
= u
"Organigramme par services"
106 class EmployeProxy(rh
.Employe
):
107 """ Proxy utilisé pour les organigrammes des employés """
111 verbose_name
= u
"Organigramme des employés"
112 verbose_name_plural
= u
"Organigramme des employés"
115 class DateRangeMixin(object):
116 prefixe_recherche_temporelle
= ""
118 def get_changelist(self
, request
, **kwargs
):
120 On filtre par défaut sur les items 'actifs'.
121 Le changelist plug le filtrage temporel.
123 if listing_par_defaut(self
.model
, request
):
124 params
= request
.GET
.copy()
125 params
.update({'statut': 'Actif'})
130 # Override of the InlineModelAdmin to support the link in the tabular inline
131 class LinkedInline(admin
.options
.InlineModelAdmin
):
132 template
= "admin/linked.html"
133 admin_model_path
= None
135 def __init__(self
, *args
):
136 super(LinkedInline
, self
).__init__(*args
)
137 if self
.admin_model_path
is None:
138 self
.admin_model_path
= self
.model
.__name__
.lower()
141 class ProtectRegionMixin(object):
143 def changelist_view(self
, request
, extra_context
=None):
145 On filtre par défaut sur la ZA du user connecté
147 if listing_par_defaut(self
.model
, request
):
148 if user_gere_obj_de_sa_region(request
.user
):
149 params
= request
.GET
.copy()
150 employe
= groups
.get_employe_from_user(request
.user
)
151 za
= employe
.implantation
.zone_administrative
.code
152 prefix_za
= "%s__code__exact" % self
.model
.prefix_implantation
153 params
.update({prefix_za
: za
})
155 return super(ProtectRegionMixin
, self
).changelist_view(request
, extra_context
)
157 def queryset(self
, request
):
158 qs
= super(ProtectRegionMixin
, self
).queryset(request
)
160 if in_drh_or_admin(request
.user
):
163 if user_gere_obj_de_sa_region(request
.user
):
164 region_user
= get_region_user(request
.user
)
165 q
= Q(**{self
.model
.prefix_implantation
: \
167 qs
= qs
.filter(q
).distinct()
171 def has_add_permission(self
, request
):
172 return user_can_add_obj(request
.user
)
174 def has_change_permission(self
, request
, obj
=None):
176 return user_can_list_obj(request
.user
)
178 return user_can_change_obj(request
.user
, obj
)
180 def has_delete_permission(self
, request
, obj
=None):
181 return user_can_delete_obj(request
.user
, obj
) if obj
else True
184 class DerniereModificationAdmin(admin
.ModelAdmin
):
186 def queryset(self
, request
):
187 qs
= super(DerniereModificationAdmin
, self
).queryset(request
)
188 ct
= ContentType
.objects
.get_for_model(self
.model
)
189 db_table
= self
.model
._meta
.db_table
190 pk
= self
.model
._meta
.pk
.column
191 return qs
.extra(select
={
193 "SELECT action_time FROM django_admin_log "
194 "WHERE content_type_id = %d AND object_id = %s.%s "
195 "ORDER BY action_time DESC "
196 "LIMIT 1" % (ct
.id, db_table
, pk
),
200 "INNER JOIN django_admin_log l ON l.user_id = u.id "
201 "WHERE l.content_type_id = %d AND object_id = %s.%s "
202 "ORDER BY action_time DESC "
203 "LIMIT 1" % (ct
.id, db_table
, pk
),
206 def derniere_modification(self
, obj
):
208 if obj
.date_modification
:
209 text
+= obj
.date_modification
.strftime('%d-%m-%Y %H:%M')
210 if obj
.user_modification
:
211 text
+= ' par ' + obj
.user_modification
213 derniere_modification
.short_description
= u
'dernière modification'
214 derniere_modification
.admin_order_field
= 'date_modification'
219 class CommentaireInlineForm(forms
.ModelForm
):
221 def save(self
, commit
=True):
223 # Hack: reversion.VersionAdmin ne sauvegarde pas les champs qui ne
224 # sont pas explicitement dans le formulaire. Il plante cependant
225 # leur valeur dans `self.initial`. Ceci est un peu fragile. Si
226 # c'est possible, il serait plus approprié que Reversion se rende
227 # compte qu'il manque des champs.
228 instance
= super(CommentaireInlineForm
, self
).save(commit
=False)
229 if instance
.owner_id
is None and 'owner' in self
.initial
:
230 instance
.owner_id
= self
.initial
['owner']
231 if instance
.date_creation
is None and 'date_creation' in self
.initial
:
232 instance
.date_creation
= self
.initial
['date_creation']
239 class ReadOnlyInlineMixin(object):
241 def get_readonly_fields(self
, request
, obj
=None):
242 return [f
.name
for f
in self
.model
._meta
.fields
]
245 class AyantDroitInline(admin
.StackedInline
):
246 model
= rh
.AyantDroit
247 form
= AyantDroitForm
254 ('nom_affichage', 'genre'),
262 class AyantDroitCommentaireInline(admin
.TabularInline
):
263 readonly_fields
= ('owner',)
264 model
= rh
.AyantDroitCommentaire
266 form
= CommentaireInlineForm
269 class ContratInline(admin
.TabularInline
):
275 class DossierROInline(ReadOnlyInlineMixin
, LinkedInline
):
276 template
= "admin/rh/dossier/linked.html"
280 fields
= ('poste', 'date_debut', 'date_fin', )
282 def has_add_permission(self
, request
=None):
285 def has_change_permission(self
, request
, obj
=None):
288 def has_delete_permission(self
, request
, obj
=None):
292 class DossierCommentaireInline(admin
.TabularInline
):
293 readonly_fields
= ('owner',)
294 model
= rh
.DossierCommentaire
296 form
= CommentaireInlineForm
299 class DossierPieceInline(admin
.TabularInline
):
300 model
= rh
.DossierPiece
304 class EmployeInline(admin
.TabularInline
):
308 class EmployeCommentaireInline(admin
.TabularInline
):
309 readonly_fields
= ('owner',)
310 model
= rh
.EmployeCommentaire
312 form
= CommentaireInlineForm
315 class EmployePieceInline(admin
.TabularInline
):
316 model
= rh
.EmployePiece
320 class PosteCommentaireInline(admin
.TabularInline
):
321 readonly_fields
= ('owner',)
322 model
= rh
.PosteCommentaire
324 form
= CommentaireInlineForm
327 class PosteFinancementInline(admin
.TabularInline
):
328 model
= rh
.PosteFinancement
331 class PostePieceInline(admin
.TabularInline
):
332 model
= rh
.PostePiece
335 class RemunerationInline(admin
.TabularInline
):
336 model
= rh
.Remuneration
340 class RemunerationROInline(ReadOnlyInlineMixin
, RemunerationInline
):
344 class TypePosteInline(admin
.TabularInline
):
348 class PosteComparaisonInline(admin
.TabularInline
):
349 model
= rh
.PosteComparaison
352 class ClassementAdmin(reversion
.VersionAdmin
, DerniereModificationAdmin
,
354 ignore_duplicate_revisions
= True
355 list_display
= ('_classement', 'derniere_modification')
357 (None, {'fields': ('type', 'echelon', 'degre', 'coefficient',)}),
360 def _classement(self
, obj
):
362 _classement
.short_description
= u
"Classement"
365 class DeviseAdmin(reversion
.VersionAdmin
, ArchivableAdmin
,
366 DerniereModificationAdmin
, BaseAdmin
):
367 ignore_duplicate_revisions
= True
369 'code', 'nom', '_archive', 'derniere_modification',
371 list_filter
= ('archive', )
373 (None, {'fields': ('code', 'nom', 'archive', )}),
377 class DossierAdmin(DateRangeMixin
, ProtectRegionMixin
, reversion
.VersionAdmin
,
378 AjaxSelect
, DerniereModificationAdmin
, BaseAdmin
):
379 change_list_template
= "admin/rh/dossier/change_list.html"
380 ignore_duplicate_revisions
= True
381 alphabet_filter
= 'employe__nom'
389 'poste__nom_feminin',
390 'poste__implantation__nom',
398 '_zone_administrative',
402 'derniere_modification',
405 list_display_links
= ('_nom',)
407 'poste__implantation__zone_administrative',
408 'poste__implantation',
409 'poste__type_poste__categorie_emploi',
411 'rh_contrats__type_contrat',
414 inlines
= (DossierPieceInline
, ContratInline
,
416 DossierCommentaireInline
,
425 'organisme_bstg',)}),
430 'remplacement_de', )}),
434 ('regime_travail', 'regime_travail_nb_heure_semaine'),)}),
435 ('Occupation du Poste par cet Employe', {
436 'fields': (('date_debut', 'date_fin'), )}
439 form
= make_ajax_form(rh
.Dossier
, {
440 'employe': 'employes',
442 'remplacement_de': 'dossiers',
443 }, superclass
=DossierForm
)
445 def lookup_allowed(self
, key
, value
):
447 'employe__nom__istartswith',
448 'poste__implantation__zone_administrative__code__exact',
449 'poste__implantation__id__exact',
450 'poste__type_poste__id__exact',
451 'poste__type_poste__categorie_emploi__id__exact',
452 'rh_contrats__type_contrat__id__exact',
460 _id
.short_description
= u
"#"
461 _id
.admin_order_field
= "id"
463 def _apercu(self
, d
):
464 apercu_link
= u
"""<a title="Aperçu du dossier"
465 onclick="return showAddAnotherPopup(this);"
467 <img src="%simg/dossier-apercu.png" />
469 (reverse('dossier_apercu', args
=(d
.id,)),
473 _apercu
.allow_tags
= True
474 _apercu
.short_description
= u
""
478 _nom
.allow_tags
= True
479 _nom
.short_description
= u
"Dossier"
481 def _employe(self
, obj
):
482 employe
= obj
.employe
483 view_link
= reverse('employe_apercu', args
=(employe
.id,))
484 edit_link
= reverse('admin:rh_employe_change', args
=(employe
.id,))
486 view
= u
"""<a href="%s"
487 title="Aperçu l'employé"
488 onclick="return showAddAnotherPopup(this);">
489 <img src="%simg/employe-apercu.png" />
490 </a>""" % (view_link
, settings
.STATIC_URL
,)
491 return u
"""%s<a href='%s' style="%s;">%s</a>""" % \
492 (view
, edit_link
, style
, employe
)
493 _employe
.allow_tags
= True
494 _employe
.short_description
= u
"Employé"
495 _employe
.admin_order_field
= "employe__nom"
497 def _poste(self
, dossier
):
498 link
= u
"""<a title="Aperçu du poste"
499 onclick="return showAddAnotherPopup(this);"
500 href='%s'><img src="%simg/poste-apercu.png" />
502 <a href="%s" title="Modifier le poste">%s [%d]</a>""" % \
503 (reverse('poste_apercu', args
=(dossier
.poste
.id,)),
505 reverse('admin:rh_poste_change', args
=(dossier
.poste
.id,)),
510 _poste
.allow_tags
= True
511 _poste
.short_description
= u
'Poste'
512 _poste
.admin_order_field
= 'poste__nom'
514 def _zone_administrative(self
, obj
):
515 return obj
.poste
.implantation
.zone_administrative
.code
516 _zone_administrative
.short_description
= u
"Zone administrative"
517 _zone_administrative
.admin_order_field
= 'poste__implantation__zone_administrative__code'
519 def _implantation(self
, obj
):
520 return obj
.poste
.implantation
.nom
521 _implantation
.short_description
= u
"Implantation"
522 _implantation
.admin_order_field
= 'poste__implantation__nom'
524 def _date_debut(self
, obj
):
525 return date(obj
.date_debut
)
527 _date_debut
.short_description
= u
'Début'
528 _date_debut
.admin_order_field
= 'date_debut'
530 def _date_fin(self
, obj
):
531 return date(obj
.date_fin
)
532 _date_fin
.short_description
= u
'Fin'
533 _date_fin
.admin_order_field
= 'date_fin'
535 def _date_modification(self
, obj
):
536 return date(obj
.date_modification
) \
537 if obj
.date_modification
is not None else "(aucune)"
538 _date_modification
.short_description
= u
'date modification'
539 _date_modification
.admin_order_field
= 'date_modification'
543 dossiers_dae
= d
.dossiers_dae
.all()
544 if len(dossiers_dae
) > 0:
545 dossier_dae
= dossiers_dae
[0]
546 apercu_link
= u
"""<a title="Aperçu du dossier"
547 onclick="return showAddAnotherPopup(this);"
549 <img src="%simg/loupe.png" />
551 (reverse('embauche_consulter', args
=(dossier_dae
.id,)),
555 _dae
.allow_tags
= True
556 _dae
.short_description
= u
"DAE"
558 def save_formset(self
, request
, form
, formset
, change
):
559 instances
= formset
.save(commit
=False)
560 for instance
in instances
:
561 if instance
.__class__
== rh
.DossierCommentaire
:
562 instance
.owner
= request
.user
563 instance
.date_creation
= datetime
.datetime
.now()
567 class EmployeAdminBase(DateRangeMixin
, ProtectRegionMixin
,
568 DerniereModificationAdmin
, BaseAdmin
):
569 prefixe_recherche_temporelle
= "rh_dossiers__"
570 alphabet_filter
= 'nom'
571 DEFAULT_ALPHABET
= u
'ABCDEFGHIJKLMNOPQRSTUVWXYZ'
573 'id', 'nom', 'prenom', 'nom_affichage',
574 'rh_dossiers__poste__nom',
575 'rh_dossiers__poste__nom_feminin'
578 form
= EmployeAdminForm
580 '_id', '_apercu', '_nom', '_dossiers_postes',
581 #'_zone_administrative',
584 'derniere_modification'
586 list_display_links
= ('_nom',)
588 'rh_dossiers__poste__implantation__zone_administrative',
589 'rh_dossiers__poste__implantation', 'nb_postes'
592 AyantDroitInline
, DossierROInline
, EmployePieceInline
,
593 EmployeCommentaireInline
599 ('nom_affichage', 'genre'),
604 ('Informations personnelles', {
605 'fields': ('situation_famille', 'date_entree', )
607 ('Coordonnées personnelles', {
609 ('tel_domicile', 'tel_cellulaire'),
610 ('adresse', 'ville'),
611 ('code_postal', 'province'),
620 _id
.short_description
= u
"#"
621 _id
.admin_order_field
= "id"
623 def _apercu(self
, obj
):
624 return u
"""<a title="Aperçu de l'employé"
625 onclick="return showAddAnotherPopup(this);"
627 <img src="%simg/employe-apercu.png" />
629 (reverse('employe_apercu', args
=(obj
.id,)), settings
.STATIC_URL
)
630 _apercu
.allow_tags
= True
631 _apercu
.short_description
= u
""
634 edit_link
= reverse('admin:rh_employe_change', args
=(obj
.id,))
635 return u
"""<a href='%s'><strong>%s</strong></a>""" % \
636 (edit_link
, "%s %s" % (obj
.nom
.upper(), obj
.prenom
))
637 _nom
.allow_tags
= True
638 _nom
.short_description
= u
"Employé"
639 _nom
.admin_order_field
= "nom"
641 def _zone_administrative(self
, obj
):
643 d
= rh
.Dossier
.objects
.filter(employe
=obj
.id, principal
=True)[0]
644 zone
= d
.poste
.implantation
.zone_administrative
.code
648 _zone_administrative
.short_description
= u
"Zone administrative"
650 def _implantation(self
, obj
):
652 d
= rh
.Dossier
.objects
.filter(employe
=obj
.id, principal
=True)[0]
653 implantation
= d
.poste
.implantation
.nom
657 _implantation
.short_description
= u
"Implantation"
659 def _dossiers_postes(self
, obj
):
661 for d
in obj
.rh_dossiers
.all().order_by('-date_debut'):
664 if d
.date_fin
is not None and d
.date_fin
< datetime
.date
.today():
665 link_style
= u
' style="color:#666;"'
666 list_style
= u
' style="color:grey;"'
668 dossier
= u
"""<a title="Aperçu du dossier"
670 onclick="return showAddAnotherPopup(this);"
671 title="Aperçu du dossier">
672 <img src="%simg/dossier-apercu.png" />
674 <a href="%s"%s>Dossier</a>
676 (reverse('dossier_apercu', args
=(d
.id,)),
678 reverse('admin:rh_dossier_change', args
=(d
.id,)),
681 poste
= u
"""<a title="Aperçu du poste"
683 onclick="return showAddAnotherPopup(this);"
684 title="Aperçu du poste">
685 <img src="%simg/poste-apercu.png" />
687 <a href="%s"%s>%s [%d]</a>
689 (reverse('poste_apercu', args
=(d
.poste
.id,)),
691 reverse('admin:rh_poste_change', args
=(d
.poste
.id,)),
696 link
= u
"""<li%s>%s %s</li>""" % \
697 (list_style
, dossier
, poste
)
700 return "<ul>%s</ul>" % "\n".join(l
)
701 _dossiers_postes
.allow_tags
= True
702 _dossiers_postes
.short_description
= u
"Dossiers et postes"
704 def _date_modification(self
, obj
):
705 return date(obj
.date_modification
) \
706 if obj
.date_modification
is not None else "(aucune)"
707 _date_modification
.short_description
= u
'date modification'
708 _date_modification
.admin_order_field
= 'date_modification'
710 def queryset(self
, request
):
711 qs
= super(EmployeAdminBase
, self
).queryset(request
)
712 return qs
.select_related(depth
=1).order_by('nom')
714 def save_formset(self
, request
, form
, formset
, change
):
715 instances
= formset
.save(commit
=False)
716 for instance
in instances
:
717 if instance
.__class__
== rh
.EmployeCommentaire
:
718 instance
.owner
= request
.user
719 instance
.date_creation
= datetime
.datetime
.now()
723 class EmployeAdmin(reversion
.VersionAdmin
, EmployeAdminBase
):
724 change_list_template
= "admin/rh/employe/change_list.html"
725 ignore_duplicate_revisions
= True
728 class EmployeProxyAdmin(EmployeAdminBase
):
729 list_display
= ('_id', '_apercu', '_nom', '_organigramme')
733 def __init__(self
, *args
, **kwargs
):
734 super(EmployeProxyAdmin
, self
).__init__(*args
, **kwargs
)
735 self
.list_display_links
= (None, )
737 def queryset(self
, request
):
738 qs
= super(ProtectRegionMixin
, self
).queryset(request
)
740 if in_drh_or_admin(request
.user
) or \
741 user_gere_obj_de_sa_region(request
.user
):
746 def has_add_permission(self
, obj
):
749 def has_change_permission(self
, request
, obj
=None):
750 user_groups
= [g
.name
for g
in request
.user
.groups
.all()]
751 if groups
.CORRESPONDANT_RH
in user_groups
or \
752 groups
.ADMINISTRATEURS
in user_groups
or \
753 groups
.DIRECTEUR_DE_BUREAU
in user_groups
or \
754 in_drh_or_admin(request
.user
):
758 def _organigramme(self
, obj
):
760 for d
in rh
.Dossier
.objects
.filter(
761 Q(date_fin__gt
=datetime
.date
.today()) |
Q(date_fin
=None),
762 Q(date_debut__lt
=datetime
.date
.today()) |
Q(date_debut
=None),
766 u
'Organigramme, niveau: ' \
767 u
'<input type="text" id="level_%s" ' \
768 u
'style="width:30px;height:15px;" /> ' \
769 u
'<input type="button" value="Générer" ' \
770 u
"""onclick="window.location='%s' + """ \
771 u
"""document.getElementById('level_%s').value" />""" % (
773 reverse('rho_employe_sans_niveau', args
=(d
.poste
.id,)),
776 link
= u
"""<li>%s [%s]:<br />%s</li>""" % (
782 return "<ul>%s</ul>" % "\n".join(l
)
784 _organigramme
.allow_tags
= True
785 _organigramme
.short_description
= "Organigramme"
788 class CategorieEmploiAdmin(reversion
.VersionAdmin
,
789 DerniereModificationAdmin
, BaseAdmin
):
790 ignore_duplicate_revisions
= True
791 list_display
= ('nom', 'derniere_modification')
792 inlines
= (TypePosteInline
,)
794 (None, {'fields': ('nom', )}),
798 class OrganismeBstgAdmin(reversion
.VersionAdmin
, DerniereModificationAdmin
,
800 ignore_duplicate_revisions
= True
801 search_fields
= ('nom',)
802 list_display
= ('nom', 'type', 'pays', 'derniere_modification')
803 list_filter
= ('type', )
804 inlines
= (DossierROInline
,)
806 (None, {'fields': ('nom', 'type', 'pays',)}),
810 class PosteAdmin(DateRangeMixin
, ProtectRegionMixin
, reversion
.VersionAdmin
,
811 AjaxSelect
, DerniereModificationAdmin
, BaseAdmin
):
812 change_list_template
= "admin/rh/poste/change_list.html"
813 ignore_duplicate_revisions
= True
814 form
= make_ajax_form(rh
.Poste
, {
815 'implantation': 'implantations',
816 'type_poste': 'typepostes',
817 'responsable': 'postes',
818 'valeur_point_min': 'valeurpoints',
819 'valeur_point_max': 'valeurpoints',
821 alphabet_filter
= 'nom'
826 'implantation__zone_administrative__code',
827 'implantation__zone_administrative__nom',
828 'rh_dossiers__employe__id',
829 'rh_dossiers__employe__nom',
830 'rh_dossiers__employe__prenom',
833 '_id', '_apercu', '_nom', '_occupe_par', 'implantation', '_service',
834 '_responsable', 'date_debut', 'date_fin', 'derniere_modification',
838 'implantation__zone_administrative',
842 'type_poste__categorie_emploi',
843 'type_poste__famille_professionnelle',
846 list_display_links
= ('_nom',)
849 ('nom', 'nom_feminin'),
859 'regime_travail_nb_heure_semaine'),
863 'fields': (('local', 'expatrie', 'mise_a_disposition', 'appel'),)}
866 'fields': (('classement_min',
879 ('Comparatifs de rémunération', {
880 'fields': ('devise_comparaison',
881 ('comp_locale_min', 'comp_locale_max'),
882 ('comp_universite_min', 'comp_universite_max'),
883 ('comp_fonctionpub_min', 'comp_fonctionpub_max'),
884 ('comp_ong_min', 'comp_ong_max'),
885 ('comp_autre_min', 'comp_autre_max'))}
888 'fields': ('justification',)}
890 ('Autres Méta-données', {
891 'fields': ('date_debut', 'date_fin')}
895 inlines
= (PosteFinancementInline
,
898 PosteComparaisonInline
,
899 PosteCommentaireInline
, )
901 def lookup_allowed(self
, key
, value
):
903 'date_debut__gte', 'date_debut__isnull', 'date_fin__lte',
904 'date_fin__isnull', 'implantation__zone_administrative__code__exact',
905 'implantation__id__exact', 'type_poste__id__exact',
906 'type_poste__categorie_emploi__id__exact', 'service__id__exact',
907 'service__isnull', 'vacant__exact', 'vacant__isnull',
908 ) or super(PosteAdmin
, self
).lookup_allowed(key
, value
)
912 _id
.short_description
= '#'
913 _id
.admin_order_field
= 'id'
915 def _apercu(self
, poste
):
916 view_link
= u
"""<a onclick="return showAddAnotherPopup(this);"
917 title="Aperçu du poste"
919 <img src="%simg/poste-apercu.png" />
921 (reverse('poste_apercu', args
=(poste
.id,)),
922 settings
.STATIC_URL
,)
924 _apercu
.allow_tags
= True
925 _apercu
.short_description
= ''
927 def _nom(self
, poste
):
928 return """<a href="%s">%s</a>""" % \
929 (reverse('admin:rh_poste_change', args
=(poste
.id,)),
931 _nom
.allow_tags
= True
932 _nom
.short_description
= u
'Poste'
933 _nom
.admin_order_field
= 'nom'
935 def _occupe_par(self
, obj
):
936 """Formatte la méthode Poste.occupe_par() pour l'admin"""
938 if obj
.date_fin
is not None and obj
.date_fin
< datetime
.date
.today():
940 employes
= obj
.occupe_par()
944 link
= u
"""<a href='%s'
945 title='Aperçu de l\'employé'
946 onclick='return showAddAnotherPopup(this)'>
947 <img src='%simg/employe-apercu.png' />
949 <a href='%s'>%s</a>""" % \
950 (reverse('employe_apercu', args
=(e
.id,)),
952 reverse('admin:rh_employe_change', args
=(e
.id,)),
955 output
= "\n<br />".join(l
)
957 _occupe_par
.allow_tags
= True
958 _occupe_par
.short_description
= "Occupé par"
960 def _zone_administrative(self
, poste
):
961 return poste
.implantation
.zone_administrative
.code
962 _zone_administrative
.short_description
= 'Zone administrative'
963 _zone_administrative
.admin_order_field
= 'implantation__zone_administrative__code'
965 def _implantation(self
, poste
):
966 return poste
.implantation
.nom
967 _implantation
.short_description
= 'Implantation'
968 _implantation
.admin_order_field
= 'implantation'
970 def _service(self
, obj
):
972 _service
.short_description
= 'Service'
973 _service
.allow_tags
= True
975 def _responsable(self
, obj
):
977 responsable
= u
"""<a href="%s"
978 onclick="return showAddAnotherPopup(this)">
979 <img src="%simg/poste-apercu.png"
980 title="Aperçu du poste" />
982 <a href="%s">%s [%d]</a>
984 (reverse('poste_apercu', args
=(obj
.responsable
.id,)),
986 reverse('admin:rh_poste_change', args
=(obj
.responsable
.id,)),
993 dossier
= obj
.responsable
.rh_dossiers
.all() \
994 .order_by('-date_debut')[0]
995 employe_id
= dossier
.employe
.id
996 employe_html
= u
"""<br />
998 onclick="return showAddAnotherPopup(this)">
999 <img src="%simg/employe-apercu.png"
1000 title="Aperçu de l'employé">
1002 <a href="%s">%s</a>""" % \
1003 (reverse('employe_apercu', args
=(employe_id
,)),
1004 settings
.STATIC_URL
,
1005 reverse('admin:rh_employe_change', args
=(employe_id
,)),
1010 return "%s %s" % (responsable
, employe_html
)
1011 _responsable
.short_description
= 'Responsable'
1012 _responsable
.allow_tags
= True
1014 def _date_debut(self
, obj
):
1015 return date_format(obj
.date_debut
)
1016 _date_debut
.short_description
= u
'Début'
1017 _date_debut
.admin_order_field
= 'date_debut'
1019 def _date_fin(self
, obj
):
1020 return date_format(obj
.date_fin
)
1021 _date_fin
.short_description
= u
'Fin'
1022 _date_fin
.admin_order_field
= 'date_fin'
1024 def _dae(self
, poste
):
1026 postes_dae
= poste
.postes_dae
.all()
1027 if len(postes_dae
) > 0:
1028 poste_dae
= postes_dae
[0]
1030 u
'<a title="Aperçu du dossier" href="%s" ' \
1031 u
'onclick="return showAddAnotherPopup(this);">' \
1032 u
'<img src="%simg/loupe.png" /></a>' % (reverse(
1033 'poste_consulter', args
=("dae-%s" % poste_dae
.id,)
1034 ), settings
.STATIC_URL
)
1036 _dae
.allow_tags
= True
1037 _dae
.short_description
= u
"DAE"
1039 def save_formset(self
, request
, form
, formset
, change
):
1040 instances
= formset
.save(commit
=False)
1041 for instance
in instances
:
1042 if instance
.__class__
== rh
.PosteCommentaire
:
1043 instance
.owner
= request
.user
1044 instance
.date_creation
= datetime
.datetime
.now()
1049 class ResponsableInline(admin
.TabularInline
):
1050 model
= rh
.ResponsableImplantation
1052 fk_name
= "implantation"
1053 form
= ResponsableInlineForm
1056 class ResponsableImplantationAdmin(BaseAdmin
):
1059 inlines
= (ResponsableInline
, )
1060 list_filter
= ('zone_administrative', 'statut', )
1061 list_display
= ('_zone_administrative', '_nom', 'statut', '_responsable', )
1062 list_display_links
= ('_nom',)
1064 readonly_fields
= ('nom', )
1067 'responsable__employe__id',
1068 'responsable__employe__nom',
1069 'responsable__employe__prenom',
1072 inlines
= (ResponsableInline
, )
1074 def _zone_administrative(self
, obj
):
1075 return obj
.zone_administrative
.code
1076 _zone_administrative
.short_description
= u
"Zone administrative"
1077 _zone_administrative
.admin_order_field
= 'zone_administrative__code'
1079 def _nom(self
, obj
):
1081 _nom
.short_description
= u
"Implantation"
1082 _nom
.admin_order_field
= 'nom'
1084 def _responsable(self
, obj
):
1086 employe
= employe
= obj
.responsable
.employe
1087 except Exception, e
:
1088 return u
"<span style='color: red;'>Pas de responsable</span><!-- %s -->" % e
1090 dossiers
= employe
.dossiers_encours()
1091 if len(dossiers
) == 0:
1092 return u
"<span style='color: red;'>%s %s </span>" % (
1093 employe
, u
"sans dossier actif")
1096 except Exception, e
:
1097 return u
"<!-- %s -->" % e
1098 _responsable
.allow_tags
= True
1099 _responsable
.short_description
= u
"Responsable"
1100 _responsable
.admin_order_field
= 'responsable__employe__nom'
1102 def has_add_permission(self
, request
=None):
1105 def has_change_permission(self
, request
, obj
=None):
1106 return in_drh_or_admin(request
.user
)
1108 def has_delete_permission(self
, request
, obj
=None):
1112 class ServiceAdminBase(ArchivableAdmin
, DerniereModificationAdmin
, BaseAdmin
):
1113 list_display
= ('nom', '_archive', 'derniere_modification')
1114 list_filter
= ('archive', )
1116 (None, {'fields': ('nom', 'archive')}),
1120 class ServiceAdmin(reversion
.VersionAdmin
, ServiceAdminBase
):
1121 ignore_duplicate_revisions
= True
1124 class ServiceProxyAdmin(ServiceAdminBase
):
1125 list_display
= ('nom', '_organigramme', '_archive', )
1128 def __init__(self
, *args
, **kwargs
):
1129 super(ServiceProxyAdmin
, self
).__init__(*args
, **kwargs
)
1130 self
.list_display_links
= (None, )
1132 def queryset(self
, request
):
1133 return super(ServiceProxyAdmin
, self
).queryset(request
) \
1134 .annotate(num_postes
=Count('rh_postes')) \
1135 .filter(num_postes__gt
=0)
1137 def has_add_permission(self
, obj
):
1140 def has_change_permission(self
, request
, obj
=None):
1141 user_groups
= [g
.name
for g
in request
.user
.groups
.all()]
1142 if groups
.CORRESPONDANT_RH
in user_groups
or \
1143 groups
.ADMINISTRATEURS
in user_groups
or \
1144 groups
.DIRECTEUR_DE_BUREAU
in user_groups
or \
1145 in_drh_or_admin(request
.user
):
1149 def _organigramme(self
, obj
):
1150 return """<a href="%s"><strong>Organigramme</strong></a>""" % \
1151 (reverse('rho_service', args
=(obj
.id,)))
1152 _organigramme
.allow_tags
= True
1153 _organigramme
.short_description
= "Organigramme"
1156 class StatutAdmin(reversion
.VersionAdmin
, DerniereModificationAdmin
,
1158 ignore_duplicate_revisions
= True
1159 list_display
= ('code', 'nom', 'derniere_modification')
1162 'fields': ('code', 'nom', ),
1167 class TauxChangeAdmin(reversion
.VersionAdmin
, DerniereModificationAdmin
,
1169 ignore_duplicate_revisions
= True
1170 list_display
= ('taux', 'devise', 'annee', 'derniere_modification')
1171 list_filter
= ('devise',)
1174 'fields': ('taux', 'devise', 'annee', ),
1179 class TypeContratAdmin(reversion
.VersionAdmin
, DerniereModificationAdmin
,
1181 ignore_duplicate_revisions
= True
1182 list_display
= ('nom', 'nom_long', 'derniere_modification')
1185 'fields': ('nom', 'nom_long', ),
1190 class TypePosteAdmin(reversion
.VersionAdmin
, DerniereModificationAdmin
,
1192 ignore_duplicate_revisions
= True
1193 search_fields
= ('nom', 'nom_feminin', )
1194 list_display
= ('nom', 'categorie_emploi', 'derniere_modification')
1195 list_filter
= ('categorie_emploi', 'famille_professionnelle')
1199 'nom', 'nom_feminin', 'is_responsable', 'categorie_emploi',
1200 'famille_professionnelle',
1206 class TypeRemunerationAdmin(reversion
.VersionAdmin
, ArchivableAdmin
,
1207 DerniereModificationAdmin
, BaseAdmin
):
1208 ignore_duplicate_revisions
= True
1210 'nom', 'type_paiement', 'nature_remuneration', '_archive',
1211 'derniere_modification'
1213 list_filter
= ('archive', )
1217 'nom', 'type_paiement', 'nature_remuneration', 'archive'
1223 class TypeRevalorisationAdmin(reversion
.VersionAdmin
,
1224 DerniereModificationAdmin
, BaseAdmin
):
1225 ignore_duplicate_revisions
= True
1226 list_display
= ('nom', 'derniere_modification')
1228 (None, {'fields': ('nom',)}),
1232 class ValeurPointAdmin(reversion
.VersionAdmin
, DerniereModificationAdmin
,
1234 ignore_duplicate_revisions
= True
1236 '_devise_code', '_devise_nom', 'annee', 'implantation',
1237 'valeur', 'derniere_modification'
1239 list_filter
= ('annee', 'devise', 'implantation__zone_administrative', )
1241 (None, {'fields': ('valeur', 'devise', 'implantation', 'annee')}),
1244 def _devise_code(self
, obj
):
1245 return obj
.devise
.code
1246 _devise_code
.short_description
= "Code de la devise"
1248 def _devise_nom(self
, obj
):
1249 return obj
.devise
.nom
1250 _devise_nom
.short_description
= "Nom de la devise"
1253 class ImplantationProxyAdmin(BaseAdmin
):
1254 list_display
= ('nom', '_organigramme')
1257 def __init__(self
, *args
, **kwargs
):
1258 super(ImplantationProxyAdmin
, self
).__init__(*args
, **kwargs
)
1259 self
.list_display_links
= (None, )
1261 def has_add_permission(self
, obj
):
1264 def has_change_permission(self
, request
, obj
=None):
1265 user_groups
= [g
.name
for g
in request
.user
.groups
.all()]
1266 if groups
.CORRESPONDANT_RH
in user_groups
or \
1267 groups
.ADMINISTRATEURS
in user_groups
or \
1268 groups
.DIRECTEUR_DE_BUREAU
in user_groups
or \
1269 in_drh_or_admin(request
.user
):
1273 def _organigramme(self
, obj
):
1274 return '<a href="%s"><strong>Organigramme</strong></a>' % (
1275 reverse('rho_implantation', args
=(obj
.id,))
1277 _organigramme
.allow_tags
= True
1278 _organigramme
.short_description
= "Organigramme"
1281 class RegionProxyAdmin(BaseAdmin
):
1282 list_display
= ('nom', '_organigramme')
1285 def __init__(self
, *args
, **kwargs
):
1286 super(RegionProxyAdmin
, self
).__init__(*args
, **kwargs
)
1287 self
.list_display_links
= (None, )
1289 def has_add_permission(self
, obj
):
1292 def has_change_permission(self
, request
, obj
=None):
1293 user_groups
= [g
.name
for g
in request
.user
.groups
.all()]
1294 if groups
.CORRESPONDANT_RH
in user_groups
or \
1295 groups
.ADMINISTRATEURS
in user_groups
or \
1296 groups
.DIRECTEUR_DE_BUREAU
in user_groups
or \
1297 in_drh_or_admin(request
.user
):
1301 def _organigramme(self
, obj
):
1302 return """<a href="%s"><strong>Organigramme</strong></a>""" % (
1303 reverse('rho_region', args
=(obj
.id,))
1305 _organigramme
.allow_tags
= True
1306 _organigramme
.short_description
= "Organigramme"
1309 admin
.site
.register(rh
.Classement
, ClassementAdmin
)
1310 admin
.site
.register(rh
.Devise
, DeviseAdmin
)
1311 admin
.site
.register(rh
.Dossier
, DossierAdmin
)
1312 admin
.site
.register(EmployeProxy
, EmployeProxyAdmin
)
1313 admin
.site
.register(ServiceProxy
, ServiceProxyAdmin
)
1314 admin
.site
.register(rh
.Employe
, EmployeAdmin
)
1315 admin
.site
.register(rh
.CategorieEmploi
, CategorieEmploiAdmin
)
1316 admin
.site
.register(rh
.FamilleProfessionnelle
)
1317 admin
.site
.register(rh
.OrganismeBstg
, OrganismeBstgAdmin
)
1318 admin
.site
.register(rh
.Poste
, PosteAdmin
)
1319 admin
.site
.register(
1320 rh
.ResponsableImplantationProxy
, ResponsableImplantationAdmin
1322 admin
.site
.register(rh
.Service
, ServiceAdmin
)
1323 admin
.site
.register(rh
.Statut
, StatutAdmin
)
1324 admin
.site
.register(rh
.TauxChange
, TauxChangeAdmin
)
1325 admin
.site
.register(rh
.TypeContrat
, TypeContratAdmin
)
1326 admin
.site
.register(rh
.TypePoste
, TypePosteAdmin
)
1327 admin
.site
.register(rh
.TypeRemuneration
, TypeRemunerationAdmin
)
1328 admin
.site
.register(rh
.TypeRevalorisation
, TypeRevalorisationAdmin
)
1329 admin
.site
.register(rh
.ValeurPoint
, ValeurPointAdmin
)
1330 admin
.site
.register(ImplantationProxy
, ImplantationProxyAdmin
)
1331 admin
.site
.register(RegionProxy
, RegionProxyAdmin
)