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
,
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__id__exact',
458 'poste__type_poste__id__exact',
459 'poste__type_poste__categorie_emploi__id__exact',
460 'rh_contrats__type_contrat__id__exact',
468 _id
.short_description
= u
"#"
469 _id
.admin_order_field
= "id"
471 def _apercu(self
, d
):
472 apercu_link
= u
"""<a title="Aperçu du dossier"
473 onclick="return showAddAnotherPopup(this);"
475 <img src="%simg/dossier-apercu.png" />
477 (reverse('dossier_apercu', args
=(d
.id,)),
481 _apercu
.allow_tags
= True
482 _apercu
.short_description
= u
""
486 _nom
.allow_tags
= True
487 _nom
.short_description
= u
"Dossier"
489 def _employe(self
, obj
):
490 employe
= obj
.employe
491 view_link
= reverse('employe_apercu', args
=(employe
.id,))
492 edit_link
= reverse('admin:rh_employe_change', args
=(employe
.id,))
494 view
= u
"""<a href="%s"
495 title="Aperçu l'employé"
496 onclick="return showAddAnotherPopup(this);">
497 <img src="%simg/employe-apercu.png" />
498 </a>""" % (view_link
, settings
.STATIC_URL
,)
499 return u
"""%s<a href='%s' style="%s;">%s</a>""" % \
500 (view
, edit_link
, style
, employe
)
501 _employe
.allow_tags
= True
502 _employe
.short_description
= u
"Employé"
503 _employe
.admin_order_field
= "employe__nom"
505 def _poste(self
, dossier
):
506 link
= u
"""<a title="Aperçu du poste"
507 onclick="return showAddAnotherPopup(this);"
508 href='%s'><img src="%simg/poste-apercu.png" />
510 <a href="%s" title="Modifier le poste">%s [%d]</a>""" % \
511 (reverse('poste_apercu', args
=(dossier
.poste
.id,)),
513 reverse('admin:rh_poste_change', args
=(dossier
.poste
.id,)),
518 _poste
.allow_tags
= True
519 _poste
.short_description
= u
'Poste'
520 _poste
.admin_order_field
= 'poste__nom'
522 def _zone_administrative(self
, obj
):
523 return obj
.poste
.implantation
.zone_administrative
.code
524 _zone_administrative
.short_description
= u
"Zone administrative"
525 _zone_administrative
.admin_order_field
= \
526 'poste__implantation__zone_administrative__code'
528 def _implantation(self
, obj
):
529 return obj
.poste
.implantation
.nom
530 _implantation
.short_description
= u
"Implantation"
531 _implantation
.admin_order_field
= 'poste__implantation__nom'
533 def _date_debut(self
, obj
):
534 return date(obj
.date_debut
)
536 _date_debut
.short_description
= u
'Début'
537 _date_debut
.admin_order_field
= 'date_debut'
539 def _date_fin(self
, obj
):
540 return date(obj
.date_fin
)
541 _date_fin
.short_description
= u
'Fin'
542 _date_fin
.admin_order_field
= 'date_fin'
544 def _date_modification(self
, obj
):
545 return date(obj
.date_modification
) \
546 if obj
.date_modification
is not None else "(aucune)"
547 _date_modification
.short_description
= u
'date modification'
548 _date_modification
.admin_order_field
= 'date_modification'
552 dossiers_dae
= d
.dossiers_dae
.all()
553 if len(dossiers_dae
) > 0:
554 dossier_dae
= dossiers_dae
[0]
555 apercu_link
= u
"""<a title="Aperçu du dossier"
556 onclick="return showAddAnotherPopup(this);"
558 <img src="%simg/loupe.png" />
560 (reverse('embauche_consulter', args
=(dossier_dae
.id,)),
564 _dae
.allow_tags
= True
565 _dae
.short_description
= u
"DAE"
567 def save_formset(self
, request
, form
, formset
, change
):
568 instances
= formset
.save(commit
=False)
569 for instance
in instances
:
570 if instance
.__class__
== rh
.DossierCommentaire
:
571 instance
.owner
= request
.user
572 instance
.date_creation
= datetime
.datetime
.now()
576 class EmployeAdminBase(DateRangeMixin
, ProtectRegionMixin
,
577 DerniereModificationAdmin
, BaseAdmin
):
578 prefixe_recherche_temporelle
= "rh_dossiers__"
579 alphabet_filter
= 'nom'
580 DEFAULT_ALPHABET
= u
'ABCDEFGHIJKLMNOPQRSTUVWXYZ'
582 'id', 'nom', 'prenom', 'nom_affichage',
583 'rh_dossiers__poste__nom',
584 'rh_dossiers__poste__nom_feminin'
587 form
= EmployeAdminForm
589 '_id', '_apercu', '_nom', '_dossiers_postes',
590 #'_zone_administrative',
593 'derniere_modification'
595 list_display_links
= ('_nom',)
597 'rh_dossiers__poste__implantation__zone_administrative',
598 'rh_dossiers__poste__implantation', 'nb_postes'
601 AyantDroitInline
, DossierROInline
, EmployePieceInline
,
602 EmployeCommentaireInline
608 ('nom_affichage', 'genre'),
613 ('Informations personnelles', {
614 'fields': ('situation_famille', 'date_entree', )
616 ('Coordonnées personnelles', {
618 ('tel_domicile', 'tel_cellulaire'),
619 ('adresse', 'ville'),
620 ('code_postal', 'province'),
629 _id
.short_description
= u
"#"
630 _id
.admin_order_field
= "id"
632 def _apercu(self
, obj
):
633 return u
"""<a title="Aperçu de l'employé"
634 onclick="return showAddAnotherPopup(this);"
636 <img src="%simg/employe-apercu.png" />
638 (reverse('employe_apercu', args
=(obj
.id,)), settings
.STATIC_URL
)
639 _apercu
.allow_tags
= True
640 _apercu
.short_description
= u
""
643 edit_link
= reverse('admin:rh_employe_change', args
=(obj
.id,))
644 return u
"""<a href='%s'><strong>%s</strong></a>""" % \
645 (edit_link
, "%s %s" % (obj
.nom
.upper(), obj
.prenom
))
646 _nom
.allow_tags
= True
647 _nom
.short_description
= u
"Employé"
648 _nom
.admin_order_field
= "nom"
650 def _zone_administrative(self
, obj
):
652 d
= rh
.Dossier
.objects
.filter(employe
=obj
.id, principal
=True)[0]
653 zone
= d
.poste
.implantation
.zone_administrative
.code
657 _zone_administrative
.short_description
= u
"Zone administrative"
659 def _implantation(self
, obj
):
661 d
= rh
.Dossier
.objects
.filter(employe
=obj
.id, principal
=True)[0]
662 implantation
= d
.poste
.implantation
.nom
666 _implantation
.short_description
= u
"Implantation"
668 def _dossiers_postes(self
, obj
):
670 for d
in obj
.rh_dossiers
.all().order_by('-date_debut'):
673 if d
.date_fin
is not None and d
.date_fin
< datetime
.date
.today():
674 link_style
= u
' style="color:#666;"'
675 list_style
= u
' style="color:grey;"'
677 dossier
= u
"""<a title="Aperçu du dossier"
679 onclick="return showAddAnotherPopup(this);"
680 title="Aperçu du dossier">
681 <img src="%simg/dossier-apercu.png" />
683 <a href="%s"%s>Dossier</a>
685 (reverse('dossier_apercu', args
=(d
.id,)),
687 reverse('admin:rh_dossier_change', args
=(d
.id,)),
690 poste
= u
"""<a title="Aperçu du poste"
692 onclick="return showAddAnotherPopup(this);"
693 title="Aperçu du poste">
694 <img src="%simg/poste-apercu.png" />
696 <a href="%s"%s>%s [%d]</a>
698 (reverse('poste_apercu', args
=(d
.poste
.id,)),
700 reverse('admin:rh_poste_change', args
=(d
.poste
.id,)),
705 link
= u
"""<li%s>%s %s</li>""" % \
706 (list_style
, dossier
, poste
)
709 return "<ul>%s</ul>" % "\n".join(l
)
710 _dossiers_postes
.allow_tags
= True
711 _dossiers_postes
.short_description
= u
"Dossiers et postes"
713 def _date_modification(self
, obj
):
714 return date(obj
.date_modification
) \
715 if obj
.date_modification
is not None else "(aucune)"
716 _date_modification
.short_description
= u
'date modification'
717 _date_modification
.admin_order_field
= 'date_modification'
719 def queryset(self
, request
):
720 qs
= super(EmployeAdminBase
, self
).queryset(request
)
721 return qs
.select_related(depth
=1).order_by('nom')
723 def save_formset(self
, request
, form
, formset
, change
):
724 instances
= formset
.save(commit
=False)
725 for instance
in instances
:
726 if instance
.__class__
== rh
.EmployeCommentaire
:
727 instance
.owner
= request
.user
728 instance
.date_creation
= datetime
.datetime
.now()
732 class EmployeAdmin(reversion
.VersionAdmin
, EmployeAdminBase
):
733 change_list_template
= "admin/rh/employe/change_list.html"
734 ignore_duplicate_revisions
= True
737 class EmployeProxyAdmin(EmployeAdminBase
):
738 list_display
= ('_id', '_apercu', '_nom', '_organigramme')
742 def __init__(self
, *args
, **kwargs
):
743 super(EmployeProxyAdmin
, self
).__init__(*args
, **kwargs
)
744 self
.list_display_links
= (None, )
746 def queryset(self
, request
):
747 qs
= super(ProtectRegionMixin
, self
).queryset(request
)
749 if in_drh_or_admin(request
.user
) or \
750 user_gere_obj_de_sa_region(request
.user
):
755 def has_add_permission(self
, obj
):
758 def has_change_permission(self
, request
, obj
=None):
759 user_groups
= [g
.name
for g
in request
.user
.groups
.all()]
760 if groups
.CORRESPONDANT_RH
in user_groups
or \
761 groups
.ADMINISTRATEURS
in user_groups
or \
762 groups
.DIRECTEUR_DE_BUREAU
in user_groups
or \
763 in_drh_or_admin(request
.user
):
767 def _organigramme(self
, obj
):
769 for d
in rh
.Dossier
.objects
.filter(
770 Q(date_fin__gt
=datetime
.date
.today()) |
Q(date_fin
=None),
771 Q(date_debut__lt
=datetime
.date
.today()) |
Q(date_debut
=None),
775 u
'Organigramme, niveau: ' \
776 u
'<input type="text" id="level_%s" ' \
777 u
'style="width:30px;height:15px;" /> ' \
778 u
'<input type="button" value="Générer" ' \
779 u
"""onclick="window.location='%s' + """ \
780 u
"""document.getElementById('level_%s').value" />""" % (
782 reverse('rho_employe_sans_niveau', args
=(d
.poste
.id,)),
785 link
= u
"""<li>%s [%s]:<br />%s</li>""" % (
791 return "<ul>%s</ul>" % "\n".join(l
)
793 _organigramme
.allow_tags
= True
794 _organigramme
.short_description
= "Organigramme"
797 class CategorieEmploiAdmin(reversion
.VersionAdmin
,
798 DerniereModificationAdmin
, BaseAdmin
):
799 ignore_duplicate_revisions
= True
800 list_display
= ('nom', 'derniere_modification')
801 inlines
= (TypePosteInline
,)
803 (None, {'fields': ('nom', )}),
807 class OrganismeBstgAdmin(reversion
.VersionAdmin
, DerniereModificationAdmin
,
809 ignore_duplicate_revisions
= True
810 search_fields
= ('nom',)
811 list_display
= ('nom', 'type', 'pays', 'derniere_modification')
812 list_filter
= ('type', )
813 inlines
= (DossierROInline
,)
815 (None, {'fields': ('nom', 'type', 'pays',)}),
819 class PosteAdmin(DateRangeMixin
, ProtectRegionMixin
, reversion
.VersionAdmin
,
820 AjaxSelect
, DerniereModificationAdmin
, BaseAdmin
):
821 change_list_template
= "admin/rh/poste/change_list.html"
822 ignore_duplicate_revisions
= True
823 form
= make_ajax_form(rh
.Poste
, {
824 'implantation': 'implantations',
825 'type_poste': 'typepostes',
826 'responsable': 'postes',
827 'valeur_point_min': 'valeurpoints',
828 'valeur_point_max': 'valeurpoints',
830 alphabet_filter
= 'nom'
835 'implantation__zone_administrative__code',
836 'implantation__zone_administrative__nom',
837 'rh_dossiers__employe__id',
838 'rh_dossiers__employe__nom',
839 'rh_dossiers__employe__prenom',
842 '_id', '_apercu', '_nom', '_occupe_par', 'implantation', '_service',
843 '_responsable', 'date_debut', 'date_fin', 'derniere_modification',
847 'implantation__zone_administrative',
851 'type_poste__categorie_emploi',
852 'type_poste__famille_professionnelle',
855 list_display_links
= ('_nom',)
858 ('nom', 'nom_feminin'),
868 'regime_travail_nb_heure_semaine'),
872 'fields': (('local', 'expatrie', 'mise_a_disposition', 'appel'),)}
875 'fields': (('classement_min',
888 ('Comparatifs de rémunération', {
889 'fields': ('devise_comparaison',
890 ('comp_locale_min', 'comp_locale_max'),
891 ('comp_universite_min', 'comp_universite_max'),
892 ('comp_fonctionpub_min', 'comp_fonctionpub_max'),
893 ('comp_ong_min', 'comp_ong_max'),
894 ('comp_autre_min', 'comp_autre_max'))}
897 'fields': ('justification',)}
899 ('Autres Méta-données', {
900 'fields': ('date_debut', 'date_fin')}
904 inlines
= (PosteFinancementInline
,
907 PosteComparaisonInline
,
908 PosteCommentaireInline
, )
910 def lookup_allowed(self
, key
, value
):
912 'date_debut__gte', 'date_debut__isnull', 'date_fin__lte',
914 'implantation__zone_administrative__code__exact',
915 'implantation__id__exact', 'type_poste__id__exact',
916 'type_poste__categorie_emploi__id__exact', 'service__id__exact',
917 'service__isnull', 'vacant__exact', 'vacant__isnull'
918 ) or super(PosteAdmin
, self
).lookup_allowed(key
, value
)
922 _id
.short_description
= '#'
923 _id
.admin_order_field
= 'id'
925 def _apercu(self
, poste
):
926 view_link
= u
"""<a onclick="return showAddAnotherPopup(this);"
927 title="Aperçu du poste"
929 <img src="%simg/poste-apercu.png" />
931 (reverse('poste_apercu', args
=(poste
.id,)),
932 settings
.STATIC_URL
,)
934 _apercu
.allow_tags
= True
935 _apercu
.short_description
= ''
937 def _nom(self
, poste
):
938 return """<a href="%s">%s</a>""" % \
939 (reverse('admin:rh_poste_change', args
=(poste
.id,)),
941 _nom
.allow_tags
= True
942 _nom
.short_description
= u
'Poste'
943 _nom
.admin_order_field
= 'nom'
945 def _occupe_par(self
, obj
):
946 """Formatte la méthode Poste.occupe_par() pour l'admin"""
948 if obj
.date_fin
is not None and obj
.date_fin
< datetime
.date
.today():
950 employes
= obj
.occupe_par()
954 link
= u
"""<a href='%s'
955 title='Aperçu de l\'employé'
956 onclick='return showAddAnotherPopup(this)'>
957 <img src='%simg/employe-apercu.png' />
959 <a href='%s'>%s</a>""" % \
960 (reverse('employe_apercu', args
=(e
.id,)),
962 reverse('admin:rh_employe_change', args
=(e
.id,)),
965 output
= "\n<br />".join(l
)
967 _occupe_par
.allow_tags
= True
968 _occupe_par
.short_description
= "Occupé par"
970 def _zone_administrative(self
, poste
):
971 return poste
.implantation
.zone_administrative
.code
972 _zone_administrative
.short_description
= 'Zone administrative'
973 _zone_administrative
.admin_order_field
= \
974 'implantation__zone_administrative__code'
976 def _implantation(self
, poste
):
977 return poste
.implantation
.nom
978 _implantation
.short_description
= 'Implantation'
979 _implantation
.admin_order_field
= 'implantation'
981 def _service(self
, obj
):
983 _service
.short_description
= 'Service'
984 _service
.allow_tags
= True
986 def _responsable(self
, obj
):
988 responsable
= u
"""<a href="%s"
989 onclick="return showAddAnotherPopup(this)">
990 <img src="%simg/poste-apercu.png"
991 title="Aperçu du poste" />
993 <a href="%s">%s [%d]</a>
995 (reverse('poste_apercu', args
=(obj
.responsable
.id,)),
997 reverse('admin:rh_poste_change', args
=(obj
.responsable
.id,)),
1004 dossier
= obj
.responsable
.rh_dossiers
.all() \
1005 .order_by('-date_debut')[0]
1006 employe_id
= dossier
.employe
.id
1007 employe_html
= u
"""<br />
1009 onclick="return showAddAnotherPopup(this)">
1010 <img src="%simg/employe-apercu.png"
1011 title="Aperçu de l'employé">
1013 <a href="%s">%s</a>""" % \
1014 (reverse('employe_apercu', args
=(employe_id
,)),
1015 settings
.STATIC_URL
,
1016 reverse('admin:rh_employe_change', args
=(employe_id
,)),
1021 return "%s %s" % (responsable
, employe_html
)
1022 _responsable
.short_description
= 'Responsable'
1023 _responsable
.allow_tags
= True
1025 def _date_debut(self
, obj
):
1026 return date_format(obj
.date_debut
)
1027 _date_debut
.short_description
= u
'Début'
1028 _date_debut
.admin_order_field
= 'date_debut'
1030 def _date_fin(self
, obj
):
1031 return date_format(obj
.date_fin
)
1032 _date_fin
.short_description
= u
'Fin'
1033 _date_fin
.admin_order_field
= 'date_fin'
1035 def _dae(self
, poste
):
1037 postes_dae
= poste
.postes_dae
.all()
1038 if len(postes_dae
) > 0:
1039 poste_dae
= postes_dae
[0]
1041 u
'<a title="Aperçu du dossier" href="%s" ' \
1042 u
'onclick="return showAddAnotherPopup(this);">' \
1043 u
'<img src="%simg/loupe.png" /></a>' % (reverse(
1044 'poste_consulter', args
=("dae-%s" % poste_dae
.id,)
1045 ), settings
.STATIC_URL
)
1047 _dae
.allow_tags
= True
1048 _dae
.short_description
= u
"DAE"
1050 def save_formset(self
, request
, form
, formset
, change
):
1051 instances
= formset
.save(commit
=False)
1052 for instance
in instances
:
1053 if instance
.__class__
== rh
.PosteCommentaire
:
1054 instance
.owner
= request
.user
1055 instance
.date_creation
= datetime
.datetime
.now()
1060 class ResponsableInline(admin
.TabularInline
):
1061 model
= rh
.ResponsableImplantation
1063 fk_name
= "implantation"
1064 form
= ResponsableInlineForm
1067 class ResponsableImplantationAdmin(BaseAdmin
):
1070 inlines
= (ResponsableInline
, )
1071 list_filter
= ('zone_administrative', 'statut', )
1072 list_display
= ('_zone_administrative', '_nom', 'statut', '_responsable', )
1073 list_display_links
= ('_nom',)
1075 readonly_fields
= ('nom', )
1078 'responsable__employe__id',
1079 'responsable__employe__nom',
1080 'responsable__employe__prenom',
1083 inlines
= (ResponsableInline
, )
1085 def _zone_administrative(self
, obj
):
1086 return obj
.zone_administrative
.code
1087 _zone_administrative
.short_description
= u
"Zone administrative"
1088 _zone_administrative
.admin_order_field
= 'zone_administrative__code'
1090 def _nom(self
, obj
):
1092 _nom
.short_description
= u
"Implantation"
1093 _nom
.admin_order_field
= 'nom'
1095 def _responsable(self
, obj
):
1097 employe
= employe
= obj
.responsable
.employe
1098 except Exception, e
:
1100 u
"<span style='color: red;'>"
1101 u
"Pas de responsable</span><!-- %s -->" % e
1104 dossiers
= employe
.dossiers_encours()
1105 if len(dossiers
) == 0:
1106 return u
"<span style='color: red;'>%s %s </span>" % (
1107 employe
, u
"sans dossier actif")
1110 except Exception, e
:
1111 return u
"<!-- %s -->" % e
1112 _responsable
.allow_tags
= True
1113 _responsable
.short_description
= u
"Responsable"
1114 _responsable
.admin_order_field
= 'responsable__employe__nom'
1116 def has_add_permission(self
, request
=None):
1119 def has_change_permission(self
, request
, obj
=None):
1120 return in_drh_or_admin(request
.user
)
1122 def has_delete_permission(self
, request
, obj
=None):
1126 class ServiceAdminBase(ArchivableAdmin
, DerniereModificationAdmin
, BaseAdmin
):
1127 list_display
= ('nom', '_archive', 'derniere_modification')
1128 list_filter
= ('archive', )
1130 (None, {'fields': ('nom', 'archive')}),
1134 class ServiceAdmin(reversion
.VersionAdmin
, ServiceAdminBase
):
1135 ignore_duplicate_revisions
= True
1138 class ServiceProxyAdmin(ServiceAdminBase
):
1139 list_display
= ('nom', '_organigramme', '_archive', )
1142 def __init__(self
, *args
, **kwargs
):
1143 super(ServiceProxyAdmin
, self
).__init__(*args
, **kwargs
)
1144 self
.list_display_links
= (None, )
1146 def queryset(self
, request
):
1147 return super(ServiceProxyAdmin
, self
).queryset(request
) \
1148 .annotate(num_postes
=Count('rh_postes')) \
1149 .filter(num_postes__gt
=0)
1151 def has_add_permission(self
, obj
):
1154 def has_change_permission(self
, request
, obj
=None):
1155 user_groups
= [g
.name
for g
in request
.user
.groups
.all()]
1156 if groups
.CORRESPONDANT_RH
in user_groups
or \
1157 groups
.ADMINISTRATEURS
in user_groups
or \
1158 groups
.DIRECTEUR_DE_BUREAU
in user_groups
or \
1159 in_drh_or_admin(request
.user
):
1163 def _organigramme(self
, obj
):
1164 return """<a href="%s"><strong>Organigramme</strong></a>""" % \
1165 (reverse('rho_service', args
=(obj
.id,)))
1166 _organigramme
.allow_tags
= True
1167 _organigramme
.short_description
= "Organigramme"
1170 class StatutAdmin(reversion
.VersionAdmin
,
1172 DerniereModificationAdmin
,
1174 ignore_duplicate_revisions
= True
1175 list_display
= ('code', 'nom', 'derniere_modification', '_archive')
1176 list_filter
= ('archive', )
1179 'fields': ('code', 'nom', 'archive'),
1184 class TauxChangeAdmin(reversion
.VersionAdmin
, DerniereModificationAdmin
,
1186 ignore_duplicate_revisions
= True
1187 list_display
= ('taux', 'devise', 'annee', 'derniere_modification')
1188 list_filter
= ('devise',)
1191 'fields': ('taux', 'devise', 'annee', ),
1196 class TypeContratAdmin(reversion
.VersionAdmin
,
1198 DerniereModificationAdmin
,
1200 ignore_duplicate_revisions
= True
1201 list_display
= ('nom', 'nom_long', 'derniere_modification', '_archive')
1202 list_filter
= ('archive', )
1205 'fields': ('nom', 'nom_long', 'archive'),
1210 class TypePosteAdmin(reversion
.VersionAdmin
,
1212 DerniereModificationAdmin
,
1214 ignore_duplicate_revisions
= True
1215 search_fields
= ('nom', 'nom_feminin', )
1216 list_display
= ('nom', 'categorie_emploi',
1217 'derniere_modification', '_archive',)
1218 list_filter
= ('categorie_emploi', 'famille_professionnelle', 'archive')
1222 'nom', 'nom_feminin', 'is_responsable', 'categorie_emploi',
1223 'famille_professionnelle',
1230 class TypeRemunerationAdmin(reversion
.VersionAdmin
, ArchivableAdmin
,
1231 DerniereModificationAdmin
, BaseAdmin
):
1232 ignore_duplicate_revisions
= True
1234 'nom', 'type_paiement', 'nature_remuneration', '_archive',
1235 'derniere_modification'
1237 list_filter
= ('archive', )
1241 'nom', 'type_paiement', 'nature_remuneration', 'archive'
1247 class TypeRevalorisationAdmin(reversion
.VersionAdmin
,
1249 DerniereModificationAdmin
,
1251 ignore_duplicate_revisions
= True
1252 list_display
= ('nom', 'derniere_modification', '_archive')
1253 list_filter
= ('archive', )
1255 (None, {'fields': ('nom', 'archive')}),
1259 class ValeurPointAdmin(reversion
.VersionAdmin
,
1260 DerniereModificationAdmin
,
1262 ignore_duplicate_revisions
= True
1264 '_devise_code', '_devise_nom', 'annee', 'implantation',
1265 'valeur', 'derniere_modification'
1267 list_filter
= ('annee', 'devise', 'implantation__zone_administrative', )
1269 (None, {'fields': ('valeur', 'devise', 'implantation', 'annee')}),
1272 def queryset(self
, request
):
1273 return super(ValeurPointAdmin
, self
).queryset(request
) \
1274 .select_related('devise', 'implantation')
1276 def _devise_code(self
, obj
):
1277 return obj
.devise
.code
1278 _devise_code
.short_description
= "Code de la devise"
1280 def _devise_nom(self
, obj
):
1281 return obj
.devise
.nom
1282 _devise_nom
.short_description
= "Nom de la devise"
1285 class ImplantationProxyAdmin(BaseAdmin
):
1286 list_display
= ('nom', '_organigramme')
1289 def __init__(self
, *args
, **kwargs
):
1290 super(ImplantationProxyAdmin
, self
).__init__(*args
, **kwargs
)
1291 self
.list_display_links
= (None, )
1293 def has_add_permission(self
, obj
):
1296 def has_change_permission(self
, request
, obj
=None):
1297 user_groups
= [g
.name
for g
in request
.user
.groups
.all()]
1298 if groups
.CORRESPONDANT_RH
in user_groups
or \
1299 groups
.ADMINISTRATEURS
in user_groups
or \
1300 groups
.DIRECTEUR_DE_BUREAU
in user_groups
or \
1301 in_drh_or_admin(request
.user
):
1305 def _organigramme(self
, obj
):
1306 return '<a href="%s"><strong>Organigramme</strong></a>' % (
1307 reverse('rho_implantation', args
=(obj
.id,))
1309 _organigramme
.allow_tags
= True
1310 _organigramme
.short_description
= "Organigramme"
1313 class RegionProxyAdmin(BaseAdmin
):
1314 list_display
= ('nom', '_organigramme')
1317 def __init__(self
, *args
, **kwargs
):
1318 super(RegionProxyAdmin
, self
).__init__(*args
, **kwargs
)
1319 self
.list_display_links
= (None, )
1321 def has_add_permission(self
, obj
):
1324 def has_change_permission(self
, request
, obj
=None):
1325 user_groups
= [g
.name
for g
in request
.user
.groups
.all()]
1326 if groups
.CORRESPONDANT_RH
in user_groups
or \
1327 groups
.ADMINISTRATEURS
in user_groups
or \
1328 groups
.DIRECTEUR_DE_BUREAU
in user_groups
or \
1329 in_drh_or_admin(request
.user
):
1333 def _organigramme(self
, obj
):
1334 return """<a href="%s"><strong>Organigramme</strong></a>""" % (
1335 reverse('rho_region', args
=(obj
.id,))
1337 _organigramme
.allow_tags
= True
1338 _organigramme
.short_description
= "Organigramme"
1341 admin
.site
.register(rh
.Classement
, ClassementAdmin
)
1342 admin
.site
.register(rh
.Devise
, DeviseAdmin
)
1343 admin
.site
.register(rh
.Dossier
, DossierAdmin
)
1344 admin
.site
.register(EmployeProxy
, EmployeProxyAdmin
)
1345 admin
.site
.register(ServiceProxy
, ServiceProxyAdmin
)
1346 admin
.site
.register(rh
.Employe
, EmployeAdmin
)
1347 admin
.site
.register(rh
.CategorieEmploi
, CategorieEmploiAdmin
)
1348 admin
.site
.register(rh
.FamilleProfessionnelle
)
1349 admin
.site
.register(rh
.OrganismeBstg
, OrganismeBstgAdmin
)
1350 admin
.site
.register(rh
.Poste
, PosteAdmin
)
1351 admin
.site
.register(
1352 rh
.ResponsableImplantationProxy
, ResponsableImplantationAdmin
1354 admin
.site
.register(rh
.Service
, ServiceAdmin
)
1355 admin
.site
.register(rh
.Statut
, StatutAdmin
)
1356 admin
.site
.register(rh
.TauxChange
, TauxChangeAdmin
)
1357 admin
.site
.register(rh
.TypeContrat
, TypeContratAdmin
)
1358 admin
.site
.register(rh
.TypePoste
, TypePosteAdmin
)
1359 admin
.site
.register(rh
.TypeRemuneration
, TypeRemunerationAdmin
)
1360 admin
.site
.register(rh
.TypeRevalorisation
, TypeRevalorisationAdmin
)
1361 admin
.site
.register(rh
.ValeurPoint
, ValeurPointAdmin
)
1362 admin
.site
.register(ImplantationProxy
, ImplantationProxyAdmin
)
1363 admin
.site
.register(RegionProxy
, RegionProxyAdmin
)