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
16 from project
.decorators
import in_drh_or_admin
17 from project
.groups
import grp_correspondants_rh
18 from project
.groups
import get_employe_from_user
19 from project
.rh
.forms
import ContratForm
, AyantDroitForm
, EmployeAdminForm
, \
20 AjaxSelect
, DossierForm
, ResponsableInlineForm
21 from project
.rh
import models
as rh
22 from project
.rh
.change_list
import ChangeList
25 class BaseAdmin(admin
.ModelAdmin
):
29 'css/admin_custom.css',
30 'jquery-autocomplete/jquery.autocomplete.css',
33 'https://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js',
34 'jquery-autocomplete/jquery.autocomplete.min.js',
38 # Admin pour reversion
40 class ArchivableAdmin(admin
.ModelAdmin
):
42 Admin pour les modèles archivables
44 list_filter
= ('archive', )
46 def queryset(self
, request
):
47 return self
.model
.avec_archives
.all()
49 def _archive(self
, obj
):
54 _archive
.short_description
= u
'Archivé'
55 _archive
.admin_order_field
= 'archive'
58 class RegionProxy(ref
.Region
):
59 """ Proxy utilisé pour les organigrammes par région """
62 verbose_name
= u
"Organigramme par région"
63 verbose_name_plural
= u
"Organigramme par région"
66 class ImplantationProxy(ref
.Implantation
):
67 """ Proxy utilisé pour les organigrammes par implantation """
70 verbose_name
= u
"Organigramme par implantations"
71 verbose_name_plural
= u
"Organigramme par implantations"
74 class ServiceProxy(rh
.Service
):
75 """ Proxy utilisé pour les organigrammes opar service """
79 verbose_name
= u
"Organigramme par services"
80 verbose_name_plural
= u
"Organigramme par services"
83 class EmployeProxy(rh
.Employe
):
84 """ Proxy utilisé pour les organigrammes des employés """
87 verbose_name
= u
"Organigramme des employés"
88 verbose_name_plural
= u
"Organigramme des employés"
91 class DateRangeMixin(object):
92 prefixe_recherche_temporelle
= ""
94 def get_changelist(self
, request
, **kwargs
):
95 if 'HTTP_REFERER' in request
.META
.keys():
96 referer
= request
.META
['HTTP_REFERER']
97 referer
= "/".join(referer
.split('/')[3:])
98 referer
= "/%s" % referer
.split('?')[0]
99 change_list_view
= 'admin:%s_%s_changelist' % (
100 self
.model
._meta
.app_label
,
101 self
.model
.__name__
.lower(),)
102 if referer
!= reverse(change_list_view
):
103 params
= request
.GET
.copy()
104 params
.update({'statut': 'Actif'})
109 # Override of the InlineModelAdmin to support the link in the tabular inline
110 class LinkedInline(admin
.options
.InlineModelAdmin
):
111 template
= "admin/linked.html"
112 admin_model_path
= None
114 def __init__(self
, *args
):
115 super(LinkedInline
, self
).__init__(*args
)
116 if self
.admin_model_path
is None:
117 self
.admin_model_path
= self
.model
.__name__
.lower()
120 class ProtectRegionMixin(object):
122 def queryset(self
, request
):
123 qs
= super(ProtectRegionMixin
, self
).queryset(request
)
125 user_groups
= request
.user
.groups
.all()
126 if in_drh_or_admin(request
.user
):
129 if grp_correspondants_rh
in user_groups
:
130 employe
= get_employe_from_user(request
.user
)
131 q
= Q(**{self
.model
.prefix_implantation
: \
132 employe
.implantation
.region
})
133 qs
= qs
.filter(q
).distinct()
137 def has_add_permission(self
, request
):
138 if not in_drh_or_admin(request
.user
):
143 def has_change_permission(self
, request
, obj
=None):
144 user_groups
= request
.user
.groups
.all()
146 # Lock pour autoriser uniquement les DRH à utiliser RH
147 if not in_drh_or_admin(request
.user
):
150 if len(user_groups
) == 0 and not request
.user
.is_superuser
:
155 ids
= [o
.id for o
in self
.queryset(request
)]
159 class DerniereModificationAdmin(admin
.ModelAdmin
):
161 def queryset(self
, request
):
162 qs
= super(DerniereModificationAdmin
, self
).queryset(request
)
163 ct
= ContentType
.objects
.get_for_model(self
.model
)
164 db_table
= self
.model
._meta
.db_table
165 pk
= self
.model
._meta
.pk
.column
166 return qs
.extra(select
={
168 "SELECT action_time FROM django_admin_log "
169 "WHERE content_type_id = %d AND object_id = %s.%s "
170 "ORDER BY action_time DESC "
171 "LIMIT 1" % (ct
.id, db_table
, pk
),
175 "INNER JOIN django_admin_log l ON l.user_id = u.id "
176 "WHERE l.content_type_id = %d AND object_id = %s.%s "
177 "ORDER BY action_time DESC "
178 "LIMIT 1" % (ct
.id, db_table
, pk
),
181 def derniere_modification(self
, obj
):
183 if obj
.date_modification
:
184 text
+= obj
.date_modification
.strftime('%d-%m-%Y %H:%M')
185 if obj
.user_modification
:
186 text
+= ' par ' + obj
.user_modification
188 derniere_modification
.short_description
= u
'dernière modification'
189 derniere_modification
.admin_order_field
= 'date_modification'
194 class CommentaireInlineForm(forms
.ModelForm
):
196 def save(self
, commit
=True):
198 # Hack: reversion.VersionAdmin ne sauvegarde pas les champs qui ne
199 # sont pas explicitement dans le formulaire. Il plante cependant
200 # leur valeur dans `self.initial`. Ceci est un peu fragile. Si
201 # c'est possible, il serait plus approprié que Reversion se rende
202 # compte qu'il manque des champs.
203 instance
= super(CommentaireInlineForm
, self
).save(commit
=False)
204 if instance
.owner_id
is None and 'owner' in self
.initial
:
205 instance
.owner_id
= self
.initial
['owner']
206 if instance
.date_creation
is None and 'date_creation' in self
.initial
:
207 instance
.date_creation
= self
.initial
['date_creation']
214 class ReadOnlyInlineMixin(object):
216 def get_readonly_fields(self
, request
, obj
=None):
217 return [f
.name
for f
in self
.model
._meta
.fields
]
220 class AyantDroitInline(admin
.StackedInline
):
221 model
= rh
.AyantDroit
222 form
= AyantDroitForm
229 ('nom_affichage', 'genre'),
237 class AyantDroitCommentaireInline(admin
.TabularInline
):
238 readonly_fields
= ('owner',)
239 model
= rh
.AyantDroitCommentaire
241 form
= CommentaireInlineForm
244 class ContratInline(admin
.TabularInline
):
250 class DossierROInline(ReadOnlyInlineMixin
, LinkedInline
):
251 template
= "admin/rh/dossier/linked.html"
256 def has_add_permission(self
, request
=None):
259 def has_change_permission(self
, request
, obj
=None):
262 def has_delete_permission(self
, request
, obj
=None):
266 class DossierCommentaireInline(admin
.TabularInline
):
267 readonly_fields
= ('owner',)
268 model
= rh
.DossierCommentaire
270 form
= CommentaireInlineForm
273 class DossierPieceInline(admin
.TabularInline
):
274 model
= rh
.DossierPiece
278 class EmployeInline(admin
.TabularInline
):
282 class EmployeCommentaireInline(admin
.TabularInline
):
283 readonly_fields
= ('owner',)
284 model
= rh
.EmployeCommentaire
286 form
= CommentaireInlineForm
289 class EmployePieceInline(admin
.TabularInline
):
290 model
= rh
.EmployePiece
294 class PosteCommentaireInline(admin
.TabularInline
):
295 readonly_fields
= ('owner',)
296 model
= rh
.PosteCommentaire
298 form
= CommentaireInlineForm
301 class PosteFinancementInline(admin
.TabularInline
):
302 model
= rh
.PosteFinancement
305 class PostePieceInline(admin
.TabularInline
):
306 model
= rh
.PostePiece
309 class RemunerationInline(admin
.TabularInline
):
310 model
= rh
.Remuneration
314 class RemunerationROInline(ReadOnlyInlineMixin
, RemunerationInline
):
318 class TypePosteInline(admin
.TabularInline
):
322 class PosteComparaisonInline(admin
.TabularInline
):
323 model
= rh
.PosteComparaison
326 class ClassementAdmin(reversion
.VersionAdmin
, DerniereModificationAdmin
,
328 ignore_duplicate_revisions
= True
329 list_display
= ('_classement', 'derniere_modification')
331 (None, {'fields': ('type', 'echelon', 'degre', 'coefficient',)}),
334 def _classement(self
, obj
):
336 _classement
.short_description
= u
"Classement"
339 class DeviseAdmin(reversion
.VersionAdmin
, ArchivableAdmin
,
340 DerniereModificationAdmin
, BaseAdmin
):
341 ignore_duplicate_revisions
= True
343 'code', 'nom', '_archive', 'derniere_modification',
345 list_filter
= ('archive', )
347 (None, {'fields': ('code', 'nom', 'archive', )}),
351 class DossierAdmin(DateRangeMixin
, ProtectRegionMixin
, reversion
.VersionAdmin
,
352 AjaxSelect
, DerniereModificationAdmin
, BaseAdmin
):
353 ignore_duplicate_revisions
= True
354 alphabet_filter
= 'employe__nom'
362 'poste__nom_feminin',
363 'poste__implantation__nom',
373 'derniere_modification',
376 list_display_links
= ('_nom',)
378 'poste__implantation__region',
379 'poste__implantation',
380 'poste__type_poste__categorie_emploi',
382 'rh_contrats__type_contrat',
385 inlines
= (DossierPieceInline
, ContratInline
,
387 DossierCommentaireInline
,
396 'organisme_bstg',)}),
401 'remplacement_de', )}),
405 ('regime_travail', 'regime_travail_nb_heure_semaine'),)}),
406 ('Occupation du Poste par cet Employe', {
407 'fields': (('date_debut', 'date_fin'), )}
410 form
= make_ajax_form(rh
.Dossier
, {
411 'employe': 'employes',
413 'remplacement_de': 'dossiers',
414 }, superclass
=DossierForm
)
416 def lookup_allowed(self
, key
, value
):
418 'employe__nom__istartswith',
419 'poste__implantation__region__id__exact',
420 'poste__implantation__id__exact',
421 'poste__type_poste__id__exact',
422 'poste__type_poste__categorie_emploi__id__exact',
423 'rh_contrats__type_contrat__id__exact',
431 _id
.short_description
= u
"#"
432 _id
.admin_order_field
= "id"
435 return "%d : %s %s" % (
437 obj
.employe
.nom
.upper(),
439 _nom
.allow_tags
= True
440 _nom
.short_description
= u
"Dossier"
442 def _apercu(self
, d
):
443 apercu_link
= u
"""<a title="Aperçu du dossier"
444 onclick="return showAddAnotherPopup(this);"
446 <img src="%simg/dossier-apercu.png" />
448 (reverse('dossier_apercu', args
=(d
.id,)),
452 _apercu
.allow_tags
= True
453 _apercu
.short_description
= u
""
457 dossiers_dae
= d
.dossiers_dae
.all()
458 if len(dossiers_dae
) > 0:
459 dossier_dae
= dossiers_dae
[0]
460 apercu_link
= u
"""<a title="Aperçu du dossier"
461 onclick="return showAddAnotherPopup(this);"
463 <img src="%simg/loupe.png" />
465 (reverse('embauche_consulter', args
=(dossier_dae
.id,)),
469 _dae
.allow_tags
= True
470 _dae
.short_description
= u
"DAE"
472 def _date_debut(self
, obj
):
473 return date(obj
.date_debut
)
475 _date_debut
.short_description
= u
'Occupation début'
476 _date_debut
.admin_order_field
= 'date_debut'
478 def _date_fin(self
, obj
):
479 return date(obj
.date_fin
)
480 _date_fin
.short_description
= u
'Occupation fin'
481 _date_fin
.admin_order_field
= 'date_fin'
483 def _poste(self
, dossier
):
484 link
= u
"""<a title="Aperçu du poste"
485 onclick="return showAddAnotherPopup(this);"
486 href='%s'><img src="%simg/poste-apercu.png" />
488 <a href="%s" title="Modifier le poste">%s</a>""" % \
489 (reverse('poste_apercu', args
=(dossier
.poste
.id,)),
491 reverse('admin:rh_poste_change', args
=(dossier
.poste
.id,)),
495 _poste
.allow_tags
= True
496 _poste
.short_description
= u
'Poste'
497 _poste
.admin_order_field
= 'poste__nom'
499 def _employe(self
, obj
):
500 employe
= obj
.employe
501 view_link
= reverse('employe_apercu', args
=(employe
.id,))
502 edit_link
= reverse('admin:rh_employe_change', args
=(employe
.id,))
505 view
= u
"""<a href="%s"
506 title="Aperçu l'employé"
507 onclick="return showAddAnotherPopup(this);">
508 <img src="%simg/employe-apercu.png" />
509 </a>""" % (view_link
, settings
.STATIC_URL
,)
510 return u
"""%s<a href='%s' style="%s;">%s</a>""" % \
511 (view
, edit_link
, style
, employe
)
512 _employe
.allow_tags
= True
513 _employe
.short_description
= u
"Employé"
514 _employe
.admin_order_field
= "employe__nom"
516 def save_formset(self
, request
, form
, formset
, change
):
517 instances
= formset
.save(commit
=False)
518 for instance
in instances
:
519 if instance
.__class__
== rh
.DossierCommentaire
:
520 instance
.owner
= request
.user
521 instance
.date_creation
= datetime
.datetime
.now()
525 class EmployeAdminBase(DateRangeMixin
, ProtectRegionMixin
,
526 DerniereModificationAdmin
, BaseAdmin
):
527 prefixe_recherche_temporelle
= "rh_dossiers__"
528 alphabet_filter
= 'nom'
529 DEFAULT_ALPHABET
= u
'ABCDEFGHIJKLMNOPQRSTUVWXYZ'
531 'id', 'nom', 'prenom', 'nom_affichage',
532 'rh_dossiers__poste__nom',
533 'rh_dossiers__poste__nom_feminin'
536 form
= EmployeAdminForm
538 '_id', '_apercu', '_nom', '_dossiers_postes', 'date_entree',
539 'derniere_modification'
541 list_display_links
= ('_nom',)
543 'rh_dossiers__poste__implantation__region',
544 'rh_dossiers__poste__implantation', 'nb_postes'
547 AyantDroitInline
, DossierROInline
, EmployePieceInline
,
548 EmployeCommentaireInline
554 ('nom_affichage', 'genre'),
559 ('Informations personnelles', {
560 'fields': ('situation_famille', 'date_entree', )
562 ('Coordonnées personnelles', {
564 ('tel_domicile', 'tel_cellulaire'),
565 ('adresse', 'ville'),
566 ('code_postal', 'province'),
573 def _apercu(self
, obj
):
574 return u
"""<a title="Aperçu de l'employé"
575 onclick="return showAddAnotherPopup(this);"
577 <img src="%simg/employe-apercu.png" />
579 (reverse('employe_apercu', args
=(obj
.id,)), settings
.STATIC_URL
)
580 _apercu
.allow_tags
= True
581 _apercu
.short_description
= u
""
584 edit_link
= reverse('admin:rh_employe_change', args
=(obj
.id,))
585 return u
"""<a href='%s'><strong>%s</strong></a>""" % \
586 (edit_link
, "%s %s" % (obj
.nom
.upper(), obj
.prenom
))
587 _nom
.allow_tags
= True
588 _nom
.short_description
= u
"Employé"
589 _nom
.admin_order_field
= "nom"
593 _id
.short_description
= u
"#"
594 _id
.admin_order_field
= "id"
596 def _date_modification(self
, obj
):
597 return date(obj
.date_modification
) \
598 if obj
.date_modification
is not None else "(aucune)"
599 _date_modification
.short_description
= u
'date modification'
600 _date_modification
.admin_order_field
= 'date_modification'
602 def _dossiers_postes(self
, obj
):
604 for d
in obj
.rh_dossiers
.all().order_by('-date_debut'):
605 dossier
= u
"""<a title="Aperçu du dossier"
607 onclick="return showAddAnotherPopup(this);"
608 title="Aperçu du dossier">
609 <img src="%simg/dossier-apercu.png" />
611 <a href="%s">Dossier</a>
613 (reverse('dossier_apercu', args
=(d
.id,)),
615 reverse('admin:rh_dossier_change', args
=(d
.id,)))
617 poste
= u
"""<a title="Aperçu du poste"
619 onclick="return showAddAnotherPopup(this);"
620 title="Aperçu du poste">
621 <img src="%simg/poste-apercu.png" />
623 <a href="%s">Poste</a>
625 (reverse('poste_apercu', args
=(d
.poste
.id,)),
627 reverse('admin:rh_poste_change', args
=(d
.poste
.id,)))
628 link
= u
"""<li>%s %s - %s : [%s] %s</li>""" % \
635 # Dossier terminé en gris non cliquable
636 if d
.date_fin
is not None and d
.date_fin
< datetime
.date
.today():
637 link
= u
"""<li style="color: grey">%s : [%s] %s</li>""" % \
644 return "<ul>%s</ul>" % "\n".join(l
)
645 _dossiers_postes
.allow_tags
= True
646 _dossiers_postes
.short_description
= u
"Dossiers et postes"
648 def queryset(self
, request
):
649 qs
= super(EmployeAdminBase
, self
).queryset(request
)
650 return qs
.select_related(depth
=1).order_by('nom')
652 def save_formset(self
, request
, form
, formset
, change
):
653 instances
= formset
.save(commit
=False)
654 for instance
in instances
:
655 if instance
.__class__
== rh
.EmployeCommentaire
:
656 instance
.owner
= request
.user
657 instance
.date_creation
= datetime
.datetime
.now()
661 class EmployeAdmin(reversion
.VersionAdmin
, EmployeAdminBase
):
662 ignore_duplicate_revisions
= True
665 class EmployeProxyAdmin(EmployeAdminBase
):
666 list_display
= ('_id', '_apercu', '_nom', '_organigramme')
669 def __init__(self
, *args
, **kwargs
):
670 super(EmployeProxyAdmin
, self
).__init__(*args
, **kwargs
)
671 self
.list_display_links
= (None, )
673 def has_add_permission(self
, obj
):
676 def _organigramme(self
, obj
):
678 for d
in rh
.Dossier
.objects
.filter(
679 Q(date_fin__gt
=datetime
.date
.today()) |
Q(date_fin
=None),
680 Q(date_debut__lt
=datetime
.date
.today()) |
Q(date_debut
=None),
684 u
'Organigramme, niveau: ' \
685 u
'<input type="text" id="level_%s" ' \
686 u
'style="width:30px;height:15px;" /> ' \
687 u
'<input type="button" value="Générer" ' \
688 u
"""onclick="window.location='%s' + """ \
689 u
"""document.getElementById('level_%s').value" />""" % (
691 reverse('rho_employe_sans_niveau', args
=(d
.poste
.id,)),
694 link
= u
"""<li>%s - [%s] %s : %s</li>""" % (
701 return "<ul>%s</ul>" % "\n".join(l
)
703 _organigramme
.allow_tags
= True
704 _organigramme
.short_description
= "Organigramme"
707 class CategorieEmploiAdmin(reversion
.VersionAdmin
,
708 DerniereModificationAdmin
, BaseAdmin
):
709 ignore_duplicate_revisions
= True
710 list_display
= ('nom', 'derniere_modification')
711 inlines
= (TypePosteInline
,)
713 (None, {'fields': ('nom', )}),
717 class OrganismeBstgAdmin(reversion
.VersionAdmin
, DerniereModificationAdmin
,
719 ignore_duplicate_revisions
= True
720 search_fields
= ('nom',)
721 list_display
= ('nom', 'type', 'pays', 'derniere_modification')
722 list_filter
= ('type', )
723 inlines
= (DossierROInline
,)
725 (None, {'fields': ('nom', 'type', 'pays',)}),
729 class PosteAdmin(DateRangeMixin
, ProtectRegionMixin
, reversion
.VersionAdmin
,
730 AjaxSelect
, DerniereModificationAdmin
, BaseAdmin
):
731 ignore_duplicate_revisions
= True
732 form
= make_ajax_form(rh
.Poste
, {
733 'implantation': 'implantations',
734 'type_poste': 'typepostes',
735 'responsable': 'postes',
736 'valeur_point_min': 'valeurpoints',
737 'valeur_point_max': 'valeurpoints',
739 alphabet_filter
= 'nom'
744 'implantation__region__code',
745 'implantation__region__nom',
746 'rh_dossiers__employe__id',
747 'rh_dossiers__employe__nom',
748 'rh_dossiers__employe__prenom',
751 '_id', '_apercu', '_nom', '_occupe_par', 'implantation', '_service',
752 '_responsable', 'date_debut', 'date_fin', 'derniere_modification',
756 'implantation__region',
760 'type_poste__categorie_emploi',
761 'type_poste__famille_professionnelle',
764 list_display_links
= ('_nom',)
767 ('nom', 'nom_feminin'),
777 'regime_travail_nb_heure_semaine'),
781 'fields': (('local', 'expatrie', 'mise_a_disposition', 'appel'),)}
784 'fields': (('classement_min',
797 ('Comparatifs de rémunération', {
798 'fields': ('devise_comparaison',
799 ('comp_locale_min', 'comp_locale_max'),
800 ('comp_universite_min', 'comp_universite_max'),
801 ('comp_fonctionpub_min', 'comp_fonctionpub_max'),
802 ('comp_ong_min', 'comp_ong_max'),
803 ('comp_autre_min', 'comp_autre_max'))}
806 'fields': ('justification',)}
808 ('Autres Méta-données', {
809 'fields': ('date_debut', 'date_fin')}
813 inlines
= (PosteFinancementInline
,
816 PosteComparaisonInline
,
817 PosteCommentaireInline
, )
819 def lookup_allowed(self
, key
, value
):
821 'date_debut__gte', 'date_debut__isnull', 'date_fin__lte',
822 'date_fin__isnull', 'implantation__region__id__exact',
823 'implantation__id__exact', 'type_poste__id__exact',
824 'type_poste__categorie_emploi__id__exact', 'service__id__exact',
825 'service__isnull', 'vacant__exact', 'vacant__isnull',
826 ) or super(PosteAdmin
, self
).lookup_allowed(key
, value
)
828 def _apercu(self
, poste
):
829 view_link
= u
"""<a onclick="return showAddAnotherPopup(this);"
830 title="Aperçu du poste"
832 <img src="%simg/poste-apercu.png" />
834 (reverse('poste_apercu', args
=(poste
.id,)),
835 settings
.STATIC_URL
,)
837 _apercu
.allow_tags
= True
838 _apercu
.short_description
= ''
840 def _dae(self
, poste
):
842 postes_dae
= poste
.postes_dae
.all()
843 if len(postes_dae
) > 0:
844 poste_dae
= postes_dae
[0]
846 u
'<a title="Aperçu du dossier" href="%s" ' \
847 u
'onclick="return showAddAnotherPopup(this);">' \
848 u
'<img src="%simg/loupe.png" /></a>' % (reverse(
849 'poste_consulter', args
=("dae-%s" % poste_dae
.id,)
850 ), settings
.STATIC_URL
)
852 _dae
.allow_tags
= True
853 _dae
.short_description
= u
"DAE"
857 _id
.short_description
= '#'
858 _id
.admin_order_field
= 'id'
860 def _service(self
, obj
):
862 _service
.short_description
= 'Service'
863 _service
.allow_tags
= True
865 def _responsable(self
, obj
):
867 responsable
= u
"""<a href="%s"
868 onclick="return showAddAnotherPopup(this)">
869 <img src="%simg/poste-apercu.png"
870 title="Aperçu du poste" />
874 (reverse('poste_apercu', args
=(obj
.responsable
.id,)),
876 reverse('admin:rh_poste_change', args
=(obj
.responsable
.id,)),
882 dossier
= obj
.responsable
.rh_dossiers
.all() \
883 .order_by('-date_debut')[0]
884 employe_id
= dossier
.employe
.id
885 employe_html
= u
"""<br />
887 onclick="return showAddAnotherPopup(this)">
888 <img src="%simg/employe-apercu.png"
889 title="Aperçu de l'employé">
891 <a href="%s">%s</a>""" % \
892 (reverse('employe_apercu', args
=(employe_id
,)),
894 reverse('admin:rh_employe_change', args
=(employe_id
,)),
899 return "%s %s" % (responsable
, employe_html
)
900 _responsable
.short_description
= 'Responsable'
901 _responsable
.allow_tags
= True
903 def _implantation(self
, poste
):
904 return poste
.implantation
.nom
905 _implantation
.short_description
= 'Implantation'
906 _implantation
.admin_order_field
= 'implantation'
908 def _nom(self
, poste
):
909 return """<a href="%s">%s</a>""" % \
910 (reverse('admin:rh_poste_change', args
=(poste
.id,)),
912 _nom
.allow_tags
= True
913 _nom
.short_description
= u
'Poste'
914 _nom
.admin_order_field
= 'nom'
916 def _occupe_par(self
, obj
):
917 """Formatte la méthode Poste.occupe_par() pour l'admin"""
919 if obj
.date_fin
is not None and obj
.date_fin
< datetime
.date
.today():
921 employes
= obj
.occupe_par()
925 link
= u
"""<a href='%s'
926 title='Aperçu de l\'employé'
927 onclick='return showAddAnotherPopup(this)'>
928 <img src='%simg/employe-apercu.png' />
930 <a href='%s'>%s</a>""" % \
931 (reverse('employe_apercu', args
=(e
.id,)),
933 reverse('admin:rh_employe_change', args
=(e
.id,)),
936 output
= "\n<br />".join(l
)
938 _occupe_par
.allow_tags
= True
939 _occupe_par
.short_description
= "Occupé par"
941 def save_formset(self
, request
, form
, formset
, change
):
942 instances
= formset
.save(commit
=False)
943 for instance
in instances
:
944 if instance
.__class__
== rh
.PosteCommentaire
:
945 instance
.owner
= request
.user
946 instance
.date_creation
= datetime
.datetime
.now()
951 class ResponsableInline(admin
.TabularInline
):
952 model
= rh
.ResponsableImplantation
954 fk_name
= "implantation"
955 form
= ResponsableInlineForm
958 class ResponsableImplantationAdmin(BaseAdmin
):
961 inlines
= (ResponsableInline
, )
962 list_filter
= ('region', 'statut', )
963 list_display
= ('_region', '_nom', 'statut', '_responsable', )
964 list_display_links
= ('_nom',)
965 readonly_fields
= ('nom', )
968 'responsable__employe__id',
969 'responsable__employe__nom',
970 'responsable__employe__prenom',
974 def _region(self
, obj
):
975 return obj
.region
.code
976 _region
.short_description
= u
"Région"
977 _region
.admin_order_field
= 'region__code'
981 _nom
.short_description
= u
"Implantation"
982 _nom
.admin_order_field
= 'nom'
984 def _responsable(self
, obj
):
986 employe
= obj
.responsable
.employe
987 dossiers
= employe
.dossiers_encours()
988 if len(dossiers
) == 0:
989 return u
"<span style='color: red;'>%s %s </span>" % (
990 employe
, u
"sans dossier actif")
994 if obj
.statut
in (1, 2): # ouverte, ouverture imminente
995 css
= "style='color: red;'"
998 return u
"<span %s>Pas de responsable</span>" % css
999 _responsable
.allow_tags
= True
1000 _responsable
.short_description
= u
"Responsable"
1001 _responsable
.admin_order_field
= 'responsable__employe__nom'
1003 def has_add_permission(self
, request
=None):
1006 def has_change_permission(self
, request
, obj
=None):
1007 return in_drh_or_admin(request
.user
)
1009 def has_delete_permission(self
, request
, obj
=None):
1013 class ServiceAdminBase(ArchivableAdmin
, DerniereModificationAdmin
, BaseAdmin
):
1014 list_display
= ('nom', '_archive', 'derniere_modification')
1015 list_filter
= ('archive', )
1017 (None, {'fields': ('nom', 'archive')}),
1021 class ServiceAdmin(reversion
.VersionAdmin
, ServiceAdminBase
):
1022 ignore_duplicate_revisions
= True
1025 class ServiceProxyAdmin(ServiceAdminBase
):
1026 list_display
= ('nom', '_organigramme', '_archive', )
1029 def __init__(self
, *args
, **kwargs
):
1030 super(ServiceProxyAdmin
, self
).__init__(*args
, **kwargs
)
1031 self
.list_display_links
= (None, )
1033 def queryset(self
, request
):
1034 return super(ServiceProxyAdmin
, self
).queryset(request
) \
1035 .annotate(num_postes
=Count('rh_postes')) \
1036 .filter(num_postes__gt
=0)
1038 def has_add_permission(self
, obj
):
1041 def has_change_permission(self
, request
, obj
=None):
1042 return in_drh_or_admin(request
.user
)
1044 def _organigramme(self
, obj
):
1045 return """<a href="%s"><strong>Organigramme</strong></a>""" % \
1046 (reverse('rho_service', args
=(obj
.id,)))
1047 _organigramme
.allow_tags
= True
1048 _organigramme
.short_description
= "Organigramme"
1051 class StatutAdmin(reversion
.VersionAdmin
, DerniereModificationAdmin
,
1053 ignore_duplicate_revisions
= True
1054 list_display
= ('code', 'nom', 'derniere_modification')
1057 'fields': ('code', 'nom', ),
1062 class TauxChangeAdmin(reversion
.VersionAdmin
, DerniereModificationAdmin
,
1064 ignore_duplicate_revisions
= True
1065 list_display
= ('taux', 'devise', 'annee', 'derniere_modification')
1066 list_filter
= ('devise',)
1069 'fields': ('taux', 'devise', 'annee', ),
1074 class TypeContratAdmin(reversion
.VersionAdmin
, DerniereModificationAdmin
,
1076 ignore_duplicate_revisions
= True
1077 list_display
= ('nom', 'nom_long', 'derniere_modification')
1080 'fields': ('nom', 'nom_long', ),
1085 class TypePosteAdmin(reversion
.VersionAdmin
, DerniereModificationAdmin
,
1087 ignore_duplicate_revisions
= True
1088 search_fields
= ('nom', 'nom_feminin', )
1089 list_display
= ('nom', 'categorie_emploi', 'derniere_modification')
1090 list_filter
= ('categorie_emploi', 'famille_professionnelle')
1094 'nom', 'nom_feminin', 'is_responsable', 'categorie_emploi',
1095 'famille_professionnelle',
1101 class TypeRemunerationAdmin(reversion
.VersionAdmin
, ArchivableAdmin
,
1102 DerniereModificationAdmin
, BaseAdmin
):
1103 ignore_duplicate_revisions
= True
1105 'nom', 'type_paiement', 'nature_remuneration', '_archive',
1106 'derniere_modification'
1108 list_filter
= ('archive', )
1112 'nom', 'type_paiement', 'nature_remuneration', 'archive'
1118 class TypeRevalorisationAdmin(reversion
.VersionAdmin
,
1119 DerniereModificationAdmin
, BaseAdmin
):
1120 ignore_duplicate_revisions
= True
1121 list_display
= ('nom', 'derniere_modification')
1123 (None, {'fields': ('nom',)}),
1127 class ValeurPointAdmin(reversion
.VersionAdmin
, DerniereModificationAdmin
,
1129 ignore_duplicate_revisions
= True
1131 '_devise_code', '_devise_nom', 'annee', 'implantation',
1132 'valeur', 'derniere_modification'
1134 list_filter
= ('annee', 'devise', 'implantation__region', )
1136 (None, {'fields': ('valeur', 'devise', 'implantation', 'annee')}),
1139 def _devise_code(self
, obj
):
1140 return obj
.devise
.code
1141 _devise_code
.short_description
= "Code de la devise"
1143 def _devise_nom(self
, obj
):
1144 return obj
.devise
.nom
1145 _devise_nom
.short_description
= "Nom de la devise"
1148 class ImplantationProxyAdmin(BaseAdmin
):
1149 list_display
= ('nom', '_organigramme')
1152 def __init__(self
, *args
, **kwargs
):
1153 super(ImplantationProxyAdmin
, self
).__init__(*args
, **kwargs
)
1154 self
.list_display_links
= (None, )
1156 def has_add_permission(self
, obj
):
1159 def has_change_permission(self
, request
, obj
=None):
1160 return in_drh_or_admin(request
.user
)
1162 def _organigramme(self
, obj
):
1163 return '<a href="%s"><strong>Organigramme</strong></a>' % (
1164 reverse('rho_implantation', args
=(obj
.id,))
1166 _organigramme
.allow_tags
= True
1167 _organigramme
.short_description
= "Organigramme"
1170 class RegionProxyAdmin(BaseAdmin
):
1171 list_display
= ('nom', '_organigramme')
1174 def __init__(self
, *args
, **kwargs
):
1175 super(RegionProxyAdmin
, self
).__init__(*args
, **kwargs
)
1176 self
.list_display_links
= (None, )
1178 def has_add_permission(self
, obj
):
1181 def has_change_permission(self
, request
, obj
=None):
1182 return in_drh_or_admin(request
.user
)
1184 def _organigramme(self
, obj
):
1185 return """<a href="%s"><strong>Organigramme</strong></a>""" % (
1186 reverse('rho_region', args
=(obj
.id,))
1188 _organigramme
.allow_tags
= True
1189 _organigramme
.short_description
= "Organigramme"
1192 admin
.site
.register(rh
.Classement
, ClassementAdmin
)
1193 admin
.site
.register(rh
.Devise
, DeviseAdmin
)
1194 admin
.site
.register(rh
.Dossier
, DossierAdmin
)
1195 admin
.site
.register(EmployeProxy
, EmployeProxyAdmin
)
1196 admin
.site
.register(ServiceProxy
, ServiceProxyAdmin
)
1197 admin
.site
.register(rh
.Employe
, EmployeAdmin
)
1198 admin
.site
.register(rh
.CategorieEmploi
, CategorieEmploiAdmin
)
1199 admin
.site
.register(rh
.FamilleProfessionnelle
)
1200 admin
.site
.register(rh
.OrganismeBstg
, OrganismeBstgAdmin
)
1201 admin
.site
.register(rh
.Poste
, PosteAdmin
)
1202 admin
.site
.register(
1203 rh
.ResponsableImplantationProxy
, ResponsableImplantationAdmin
1205 admin
.site
.register(rh
.Service
, ServiceAdmin
)
1206 admin
.site
.register(rh
.Statut
, StatutAdmin
)
1207 admin
.site
.register(rh
.TauxChange
, TauxChangeAdmin
)
1208 admin
.site
.register(rh
.TypeContrat
, TypeContratAdmin
)
1209 admin
.site
.register(rh
.TypePoste
, TypePosteAdmin
)
1210 admin
.site
.register(rh
.TypeRemuneration
, TypeRemunerationAdmin
)
1211 admin
.site
.register(rh
.TypeRevalorisation
, TypeRevalorisationAdmin
)
1212 admin
.site
.register(rh
.ValeurPoint
, ValeurPointAdmin
)
1213 admin
.site
.register(ImplantationProxy
, ImplantationProxyAdmin
)
1214 admin
.site
.register(RegionProxy
, RegionProxyAdmin
)