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
.decorators
import in_drh_or_admin
18 from project
.groups
import grp_correspondants_rh
19 from project
.groups
import get_employe_from_user
20 from project
.rh
import models
as rh
21 from project
.rh
.change_list
import ChangeList
22 from project
.rh
.forms
import ContratForm
, AyantDroitForm
, EmployeAdminForm
, \
23 AjaxSelect
, DossierForm
, ResponsableInlineForm
26 class BaseAdmin(admin
.ModelAdmin
):
30 'css/admin_custom.css',
31 'jquery-autocomplete/jquery.autocomplete.css',
34 'https://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js',
35 'jquery-autocomplete/jquery.autocomplete.min.js',
39 # Admin pour reversion
41 class ArchivableAdmin(admin
.ModelAdmin
):
43 Admin pour les modèles archivables
45 list_filter
= ('archive', )
47 def queryset(self
, request
):
48 return self
.model
.avec_archives
.all()
50 def _archive(self
, obj
):
55 _archive
.short_description
= u
'Archivé'
56 _archive
.admin_order_field
= 'archive'
59 class RegionProxy(ref
.Region
):
60 """ Proxy utilisé pour les organigrammes par région """
63 verbose_name
= u
"Organigramme par région"
64 verbose_name_plural
= u
"Organigramme par région"
67 class ImplantationProxy(ref
.Implantation
):
68 """ Proxy utilisé pour les organigrammes par implantation """
71 verbose_name
= u
"Organigramme par implantations"
72 verbose_name_plural
= u
"Organigramme par implantations"
75 class ServiceProxy(rh
.Service
):
76 """ Proxy utilisé pour les organigrammes opar service """
80 verbose_name
= u
"Organigramme par services"
81 verbose_name_plural
= u
"Organigramme par services"
84 class EmployeProxy(rh
.Employe
):
85 """ Proxy utilisé pour les organigrammes des employés """
88 verbose_name
= u
"Organigramme des employés"
89 verbose_name_plural
= u
"Organigramme des employés"
92 class DateRangeMixin(object):
93 prefixe_recherche_temporelle
= ""
95 def get_changelist(self
, request
, **kwargs
):
96 if 'HTTP_REFERER' in request
.META
.keys():
97 referer
= request
.META
['HTTP_REFERER']
98 referer
= "/".join(referer
.split('/')[3:])
99 referer
= "/%s" % referer
.split('?')[0]
100 change_list_view
= 'admin:%s_%s_changelist' % (
101 self
.model
._meta
.app_label
,
102 self
.model
.__name__
.lower(),)
103 if referer
!= reverse(change_list_view
):
104 params
= request
.GET
.copy()
105 params
.update({'statut': 'Actif'})
110 # Override of the InlineModelAdmin to support the link in the tabular inline
111 class LinkedInline(admin
.options
.InlineModelAdmin
):
112 template
= "admin/linked.html"
113 admin_model_path
= None
115 def __init__(self
, *args
):
116 super(LinkedInline
, self
).__init__(*args
)
117 if self
.admin_model_path
is None:
118 self
.admin_model_path
= self
.model
.__name__
.lower()
121 class ProtectRegionMixin(object):
123 def queryset(self
, request
):
124 qs
= super(ProtectRegionMixin
, self
).queryset(request
)
126 user_groups
= request
.user
.groups
.all()
127 if in_drh_or_admin(request
.user
):
130 if grp_correspondants_rh
in user_groups
:
131 employe
= get_employe_from_user(request
.user
)
132 q
= Q(**{self
.model
.prefix_implantation
: \
133 employe
.implantation
.region
})
134 qs
= qs
.filter(q
).distinct()
138 def has_add_permission(self
, request
):
139 if not in_drh_or_admin(request
.user
):
144 def has_change_permission(self
, request
, obj
=None):
145 user_groups
= request
.user
.groups
.all()
147 # Lock pour autoriser uniquement les DRH à utiliser RH
148 if not in_drh_or_admin(request
.user
):
151 if len(user_groups
) == 0 and not request
.user
.is_superuser
:
156 ids
= [o
.id for o
in self
.queryset(request
)]
160 class DerniereModificationAdmin(admin
.ModelAdmin
):
162 def queryset(self
, request
):
163 qs
= super(DerniereModificationAdmin
, self
).queryset(request
)
164 ct
= ContentType
.objects
.get_for_model(self
.model
)
165 db_table
= self
.model
._meta
.db_table
166 pk
= self
.model
._meta
.pk
.column
167 return qs
.extra(select
={
169 "SELECT action_time FROM django_admin_log "
170 "WHERE content_type_id = %d AND object_id = %s.%s "
171 "ORDER BY action_time DESC "
172 "LIMIT 1" % (ct
.id, db_table
, pk
),
176 "INNER JOIN django_admin_log l ON l.user_id = u.id "
177 "WHERE l.content_type_id = %d AND object_id = %s.%s "
178 "ORDER BY action_time DESC "
179 "LIMIT 1" % (ct
.id, db_table
, pk
),
182 def derniere_modification(self
, obj
):
184 if obj
.date_modification
:
185 text
+= obj
.date_modification
.strftime('%d-%m-%Y %H:%M')
186 if obj
.user_modification
:
187 text
+= ' par ' + obj
.user_modification
189 derniere_modification
.short_description
= u
'dernière modification'
190 derniere_modification
.admin_order_field
= 'date_modification'
195 class CommentaireInlineForm(forms
.ModelForm
):
197 def save(self
, commit
=True):
199 # Hack: reversion.VersionAdmin ne sauvegarde pas les champs qui ne
200 # sont pas explicitement dans le formulaire. Il plante cependant
201 # leur valeur dans `self.initial`. Ceci est un peu fragile. Si
202 # c'est possible, il serait plus approprié que Reversion se rende
203 # compte qu'il manque des champs.
204 instance
= super(CommentaireInlineForm
, self
).save(commit
=False)
205 if instance
.owner_id
is None and 'owner' in self
.initial
:
206 instance
.owner_id
= self
.initial
['owner']
207 if instance
.date_creation
is None and 'date_creation' in self
.initial
:
208 instance
.date_creation
= self
.initial
['date_creation']
215 class ReadOnlyInlineMixin(object):
217 def get_readonly_fields(self
, request
, obj
=None):
218 return [f
.name
for f
in self
.model
._meta
.fields
]
221 class AyantDroitInline(admin
.StackedInline
):
222 model
= rh
.AyantDroit
223 form
= AyantDroitForm
230 ('nom_affichage', 'genre'),
238 class AyantDroitCommentaireInline(admin
.TabularInline
):
239 readonly_fields
= ('owner',)
240 model
= rh
.AyantDroitCommentaire
242 form
= CommentaireInlineForm
245 class ContratInline(admin
.TabularInline
):
251 class DossierROInline(ReadOnlyInlineMixin
, LinkedInline
):
252 template
= "admin/rh/dossier/linked.html"
257 def has_add_permission(self
, request
=None):
260 def has_change_permission(self
, request
, obj
=None):
263 def has_delete_permission(self
, request
, obj
=None):
267 class DossierCommentaireInline(admin
.TabularInline
):
268 readonly_fields
= ('owner',)
269 model
= rh
.DossierCommentaire
271 form
= CommentaireInlineForm
274 class DossierPieceInline(admin
.TabularInline
):
275 model
= rh
.DossierPiece
279 class EmployeInline(admin
.TabularInline
):
283 class EmployeCommentaireInline(admin
.TabularInline
):
284 readonly_fields
= ('owner',)
285 model
= rh
.EmployeCommentaire
287 form
= CommentaireInlineForm
290 class EmployePieceInline(admin
.TabularInline
):
291 model
= rh
.EmployePiece
295 class PosteCommentaireInline(admin
.TabularInline
):
296 readonly_fields
= ('owner',)
297 model
= rh
.PosteCommentaire
299 form
= CommentaireInlineForm
302 class PosteFinancementInline(admin
.TabularInline
):
303 model
= rh
.PosteFinancement
306 class PostePieceInline(admin
.TabularInline
):
307 model
= rh
.PostePiece
310 class RemunerationInline(admin
.TabularInline
):
311 model
= rh
.Remuneration
315 class RemunerationROInline(ReadOnlyInlineMixin
, RemunerationInline
):
319 class TypePosteInline(admin
.TabularInline
):
323 class PosteComparaisonInline(admin
.TabularInline
):
324 model
= rh
.PosteComparaison
327 class ClassementAdmin(reversion
.VersionAdmin
, DerniereModificationAdmin
,
329 ignore_duplicate_revisions
= True
330 list_display
= ('_classement', 'derniere_modification')
332 (None, {'fields': ('type', 'echelon', 'degre', 'coefficient',)}),
335 def _classement(self
, obj
):
337 _classement
.short_description
= u
"Classement"
340 class DeviseAdmin(reversion
.VersionAdmin
, ArchivableAdmin
,
341 DerniereModificationAdmin
, BaseAdmin
):
342 ignore_duplicate_revisions
= True
344 'code', 'nom', '_archive', 'derniere_modification',
346 list_filter
= ('archive', )
348 (None, {'fields': ('code', 'nom', 'archive', )}),
352 class DossierAdmin(DateRangeMixin
, ProtectRegionMixin
, reversion
.VersionAdmin
,
353 AjaxSelect
, DerniereModificationAdmin
, BaseAdmin
):
354 ignore_duplicate_revisions
= True
355 alphabet_filter
= 'employe__nom'
363 'poste__nom_feminin',
364 'poste__implantation__nom',
376 'derniere_modification',
379 list_display_links
= ('_nom',)
381 'poste__implantation__region',
382 'poste__implantation',
383 'poste__type_poste__categorie_emploi',
385 'rh_contrats__type_contrat',
388 inlines
= (DossierPieceInline
, ContratInline
,
390 DossierCommentaireInline
,
399 'organisme_bstg',)}),
404 'remplacement_de', )}),
408 ('regime_travail', 'regime_travail_nb_heure_semaine'),)}),
409 ('Occupation du Poste par cet Employe', {
410 'fields': (('date_debut', 'date_fin'), )}
413 form
= make_ajax_form(rh
.Dossier
, {
414 'employe': 'employes',
416 'remplacement_de': 'dossiers',
417 }, superclass
=DossierForm
)
419 def lookup_allowed(self
, key
, value
):
421 'employe__nom__istartswith',
422 'poste__implantation__region__id__exact',
423 'poste__implantation__id__exact',
424 'poste__type_poste__id__exact',
425 'poste__type_poste__categorie_emploi__id__exact',
426 'rh_contrats__type_contrat__id__exact',
434 _id
.short_description
= u
"#"
435 _id
.admin_order_field
= "id"
437 def _apercu(self
, d
):
438 apercu_link
= u
"""<a title="Aperçu du dossier"
439 onclick="return showAddAnotherPopup(this);"
441 <img src="%simg/dossier-apercu.png" />
443 (reverse('dossier_apercu', args
=(d
.id,)),
447 _apercu
.allow_tags
= True
448 _apercu
.short_description
= u
""
452 _nom
.allow_tags
= True
453 _nom
.short_description
= u
"Dossier"
455 def _employe(self
, obj
):
456 employe
= obj
.employe
457 view_link
= reverse('employe_apercu', args
=(employe
.id,))
458 edit_link
= reverse('admin:rh_employe_change', args
=(employe
.id,))
460 view
= u
"""<a href="%s"
461 title="Aperçu l'employé"
462 onclick="return showAddAnotherPopup(this);">
463 <img src="%simg/employe-apercu.png" />
464 </a>""" % (view_link
, settings
.STATIC_URL
,)
465 return u
"""%s<a href='%s' style="%s;">%s</a>""" % \
466 (view
, edit_link
, style
, employe
)
467 _employe
.allow_tags
= True
468 _employe
.short_description
= u
"Employé"
469 _employe
.admin_order_field
= "employe__nom"
471 def _poste(self
, dossier
):
472 link
= u
"""<a title="Aperçu du poste"
473 onclick="return showAddAnotherPopup(this);"
474 href='%s'><img src="%simg/poste-apercu.png" />
476 <a href="%s" title="Modifier le poste">%s [%d]</a>""" % \
477 (reverse('poste_apercu', args
=(dossier
.poste
.id,)),
479 reverse('admin:rh_poste_change', args
=(dossier
.poste
.id,)),
484 _poste
.allow_tags
= True
485 _poste
.short_description
= u
'Poste'
486 _poste
.admin_order_field
= 'poste__nom'
488 def _region(self
, obj
):
489 return obj
.poste
.implantation
.region
.code
490 _region
.short_description
= u
"Région"
491 _region
.admin_order_field
= 'poste__implantation__region__code'
493 def _implantation(self
, obj
):
494 return obj
.poste
.implantation
.nom
495 _implantation
.short_description
= u
"Implantation"
496 _implantation
.admin_order_field
= 'poste__implantation__nom'
498 def _date_debut(self
, obj
):
499 return date(obj
.date_debut
)
501 _date_debut
.short_description
= u
'Début'
502 _date_debut
.admin_order_field
= 'date_debut'
504 def _date_fin(self
, obj
):
505 return date(obj
.date_fin
)
506 _date_fin
.short_description
= u
'Fin'
507 _date_fin
.admin_order_field
= 'date_fin'
509 def _date_modification(self
, obj
):
510 return date(obj
.date_modification
) \
511 if obj
.date_modification
is not None else "(aucune)"
512 _date_modification
.short_description
= u
'date modification'
513 _date_modification
.admin_order_field
= 'date_modification'
517 dossiers_dae
= d
.dossiers_dae
.all()
518 if len(dossiers_dae
) > 0:
519 dossier_dae
= dossiers_dae
[0]
520 apercu_link
= u
"""<a title="Aperçu du dossier"
521 onclick="return showAddAnotherPopup(this);"
523 <img src="%simg/loupe.png" />
525 (reverse('embauche_consulter', args
=(dossier_dae
.id,)),
529 _dae
.allow_tags
= True
530 _dae
.short_description
= u
"DAE"
532 def save_formset(self
, request
, form
, formset
, change
):
533 instances
= formset
.save(commit
=False)
534 for instance
in instances
:
535 if instance
.__class__
== rh
.DossierCommentaire
:
536 instance
.owner
= request
.user
537 instance
.date_creation
= datetime
.datetime
.now()
541 class EmployeAdminBase(DateRangeMixin
, ProtectRegionMixin
,
542 DerniereModificationAdmin
, BaseAdmin
):
543 prefixe_recherche_temporelle
= "rh_dossiers__"
544 alphabet_filter
= 'nom'
545 DEFAULT_ALPHABET
= u
'ABCDEFGHIJKLMNOPQRSTUVWXYZ'
547 'id', 'nom', 'prenom', 'nom_affichage',
548 'rh_dossiers__poste__nom',
549 'rh_dossiers__poste__nom_feminin'
552 form
= EmployeAdminForm
554 '_id', '_apercu', '_nom', '_dossiers_postes',
558 'derniere_modification'
560 list_display_links
= ('_nom',)
562 'rh_dossiers__poste__implantation__region',
563 'rh_dossiers__poste__implantation', 'nb_postes'
566 AyantDroitInline
, DossierROInline
, EmployePieceInline
,
567 EmployeCommentaireInline
573 ('nom_affichage', 'genre'),
578 ('Informations personnelles', {
579 'fields': ('situation_famille', 'date_entree', )
581 ('Coordonnées personnelles', {
583 ('tel_domicile', 'tel_cellulaire'),
584 ('adresse', 'ville'),
585 ('code_postal', 'province'),
594 _id
.short_description
= u
"#"
595 _id
.admin_order_field
= "id"
597 def _apercu(self
, obj
):
598 return u
"""<a title="Aperçu de l'employé"
599 onclick="return showAddAnotherPopup(this);"
601 <img src="%simg/employe-apercu.png" />
603 (reverse('employe_apercu', args
=(obj
.id,)), settings
.STATIC_URL
)
604 _apercu
.allow_tags
= True
605 _apercu
.short_description
= u
""
608 edit_link
= reverse('admin:rh_employe_change', args
=(obj
.id,))
609 return u
"""<a href='%s'><strong>%s</strong></a>""" % \
610 (edit_link
, "%s %s" % (obj
.nom
.upper(), obj
.prenom
))
611 _nom
.allow_tags
= True
612 _nom
.short_description
= u
"Employé"
613 _nom
.admin_order_field
= "nom"
615 def _region(self
, obj
):
617 d
= rh
.Dossier
.objects
.filter(employe
=obj
.id, principal
=True)[0]
618 region
= d
.poste
.implantation
.region
.code
622 _region
.short_description
= u
"Région"
624 def _implantation(self
, obj
):
626 d
= rh
.Dossier
.objects
.filter(employe
=obj
.id, principal
=True)[0]
627 implantation
= d
.poste
.implantation
.nom
631 _implantation
.short_description
= u
"Implantation"
633 def _dossiers_postes(self
, obj
):
635 for d
in obj
.rh_dossiers
.all().order_by('-date_debut'):
638 if d
.date_fin
is not None and d
.date_fin
< datetime
.date
.today():
639 link_style
= u
' style="color:#666;"'
640 list_style
= u
' style="color:grey;"'
642 dossier
= u
"""<a title="Aperçu du dossier"
644 onclick="return showAddAnotherPopup(this);"
645 title="Aperçu du dossier">
646 <img src="%simg/dossier-apercu.png" />
648 <a href="%s"%s>Dossier</a>
650 (reverse('dossier_apercu', args
=(d
.id,)),
652 reverse('admin:rh_dossier_change', args
=(d
.id,)),
655 poste
= u
"""<a title="Aperçu du poste"
657 onclick="return showAddAnotherPopup(this);"
658 title="Aperçu du poste">
659 <img src="%simg/poste-apercu.png" />
661 <a href="%s"%s>%s [%d]</a>
663 (reverse('poste_apercu', args
=(d
.poste
.id,)),
665 reverse('admin:rh_poste_change', args
=(d
.poste
.id,)),
670 link
= u
"""<li%s>%s %s</li>""" % \
671 (list_style
, dossier
, poste
)
674 return "<ul>%s</ul>" % "\n".join(l
)
675 _dossiers_postes
.allow_tags
= True
676 _dossiers_postes
.short_description
= u
"Dossiers et postes"
678 def _date_modification(self
, obj
):
679 return date(obj
.date_modification
) \
680 if obj
.date_modification
is not None else "(aucune)"
681 _date_modification
.short_description
= u
'date modification'
682 _date_modification
.admin_order_field
= 'date_modification'
684 def queryset(self
, request
):
685 qs
= super(EmployeAdminBase
, self
).queryset(request
)
686 return qs
.select_related(depth
=1).order_by('nom')
688 def save_formset(self
, request
, form
, formset
, change
):
689 instances
= formset
.save(commit
=False)
690 for instance
in instances
:
691 if instance
.__class__
== rh
.EmployeCommentaire
:
692 instance
.owner
= request
.user
693 instance
.date_creation
= datetime
.datetime
.now()
697 class EmployeAdmin(reversion
.VersionAdmin
, EmployeAdminBase
):
698 ignore_duplicate_revisions
= True
701 class EmployeProxyAdmin(EmployeAdminBase
):
702 list_display
= ('_id', '_apercu', '_nom', '_organigramme')
706 def __init__(self
, *args
, **kwargs
):
707 super(EmployeProxyAdmin
, self
).__init__(*args
, **kwargs
)
708 self
.list_display_links
= (None, )
710 def has_add_permission(self
, obj
):
713 def _organigramme(self
, obj
):
715 for d
in rh
.Dossier
.objects
.filter(
716 Q(date_fin__gt
=datetime
.date
.today()) |
Q(date_fin
=None),
717 Q(date_debut__lt
=datetime
.date
.today()) |
Q(date_debut
=None),
721 u
'Organigramme, niveau: ' \
722 u
'<input type="text" id="level_%s" ' \
723 u
'style="width:30px;height:15px;" /> ' \
724 u
'<input type="button" value="Générer" ' \
725 u
"""onclick="window.location='%s' + """ \
726 u
"""document.getElementById('level_%s').value" />""" % (
728 reverse('rho_employe_sans_niveau', args
=(d
.poste
.id,)),
731 link
= u
"""<li>%s [%s]:<br />%s</li>""" % (
737 return "<ul>%s</ul>" % "\n".join(l
)
739 _organigramme
.allow_tags
= True
740 _organigramme
.short_description
= "Organigramme"
743 class CategorieEmploiAdmin(reversion
.VersionAdmin
,
744 DerniereModificationAdmin
, BaseAdmin
):
745 ignore_duplicate_revisions
= True
746 list_display
= ('nom', 'derniere_modification')
747 inlines
= (TypePosteInline
,)
749 (None, {'fields': ('nom', )}),
753 class OrganismeBstgAdmin(reversion
.VersionAdmin
, DerniereModificationAdmin
,
755 ignore_duplicate_revisions
= True
756 search_fields
= ('nom',)
757 list_display
= ('nom', 'type', 'pays', 'derniere_modification')
758 list_filter
= ('type', )
759 inlines
= (DossierROInline
,)
761 (None, {'fields': ('nom', 'type', 'pays',)}),
765 class PosteAdmin(DateRangeMixin
, ProtectRegionMixin
, reversion
.VersionAdmin
,
766 AjaxSelect
, DerniereModificationAdmin
, BaseAdmin
):
767 ignore_duplicate_revisions
= True
768 form
= make_ajax_form(rh
.Poste
, {
769 'implantation': 'implantations',
770 'type_poste': 'typepostes',
771 'responsable': 'postes',
772 'valeur_point_min': 'valeurpoints',
773 'valeur_point_max': 'valeurpoints',
775 alphabet_filter
= 'nom'
780 'implantation__region__code',
781 'implantation__region__nom',
782 'rh_dossiers__employe__id',
783 'rh_dossiers__employe__nom',
784 'rh_dossiers__employe__prenom',
787 '_id', '_apercu', '_nom', '_occupe_par', 'implantation', '_service',
788 '_responsable', 'date_debut', 'date_fin', 'derniere_modification',
792 'implantation__region',
796 'type_poste__categorie_emploi',
797 'type_poste__famille_professionnelle',
800 list_display_links
= ('_nom',)
803 ('nom', 'nom_feminin'),
813 'regime_travail_nb_heure_semaine'),
817 'fields': (('local', 'expatrie', 'mise_a_disposition', 'appel'),)}
820 'fields': (('classement_min',
833 ('Comparatifs de rémunération', {
834 'fields': ('devise_comparaison',
835 ('comp_locale_min', 'comp_locale_max'),
836 ('comp_universite_min', 'comp_universite_max'),
837 ('comp_fonctionpub_min', 'comp_fonctionpub_max'),
838 ('comp_ong_min', 'comp_ong_max'),
839 ('comp_autre_min', 'comp_autre_max'))}
842 'fields': ('justification',)}
844 ('Autres Méta-données', {
845 'fields': ('date_debut', 'date_fin')}
849 inlines
= (PosteFinancementInline
,
852 PosteComparaisonInline
,
853 PosteCommentaireInline
, )
855 def lookup_allowed(self
, key
, value
):
857 'date_debut__gte', 'date_debut__isnull', 'date_fin__lte',
858 'date_fin__isnull', 'implantation__region__id__exact',
859 'implantation__id__exact', 'type_poste__id__exact',
860 'type_poste__categorie_emploi__id__exact', 'service__id__exact',
861 'service__isnull', 'vacant__exact', 'vacant__isnull',
862 ) or super(PosteAdmin
, self
).lookup_allowed(key
, value
)
866 _id
.short_description
= '#'
867 _id
.admin_order_field
= 'id'
869 def _apercu(self
, poste
):
870 view_link
= u
"""<a onclick="return showAddAnotherPopup(this);"
871 title="Aperçu du poste"
873 <img src="%simg/poste-apercu.png" />
875 (reverse('poste_apercu', args
=(poste
.id,)),
876 settings
.STATIC_URL
,)
878 _apercu
.allow_tags
= True
879 _apercu
.short_description
= ''
881 def _nom(self
, poste
):
882 return """<a href="%s">%s</a>""" % \
883 (reverse('admin:rh_poste_change', args
=(poste
.id,)),
885 _nom
.allow_tags
= True
886 _nom
.short_description
= u
'Poste'
887 _nom
.admin_order_field
= 'nom'
889 def _occupe_par(self
, obj
):
890 """Formatte la méthode Poste.occupe_par() pour l'admin"""
892 if obj
.date_fin
is not None and obj
.date_fin
< datetime
.date
.today():
894 employes
= obj
.occupe_par()
898 link
= u
"""<a href='%s'
899 title='Aperçu de l\'employé'
900 onclick='return showAddAnotherPopup(this)'>
901 <img src='%simg/employe-apercu.png' />
903 <a href='%s'>%s</a>""" % \
904 (reverse('employe_apercu', args
=(e
.id,)),
906 reverse('admin:rh_employe_change', args
=(e
.id,)),
909 output
= "\n<br />".join(l
)
911 _occupe_par
.allow_tags
= True
912 _occupe_par
.short_description
= "Occupé par"
914 def _region(self
, poste
):
915 return poste
.implantation
.region
.code
916 _region
.short_description
= 'Région'
917 _region
.admin_order_field
= 'implantation__region__code'
919 def _implantation(self
, poste
):
920 return poste
.implantation
.nom
921 _implantation
.short_description
= 'Implantation'
922 _implantation
.admin_order_field
= 'implantation'
924 def _service(self
, obj
):
926 _service
.short_description
= 'Service'
927 _service
.allow_tags
= True
929 def _responsable(self
, obj
):
931 responsable
= u
"""<a href="%s"
932 onclick="return showAddAnotherPopup(this)">
933 <img src="%simg/poste-apercu.png"
934 title="Aperçu du poste" />
936 <a href="%s">%s [%d]</a>
938 (reverse('poste_apercu', args
=(obj
.responsable
.id,)),
940 reverse('admin:rh_poste_change', args
=(obj
.responsable
.id,)),
947 dossier
= obj
.responsable
.rh_dossiers
.all() \
948 .order_by('-date_debut')[0]
949 employe_id
= dossier
.employe
.id
950 employe_html
= u
"""<br />
952 onclick="return showAddAnotherPopup(this)">
953 <img src="%simg/employe-apercu.png"
954 title="Aperçu de l'employé">
956 <a href="%s">%s</a>""" % \
957 (reverse('employe_apercu', args
=(employe_id
,)),
959 reverse('admin:rh_employe_change', args
=(employe_id
,)),
964 return "%s %s" % (responsable
, employe_html
)
965 _responsable
.short_description
= 'Responsable'
966 _responsable
.allow_tags
= True
968 def _date_debut(self
, obj
):
969 return date_format(obj
.date_debut
)
970 _date_debut
.short_description
= u
'Début'
971 _date_debut
.admin_order_field
= 'date_debut'
973 def _date_fin(self
, obj
):
974 return date_format(obj
.date_fin
)
975 _date_fin
.short_description
= u
'Fin'
976 _date_fin
.admin_order_field
= 'date_fin'
978 def _dae(self
, poste
):
980 postes_dae
= poste
.postes_dae
.all()
981 if len(postes_dae
) > 0:
982 poste_dae
= postes_dae
[0]
984 u
'<a title="Aperçu du dossier" href="%s" ' \
985 u
'onclick="return showAddAnotherPopup(this);">' \
986 u
'<img src="%simg/loupe.png" /></a>' % (reverse(
987 'poste_consulter', args
=("dae-%s" % poste_dae
.id,)
988 ), settings
.STATIC_URL
)
990 _dae
.allow_tags
= True
991 _dae
.short_description
= u
"DAE"
993 def save_formset(self
, request
, form
, formset
, change
):
994 instances
= formset
.save(commit
=False)
995 for instance
in instances
:
996 if instance
.__class__
== rh
.PosteCommentaire
:
997 instance
.owner
= request
.user
998 instance
.date_creation
= datetime
.datetime
.now()
1003 class ResponsableInline(admin
.TabularInline
):
1004 model
= rh
.ResponsableImplantation
1006 fk_name
= "implantation"
1007 form
= ResponsableInlineForm
1010 class ResponsableImplantationAdmin(BaseAdmin
):
1013 inlines
= (ResponsableInline
, )
1014 list_filter
= ('region', 'statut', )
1015 list_display
= ('_region', '_nom', 'statut', '_responsable', )
1016 list_display_links
= ('_nom',)
1018 readonly_fields
= ('nom', )
1021 'responsable__employe__id',
1022 'responsable__employe__nom',
1023 'responsable__employe__prenom',
1027 def _region(self
, obj
):
1028 return obj
.region
.code
1029 _region
.short_description
= u
"Région"
1030 _region
.admin_order_field
= 'region__code'
1032 def _nom(self
, obj
):
1034 _nom
.short_description
= u
"Implantation"
1035 _nom
.admin_order_field
= 'nom'
1037 def _responsable(self
, obj
):
1039 employe
= obj
.responsable
.employe
1040 dossiers
= employe
.dossiers_encours()
1041 if len(dossiers
) == 0:
1042 return u
"<span style='color: red;'>%s %s </span>" % (
1043 employe
, u
"sans dossier actif")
1047 if obj
.statut
in (1, 2): # ouverte, ouverture imminente
1048 css
= "style='color: red;'"
1051 return u
"<span %s>Pas de responsable</span>" % css
1052 _responsable
.allow_tags
= True
1053 _responsable
.short_description
= u
"Responsable"
1054 _responsable
.admin_order_field
= 'responsable__employe__nom'
1056 def has_add_permission(self
, request
=None):
1059 def has_change_permission(self
, request
, obj
=None):
1060 return in_drh_or_admin(request
.user
)
1062 def has_delete_permission(self
, request
, obj
=None):
1066 class ServiceAdminBase(ArchivableAdmin
, DerniereModificationAdmin
, BaseAdmin
):
1067 list_display
= ('nom', '_archive', 'derniere_modification')
1068 list_filter
= ('archive', )
1070 (None, {'fields': ('nom', 'archive')}),
1074 class ServiceAdmin(reversion
.VersionAdmin
, ServiceAdminBase
):
1075 ignore_duplicate_revisions
= True
1078 class ServiceProxyAdmin(ServiceAdminBase
):
1079 list_display
= ('nom', '_organigramme', '_archive', )
1082 def __init__(self
, *args
, **kwargs
):
1083 super(ServiceProxyAdmin
, self
).__init__(*args
, **kwargs
)
1084 self
.list_display_links
= (None, )
1086 def queryset(self
, request
):
1087 return super(ServiceProxyAdmin
, self
).queryset(request
) \
1088 .annotate(num_postes
=Count('rh_postes')) \
1089 .filter(num_postes__gt
=0)
1091 def has_add_permission(self
, obj
):
1094 def has_change_permission(self
, request
, obj
=None):
1095 return in_drh_or_admin(request
.user
)
1097 def _organigramme(self
, obj
):
1098 return """<a href="%s"><strong>Organigramme</strong></a>""" % \
1099 (reverse('rho_service', args
=(obj
.id,)))
1100 _organigramme
.allow_tags
= True
1101 _organigramme
.short_description
= "Organigramme"
1104 class StatutAdmin(reversion
.VersionAdmin
, DerniereModificationAdmin
,
1106 ignore_duplicate_revisions
= True
1107 list_display
= ('code', 'nom', 'derniere_modification')
1110 'fields': ('code', 'nom', ),
1115 class TauxChangeAdmin(reversion
.VersionAdmin
, DerniereModificationAdmin
,
1117 ignore_duplicate_revisions
= True
1118 list_display
= ('taux', 'devise', 'annee', 'derniere_modification')
1119 list_filter
= ('devise',)
1122 'fields': ('taux', 'devise', 'annee', ),
1127 class TypeContratAdmin(reversion
.VersionAdmin
, DerniereModificationAdmin
,
1129 ignore_duplicate_revisions
= True
1130 list_display
= ('nom', 'nom_long', 'derniere_modification')
1133 'fields': ('nom', 'nom_long', ),
1138 class TypePosteAdmin(reversion
.VersionAdmin
, DerniereModificationAdmin
,
1140 ignore_duplicate_revisions
= True
1141 search_fields
= ('nom', 'nom_feminin', )
1142 list_display
= ('nom', 'categorie_emploi', 'derniere_modification')
1143 list_filter
= ('categorie_emploi', 'famille_professionnelle')
1147 'nom', 'nom_feminin', 'is_responsable', 'categorie_emploi',
1148 'famille_professionnelle',
1154 class TypeRemunerationAdmin(reversion
.VersionAdmin
, ArchivableAdmin
,
1155 DerniereModificationAdmin
, BaseAdmin
):
1156 ignore_duplicate_revisions
= True
1158 'nom', 'type_paiement', 'nature_remuneration', '_archive',
1159 'derniere_modification'
1161 list_filter
= ('archive', )
1165 'nom', 'type_paiement', 'nature_remuneration', 'archive'
1171 class TypeRevalorisationAdmin(reversion
.VersionAdmin
,
1172 DerniereModificationAdmin
, BaseAdmin
):
1173 ignore_duplicate_revisions
= True
1174 list_display
= ('nom', 'derniere_modification')
1176 (None, {'fields': ('nom',)}),
1180 class ValeurPointAdmin(reversion
.VersionAdmin
, DerniereModificationAdmin
,
1182 ignore_duplicate_revisions
= True
1184 '_devise_code', '_devise_nom', 'annee', 'implantation',
1185 'valeur', 'derniere_modification'
1187 list_filter
= ('annee', 'devise', 'implantation__region', )
1189 (None, {'fields': ('valeur', 'devise', 'implantation', 'annee')}),
1192 def _devise_code(self
, obj
):
1193 return obj
.devise
.code
1194 _devise_code
.short_description
= "Code de la devise"
1196 def _devise_nom(self
, obj
):
1197 return obj
.devise
.nom
1198 _devise_nom
.short_description
= "Nom de la devise"
1201 class ImplantationProxyAdmin(BaseAdmin
):
1202 list_display
= ('nom', '_organigramme')
1205 def __init__(self
, *args
, **kwargs
):
1206 super(ImplantationProxyAdmin
, self
).__init__(*args
, **kwargs
)
1207 self
.list_display_links
= (None, )
1209 def has_add_permission(self
, obj
):
1212 def has_change_permission(self
, request
, obj
=None):
1213 return in_drh_or_admin(request
.user
)
1215 def _organigramme(self
, obj
):
1216 return '<a href="%s"><strong>Organigramme</strong></a>' % (
1217 reverse('rho_implantation', args
=(obj
.id,))
1219 _organigramme
.allow_tags
= True
1220 _organigramme
.short_description
= "Organigramme"
1223 class RegionProxyAdmin(BaseAdmin
):
1224 list_display
= ('nom', '_organigramme')
1227 def __init__(self
, *args
, **kwargs
):
1228 super(RegionProxyAdmin
, self
).__init__(*args
, **kwargs
)
1229 self
.list_display_links
= (None, )
1231 def has_add_permission(self
, obj
):
1234 def has_change_permission(self
, request
, obj
=None):
1235 return in_drh_or_admin(request
.user
)
1237 def _organigramme(self
, obj
):
1238 return """<a href="%s"><strong>Organigramme</strong></a>""" % (
1239 reverse('rho_region', args
=(obj
.id,))
1241 _organigramme
.allow_tags
= True
1242 _organigramme
.short_description
= "Organigramme"
1245 admin
.site
.register(rh
.Classement
, ClassementAdmin
)
1246 admin
.site
.register(rh
.Devise
, DeviseAdmin
)
1247 admin
.site
.register(rh
.Dossier
, DossierAdmin
)
1248 admin
.site
.register(EmployeProxy
, EmployeProxyAdmin
)
1249 admin
.site
.register(ServiceProxy
, ServiceProxyAdmin
)
1250 admin
.site
.register(rh
.Employe
, EmployeAdmin
)
1251 admin
.site
.register(rh
.CategorieEmploi
, CategorieEmploiAdmin
)
1252 admin
.site
.register(rh
.FamilleProfessionnelle
)
1253 admin
.site
.register(rh
.OrganismeBstg
, OrganismeBstgAdmin
)
1254 admin
.site
.register(rh
.Poste
, PosteAdmin
)
1255 admin
.site
.register(
1256 rh
.ResponsableImplantationProxy
, ResponsableImplantationAdmin
1258 admin
.site
.register(rh
.Service
, ServiceAdmin
)
1259 admin
.site
.register(rh
.Statut
, StatutAdmin
)
1260 admin
.site
.register(rh
.TauxChange
, TauxChangeAdmin
)
1261 admin
.site
.register(rh
.TypeContrat
, TypeContratAdmin
)
1262 admin
.site
.register(rh
.TypePoste
, TypePosteAdmin
)
1263 admin
.site
.register(rh
.TypeRemuneration
, TypeRemunerationAdmin
)
1264 admin
.site
.register(rh
.TypeRevalorisation
, TypeRevalorisationAdmin
)
1265 admin
.site
.register(rh
.ValeurPoint
, ValeurPointAdmin
)
1266 admin
.site
.register(ImplantationProxy
, ImplantationProxyAdmin
)
1267 admin
.site
.register(RegionProxy
, RegionProxyAdmin
)