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
, \
22 user_can_change_obj
, \
25 from project
.rh
.forms
import ContratForm
, AyantDroitForm
, EmployeAdminForm
, \
26 AjaxSelect
, DossierForm
, ResponsableInlineForm
27 from project
.rh
.change_list
import ChangeList
30 class BaseAdmin(admin
.ModelAdmin
):
34 'css/admin_custom.css',
35 'jquery-autocomplete/jquery.autocomplete.css',
38 'https://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js',
39 'jquery-autocomplete/jquery.autocomplete.min.js',
42 # Admin pour reversion
44 class ArchivableAdmin(admin
.ModelAdmin
):
46 Admin pour les modèles archivables
48 list_filter
= ('archive', )
50 def queryset(self
, request
):
51 return self
.model
.avec_archives
.all()
53 def _archive(self
, obj
):
58 _archive
.short_description
= u
'Archivé'
59 _archive
.admin_order_field
= 'archive'
62 class RegionProxy(ref
.Region
):
63 """ Proxy utilisé pour les organigrammes par région """
67 verbose_name
= u
"Organigramme par région"
68 verbose_name_plural
= u
"Organigramme par région"
71 class ImplantationProxy(ref
.Implantation
):
72 """ Proxy utilisé pour les organigrammes par implantation """
76 verbose_name
= u
"Organigramme par implantations"
77 verbose_name_plural
= u
"Organigramme par implantations"
80 class ServiceProxy(rh
.Service
):
81 """ Proxy utilisé pour les organigrammes par service """
86 verbose_name
= u
"Organigramme par services"
87 verbose_name_plural
= u
"Organigramme par services"
90 class EmployeProxy(rh
.Employe
):
91 """ Proxy utilisé pour les organigrammes des employés """
95 verbose_name
= u
"Organigramme des employés"
96 verbose_name_plural
= u
"Organigramme des employés"
99 class DateRangeMixin(object):
100 prefixe_recherche_temporelle
= ""
102 def get_changelist(self
, request
, **kwargs
):
103 if 'HTTP_REFERER' in request
.META
.keys():
104 referer
= request
.META
['HTTP_REFERER']
105 referer
= "/".join(referer
.split('/')[3:])
106 referer
= "/%s" % referer
.split('?')[0]
107 change_list_view
= 'admin:%s_%s_changelist' % (
108 self
.model
._meta
.app_label
,
109 self
.model
.__name__
.lower(),)
110 if referer
!= reverse(change_list_view
):
111 params
= request
.GET
.copy()
112 params
.update({'statut': 'Actif'})
117 # Override of the InlineModelAdmin to support the link in the tabular inline
118 class LinkedInline(admin
.options
.InlineModelAdmin
):
119 template
= "admin/linked.html"
120 admin_model_path
= None
122 def __init__(self
, *args
):
123 super(LinkedInline
, self
).__init__(*args
)
124 if self
.admin_model_path
is None:
125 self
.admin_model_path
= self
.model
.__name__
.lower()
128 class ProtectRegionMixin(object):
130 def queryset(self
, request
):
131 qs
= super(ProtectRegionMixin
, self
).queryset(request
)
133 if in_drh_or_admin(request
.user
):
136 #if user_gere_obj_de_sa_region(request.user):
137 # region_user = get_region_user(request.user)
138 # q = Q(**{self.model.prefix_implantation: \
140 # qs = qs.filter(q).distinct()
144 def has_add_permission(self
, request
):
145 return in_drh_or_admin(request
.user
)
146 #return user_can_add_obj(request.user)
148 def has_change_permission(self
, request
, obj
=None):
149 return in_drh_or_admin(request
.user
)
150 #return user_can_change_obj(request.user, obj) if obj else True
152 def has_delete_permission(self
, request
, obj
=None):
153 return in_drh_or_admin(request
.user
)
154 #return user_can_delete_obj(request.user, obj) if obj else True
157 class DerniereModificationAdmin(admin
.ModelAdmin
):
159 def queryset(self
, request
):
160 qs
= super(DerniereModificationAdmin
, self
).queryset(request
)
161 ct
= ContentType
.objects
.get_for_model(self
.model
)
162 db_table
= self
.model
._meta
.db_table
163 pk
= self
.model
._meta
.pk
.column
164 return qs
.extra(select
={
166 "SELECT action_time FROM django_admin_log "
167 "WHERE content_type_id = %d AND object_id = %s.%s "
168 "ORDER BY action_time DESC "
169 "LIMIT 1" % (ct
.id, db_table
, pk
),
173 "INNER JOIN django_admin_log l ON l.user_id = u.id "
174 "WHERE l.content_type_id = %d AND object_id = %s.%s "
175 "ORDER BY action_time DESC "
176 "LIMIT 1" % (ct
.id, db_table
, pk
),
179 def derniere_modification(self
, obj
):
181 if obj
.date_modification
:
182 text
+= obj
.date_modification
.strftime('%d-%m-%Y %H:%M')
183 if obj
.user_modification
:
184 text
+= ' par ' + obj
.user_modification
186 derniere_modification
.short_description
= u
'dernière modification'
187 derniere_modification
.admin_order_field
= 'date_modification'
192 class CommentaireInlineForm(forms
.ModelForm
):
194 def save(self
, commit
=True):
196 # Hack: reversion.VersionAdmin ne sauvegarde pas les champs qui ne
197 # sont pas explicitement dans le formulaire. Il plante cependant
198 # leur valeur dans `self.initial`. Ceci est un peu fragile. Si
199 # c'est possible, il serait plus approprié que Reversion se rende
200 # compte qu'il manque des champs.
201 instance
= super(CommentaireInlineForm
, self
).save(commit
=False)
202 if instance
.owner_id
is None and 'owner' in self
.initial
:
203 instance
.owner_id
= self
.initial
['owner']
204 if instance
.date_creation
is None and 'date_creation' in self
.initial
:
205 instance
.date_creation
= self
.initial
['date_creation']
212 class ReadOnlyInlineMixin(object):
214 def get_readonly_fields(self
, request
, obj
=None):
215 return [f
.name
for f
in self
.model
._meta
.fields
]
218 class AyantDroitInline(admin
.StackedInline
):
219 model
= rh
.AyantDroit
220 form
= AyantDroitForm
227 ('nom_affichage', 'genre'),
235 class AyantDroitCommentaireInline(admin
.TabularInline
):
236 readonly_fields
= ('owner',)
237 model
= rh
.AyantDroitCommentaire
239 form
= CommentaireInlineForm
242 class ContratInline(admin
.TabularInline
):
248 class DossierROInline(ReadOnlyInlineMixin
, LinkedInline
):
249 template
= "admin/rh/dossier/linked.html"
254 def has_add_permission(self
, request
=None):
257 def has_change_permission(self
, request
, obj
=None):
260 def has_delete_permission(self
, request
, obj
=None):
264 class DossierCommentaireInline(admin
.TabularInline
):
265 readonly_fields
= ('owner',)
266 model
= rh
.DossierCommentaire
268 form
= CommentaireInlineForm
271 class DossierPieceInline(admin
.TabularInline
):
272 model
= rh
.DossierPiece
276 class EmployeInline(admin
.TabularInline
):
280 class EmployeCommentaireInline(admin
.TabularInline
):
281 readonly_fields
= ('owner',)
282 model
= rh
.EmployeCommentaire
284 form
= CommentaireInlineForm
287 class EmployePieceInline(admin
.TabularInline
):
288 model
= rh
.EmployePiece
292 class PosteCommentaireInline(admin
.TabularInline
):
293 readonly_fields
= ('owner',)
294 model
= rh
.PosteCommentaire
296 form
= CommentaireInlineForm
299 class PosteFinancementInline(admin
.TabularInline
):
300 model
= rh
.PosteFinancement
303 class PostePieceInline(admin
.TabularInline
):
304 model
= rh
.PostePiece
307 class RemunerationInline(admin
.TabularInline
):
308 model
= rh
.Remuneration
312 class RemunerationROInline(ReadOnlyInlineMixin
, RemunerationInline
):
316 class TypePosteInline(admin
.TabularInline
):
320 class PosteComparaisonInline(admin
.TabularInline
):
321 model
= rh
.PosteComparaison
324 class ClassementAdmin(reversion
.VersionAdmin
, DerniereModificationAdmin
,
326 ignore_duplicate_revisions
= True
327 list_display
= ('_classement', 'derniere_modification')
329 (None, {'fields': ('type', 'echelon', 'degre', 'coefficient',)}),
332 def _classement(self
, obj
):
334 _classement
.short_description
= u
"Classement"
337 class DeviseAdmin(reversion
.VersionAdmin
, ArchivableAdmin
,
338 DerniereModificationAdmin
, BaseAdmin
):
339 ignore_duplicate_revisions
= True
341 'code', 'nom', '_archive', 'derniere_modification',
343 list_filter
= ('archive', )
345 (None, {'fields': ('code', 'nom', 'archive', )}),
349 class DossierAdmin(DateRangeMixin
, ProtectRegionMixin
, reversion
.VersionAdmin
,
350 AjaxSelect
, DerniereModificationAdmin
, BaseAdmin
):
351 change_list_template
= "admin/rh/dossier/change_list.html"
352 ignore_duplicate_revisions
= True
353 alphabet_filter
= 'employe__nom'
361 'poste__nom_feminin',
362 'poste__implantation__nom',
374 'derniere_modification',
377 list_display_links
= ('_nom',)
379 'poste__implantation__region',
380 'poste__implantation',
381 'poste__type_poste__categorie_emploi',
383 'rh_contrats__type_contrat',
386 inlines
= (DossierPieceInline
, ContratInline
,
388 DossierCommentaireInline
,
397 'organisme_bstg',)}),
402 'remplacement_de', )}),
406 ('regime_travail', 'regime_travail_nb_heure_semaine'),)}),
407 ('Occupation du Poste par cet Employe', {
408 'fields': (('date_debut', 'date_fin'), )}
411 form
= make_ajax_form(rh
.Dossier
, {
412 'employe': 'employes',
414 'remplacement_de': 'dossiers',
415 }, superclass
=DossierForm
)
417 def lookup_allowed(self
, key
, value
):
419 'employe__nom__istartswith',
420 'poste__implantation__region__id__exact',
421 'poste__implantation__id__exact',
422 'poste__type_poste__id__exact',
423 'poste__type_poste__categorie_emploi__id__exact',
424 'rh_contrats__type_contrat__id__exact',
432 _id
.short_description
= u
"#"
433 _id
.admin_order_field
= "id"
435 def _apercu(self
, d
):
436 apercu_link
= u
"""<a title="Aperçu du dossier"
437 onclick="return showAddAnotherPopup(this);"
439 <img src="%simg/dossier-apercu.png" />
441 (reverse('dossier_apercu', args
=(d
.id,)),
445 _apercu
.allow_tags
= True
446 _apercu
.short_description
= u
""
450 _nom
.allow_tags
= True
451 _nom
.short_description
= u
"Dossier"
453 def _employe(self
, obj
):
454 employe
= obj
.employe
455 view_link
= reverse('employe_apercu', args
=(employe
.id,))
456 edit_link
= reverse('admin:rh_employe_change', args
=(employe
.id,))
458 view
= u
"""<a href="%s"
459 title="Aperçu l'employé"
460 onclick="return showAddAnotherPopup(this);">
461 <img src="%simg/employe-apercu.png" />
462 </a>""" % (view_link
, settings
.STATIC_URL
,)
463 return u
"""%s<a href='%s' style="%s;">%s</a>""" % \
464 (view
, edit_link
, style
, employe
)
465 _employe
.allow_tags
= True
466 _employe
.short_description
= u
"Employé"
467 _employe
.admin_order_field
= "employe__nom"
469 def _poste(self
, dossier
):
470 link
= u
"""<a title="Aperçu du poste"
471 onclick="return showAddAnotherPopup(this);"
472 href='%s'><img src="%simg/poste-apercu.png" />
474 <a href="%s" title="Modifier le poste">%s [%d]</a>""" % \
475 (reverse('poste_apercu', args
=(dossier
.poste
.id,)),
477 reverse('admin:rh_poste_change', args
=(dossier
.poste
.id,)),
482 _poste
.allow_tags
= True
483 _poste
.short_description
= u
'Poste'
484 _poste
.admin_order_field
= 'poste__nom'
486 def _region(self
, obj
):
487 return obj
.poste
.implantation
.region
.code
488 _region
.short_description
= u
"Région"
489 _region
.admin_order_field
= 'poste__implantation__region__code'
491 def _implantation(self
, obj
):
492 return obj
.poste
.implantation
.nom
493 _implantation
.short_description
= u
"Implantation"
494 _implantation
.admin_order_field
= 'poste__implantation__nom'
496 def _date_debut(self
, obj
):
497 return date(obj
.date_debut
)
499 _date_debut
.short_description
= u
'Début'
500 _date_debut
.admin_order_field
= 'date_debut'
502 def _date_fin(self
, obj
):
503 return date(obj
.date_fin
)
504 _date_fin
.short_description
= u
'Fin'
505 _date_fin
.admin_order_field
= 'date_fin'
507 def _date_modification(self
, obj
):
508 return date(obj
.date_modification
) \
509 if obj
.date_modification
is not None else "(aucune)"
510 _date_modification
.short_description
= u
'date modification'
511 _date_modification
.admin_order_field
= 'date_modification'
515 dossiers_dae
= d
.dossiers_dae
.all()
516 if len(dossiers_dae
) > 0:
517 dossier_dae
= dossiers_dae
[0]
518 apercu_link
= u
"""<a title="Aperçu du dossier"
519 onclick="return showAddAnotherPopup(this);"
521 <img src="%simg/loupe.png" />
523 (reverse('embauche_consulter', args
=(dossier_dae
.id,)),
527 _dae
.allow_tags
= True
528 _dae
.short_description
= u
"DAE"
530 def save_formset(self
, request
, form
, formset
, change
):
531 instances
= formset
.save(commit
=False)
532 for instance
in instances
:
533 if instance
.__class__
== rh
.DossierCommentaire
:
534 instance
.owner
= request
.user
535 instance
.date_creation
= datetime
.datetime
.now()
539 class EmployeAdminBase(DateRangeMixin
, ProtectRegionMixin
,
540 DerniereModificationAdmin
, BaseAdmin
):
541 prefixe_recherche_temporelle
= "rh_dossiers__"
542 alphabet_filter
= 'nom'
543 DEFAULT_ALPHABET
= u
'ABCDEFGHIJKLMNOPQRSTUVWXYZ'
545 'id', 'nom', 'prenom', 'nom_affichage',
546 'rh_dossiers__poste__nom',
547 'rh_dossiers__poste__nom_feminin'
550 form
= EmployeAdminForm
552 '_id', '_apercu', '_nom', '_dossiers_postes',
556 'derniere_modification'
558 list_display_links
= ('_nom',)
560 'rh_dossiers__poste__implantation__region',
561 'rh_dossiers__poste__implantation', 'nb_postes'
564 AyantDroitInline
, DossierROInline
, EmployePieceInline
,
565 EmployeCommentaireInline
571 ('nom_affichage', 'genre'),
576 ('Informations personnelles', {
577 'fields': ('situation_famille', 'date_entree', )
579 ('Coordonnées personnelles', {
581 ('tel_domicile', 'tel_cellulaire'),
582 ('adresse', 'ville'),
583 ('code_postal', 'province'),
592 _id
.short_description
= u
"#"
593 _id
.admin_order_field
= "id"
595 def _apercu(self
, obj
):
596 return u
"""<a title="Aperçu de l'employé"
597 onclick="return showAddAnotherPopup(this);"
599 <img src="%simg/employe-apercu.png" />
601 (reverse('employe_apercu', args
=(obj
.id,)), settings
.STATIC_URL
)
602 _apercu
.allow_tags
= True
603 _apercu
.short_description
= u
""
606 edit_link
= reverse('admin:rh_employe_change', args
=(obj
.id,))
607 return u
"""<a href='%s'><strong>%s</strong></a>""" % \
608 (edit_link
, "%s %s" % (obj
.nom
.upper(), obj
.prenom
))
609 _nom
.allow_tags
= True
610 _nom
.short_description
= u
"Employé"
611 _nom
.admin_order_field
= "nom"
613 def _region(self
, obj
):
615 d
= rh
.Dossier
.objects
.filter(employe
=obj
.id, principal
=True)[0]
616 region
= d
.poste
.implantation
.region
.code
620 _region
.short_description
= u
"Région"
622 def _implantation(self
, obj
):
624 d
= rh
.Dossier
.objects
.filter(employe
=obj
.id, principal
=True)[0]
625 implantation
= d
.poste
.implantation
.nom
629 _implantation
.short_description
= u
"Implantation"
631 def _dossiers_postes(self
, obj
):
633 for d
in obj
.rh_dossiers
.all().order_by('-date_debut'):
636 if d
.date_fin
is not None and d
.date_fin
< datetime
.date
.today():
637 link_style
= u
' style="color:#666;"'
638 list_style
= u
' style="color:grey;"'
640 dossier
= u
"""<a title="Aperçu du dossier"
642 onclick="return showAddAnotherPopup(this);"
643 title="Aperçu du dossier">
644 <img src="%simg/dossier-apercu.png" />
646 <a href="%s"%s>Dossier</a>
648 (reverse('dossier_apercu', args
=(d
.id,)),
650 reverse('admin:rh_dossier_change', args
=(d
.id,)),
653 poste
= u
"""<a title="Aperçu du poste"
655 onclick="return showAddAnotherPopup(this);"
656 title="Aperçu du poste">
657 <img src="%simg/poste-apercu.png" />
659 <a href="%s"%s>%s [%d]</a>
661 (reverse('poste_apercu', args
=(d
.poste
.id,)),
663 reverse('admin:rh_poste_change', args
=(d
.poste
.id,)),
668 link
= u
"""<li%s>%s %s</li>""" % \
669 (list_style
, dossier
, poste
)
672 return "<ul>%s</ul>" % "\n".join(l
)
673 _dossiers_postes
.allow_tags
= True
674 _dossiers_postes
.short_description
= u
"Dossiers et postes"
676 def _date_modification(self
, obj
):
677 return date(obj
.date_modification
) \
678 if obj
.date_modification
is not None else "(aucune)"
679 _date_modification
.short_description
= u
'date modification'
680 _date_modification
.admin_order_field
= 'date_modification'
682 def queryset(self
, request
):
683 qs
= super(EmployeAdminBase
, self
).queryset(request
)
684 return qs
.select_related(depth
=1).order_by('nom')
686 def save_formset(self
, request
, form
, formset
, change
):
687 instances
= formset
.save(commit
=False)
688 for instance
in instances
:
689 if instance
.__class__
== rh
.EmployeCommentaire
:
690 instance
.owner
= request
.user
691 instance
.date_creation
= datetime
.datetime
.now()
695 class EmployeAdmin(reversion
.VersionAdmin
, EmployeAdminBase
):
696 change_list_template
= "admin/rh/employe/change_list.html"
697 ignore_duplicate_revisions
= True
700 class EmployeProxyAdmin(EmployeAdminBase
):
701 list_display
= ('_id', '_apercu', '_nom', '_organigramme')
705 def __init__(self
, *args
, **kwargs
):
706 super(EmployeProxyAdmin
, self
).__init__(*args
, **kwargs
)
707 self
.list_display_links
= (None, )
709 def queryset(self
, request
):
710 qs
= super(ProtectRegionMixin
, self
).queryset(request
)
712 if in_drh_or_admin(request
.user
) or \
713 user_gere_obj_de_sa_region(request
.user
):
718 def has_add_permission(self
, obj
):
721 def has_change_permission(self
, request
, obj
=None):
722 user_groups
= [g
.name
for g
in request
.user
.groups
.all()]
723 if groups
.CORRESPONDANT_RH
in user_groups
or \
724 groups
.ADMINISTRATEURS
in user_groups
or \
725 groups
.DIRECTEUR_DE_BUREAU
in user_groups
or \
726 in_drh_or_admin(request
.user
):
730 def _organigramme(self
, obj
):
732 for d
in rh
.Dossier
.objects
.filter(
733 Q(date_fin__gt
=datetime
.date
.today()) |
Q(date_fin
=None),
734 Q(date_debut__lt
=datetime
.date
.today()) |
Q(date_debut
=None),
738 u
'Organigramme, niveau: ' \
739 u
'<input type="text" id="level_%s" ' \
740 u
'style="width:30px;height:15px;" /> ' \
741 u
'<input type="button" value="Générer" ' \
742 u
"""onclick="window.location='%s' + """ \
743 u
"""document.getElementById('level_%s').value" />""" % (
745 reverse('rho_employe_sans_niveau', args
=(d
.poste
.id,)),
748 link
= u
"""<li>%s [%s]:<br />%s</li>""" % (
754 return "<ul>%s</ul>" % "\n".join(l
)
756 _organigramme
.allow_tags
= True
757 _organigramme
.short_description
= "Organigramme"
760 class CategorieEmploiAdmin(reversion
.VersionAdmin
,
761 DerniereModificationAdmin
, BaseAdmin
):
762 ignore_duplicate_revisions
= True
763 list_display
= ('nom', 'derniere_modification')
764 inlines
= (TypePosteInline
,)
766 (None, {'fields': ('nom', )}),
770 class OrganismeBstgAdmin(reversion
.VersionAdmin
, DerniereModificationAdmin
,
772 ignore_duplicate_revisions
= True
773 search_fields
= ('nom',)
774 list_display
= ('nom', 'type', 'pays', 'derniere_modification')
775 list_filter
= ('type', )
776 inlines
= (DossierROInline
,)
778 (None, {'fields': ('nom', 'type', 'pays',)}),
782 class PosteAdmin(DateRangeMixin
, ProtectRegionMixin
, reversion
.VersionAdmin
,
783 AjaxSelect
, DerniereModificationAdmin
, BaseAdmin
):
784 change_list_template
= "admin/rh/poste/change_list.html"
785 ignore_duplicate_revisions
= True
786 form
= make_ajax_form(rh
.Poste
, {
787 'implantation': 'implantations',
788 'type_poste': 'typepostes',
789 'responsable': 'postes',
790 'valeur_point_min': 'valeurpoints',
791 'valeur_point_max': 'valeurpoints',
793 alphabet_filter
= 'nom'
798 'implantation__region__code',
799 'implantation__region__nom',
800 'rh_dossiers__employe__id',
801 'rh_dossiers__employe__nom',
802 'rh_dossiers__employe__prenom',
805 '_id', '_apercu', '_nom', '_occupe_par', 'implantation', '_service',
806 '_responsable', 'date_debut', 'date_fin', 'derniere_modification',
810 'implantation__region',
814 'type_poste__categorie_emploi',
815 'type_poste__famille_professionnelle',
818 list_display_links
= ('_nom',)
821 ('nom', 'nom_feminin'),
831 'regime_travail_nb_heure_semaine'),
835 'fields': (('local', 'expatrie', 'mise_a_disposition', 'appel'),)}
838 'fields': (('classement_min',
851 ('Comparatifs de rémunération', {
852 'fields': ('devise_comparaison',
853 ('comp_locale_min', 'comp_locale_max'),
854 ('comp_universite_min', 'comp_universite_max'),
855 ('comp_fonctionpub_min', 'comp_fonctionpub_max'),
856 ('comp_ong_min', 'comp_ong_max'),
857 ('comp_autre_min', 'comp_autre_max'))}
860 'fields': ('justification',)}
862 ('Autres Méta-données', {
863 'fields': ('date_debut', 'date_fin')}
867 inlines
= (PosteFinancementInline
,
870 PosteComparaisonInline
,
871 PosteCommentaireInline
, )
873 def lookup_allowed(self
, key
, value
):
875 'date_debut__gte', 'date_debut__isnull', 'date_fin__lte',
876 'date_fin__isnull', 'implantation__region__id__exact',
877 'implantation__id__exact', 'type_poste__id__exact',
878 'type_poste__categorie_emploi__id__exact', 'service__id__exact',
879 'service__isnull', 'vacant__exact', 'vacant__isnull',
880 ) or super(PosteAdmin
, self
).lookup_allowed(key
, value
)
884 _id
.short_description
= '#'
885 _id
.admin_order_field
= 'id'
887 def _apercu(self
, poste
):
888 view_link
= u
"""<a onclick="return showAddAnotherPopup(this);"
889 title="Aperçu du poste"
891 <img src="%simg/poste-apercu.png" />
893 (reverse('poste_apercu', args
=(poste
.id,)),
894 settings
.STATIC_URL
,)
896 _apercu
.allow_tags
= True
897 _apercu
.short_description
= ''
899 def _nom(self
, poste
):
900 return """<a href="%s">%s</a>""" % \
901 (reverse('admin:rh_poste_change', args
=(poste
.id,)),
903 _nom
.allow_tags
= True
904 _nom
.short_description
= u
'Poste'
905 _nom
.admin_order_field
= 'nom'
907 def _occupe_par(self
, obj
):
908 """Formatte la méthode Poste.occupe_par() pour l'admin"""
910 if obj
.date_fin
is not None and obj
.date_fin
< datetime
.date
.today():
912 employes
= obj
.occupe_par()
916 link
= u
"""<a href='%s'
917 title='Aperçu de l\'employé'
918 onclick='return showAddAnotherPopup(this)'>
919 <img src='%simg/employe-apercu.png' />
921 <a href='%s'>%s</a>""" % \
922 (reverse('employe_apercu', args
=(e
.id,)),
924 reverse('admin:rh_employe_change', args
=(e
.id,)),
927 output
= "\n<br />".join(l
)
929 _occupe_par
.allow_tags
= True
930 _occupe_par
.short_description
= "Occupé par"
932 def _region(self
, poste
):
933 return poste
.implantation
.region
.code
934 _region
.short_description
= 'Région'
935 _region
.admin_order_field
= 'implantation__region__code'
937 def _implantation(self
, poste
):
938 return poste
.implantation
.nom
939 _implantation
.short_description
= 'Implantation'
940 _implantation
.admin_order_field
= 'implantation'
942 def _service(self
, obj
):
944 _service
.short_description
= 'Service'
945 _service
.allow_tags
= True
947 def _responsable(self
, obj
):
949 responsable
= u
"""<a href="%s"
950 onclick="return showAddAnotherPopup(this)">
951 <img src="%simg/poste-apercu.png"
952 title="Aperçu du poste" />
954 <a href="%s">%s [%d]</a>
956 (reverse('poste_apercu', args
=(obj
.responsable
.id,)),
958 reverse('admin:rh_poste_change', args
=(obj
.responsable
.id,)),
965 dossier
= obj
.responsable
.rh_dossiers
.all() \
966 .order_by('-date_debut')[0]
967 employe_id
= dossier
.employe
.id
968 employe_html
= u
"""<br />
970 onclick="return showAddAnotherPopup(this)">
971 <img src="%simg/employe-apercu.png"
972 title="Aperçu de l'employé">
974 <a href="%s">%s</a>""" % \
975 (reverse('employe_apercu', args
=(employe_id
,)),
977 reverse('admin:rh_employe_change', args
=(employe_id
,)),
982 return "%s %s" % (responsable
, employe_html
)
983 _responsable
.short_description
= 'Responsable'
984 _responsable
.allow_tags
= True
986 def _date_debut(self
, obj
):
987 return date_format(obj
.date_debut
)
988 _date_debut
.short_description
= u
'Début'
989 _date_debut
.admin_order_field
= 'date_debut'
991 def _date_fin(self
, obj
):
992 return date_format(obj
.date_fin
)
993 _date_fin
.short_description
= u
'Fin'
994 _date_fin
.admin_order_field
= 'date_fin'
996 def _dae(self
, poste
):
998 postes_dae
= poste
.postes_dae
.all()
999 if len(postes_dae
) > 0:
1000 poste_dae
= postes_dae
[0]
1002 u
'<a title="Aperçu du dossier" href="%s" ' \
1003 u
'onclick="return showAddAnotherPopup(this);">' \
1004 u
'<img src="%simg/loupe.png" /></a>' % (reverse(
1005 'poste_consulter', args
=("dae-%s" % poste_dae
.id,)
1006 ), settings
.STATIC_URL
)
1008 _dae
.allow_tags
= True
1009 _dae
.short_description
= u
"DAE"
1011 def save_formset(self
, request
, form
, formset
, change
):
1012 instances
= formset
.save(commit
=False)
1013 for instance
in instances
:
1014 if instance
.__class__
== rh
.PosteCommentaire
:
1015 instance
.owner
= request
.user
1016 instance
.date_creation
= datetime
.datetime
.now()
1021 class ResponsableInline(admin
.TabularInline
):
1022 model
= rh
.ResponsableImplantation
1024 fk_name
= "implantation"
1025 form
= ResponsableInlineForm
1028 class ResponsableImplantationAdmin(BaseAdmin
):
1031 inlines
= (ResponsableInline
, )
1032 list_filter
= ('region', 'statut', )
1033 list_display
= ('_region', '_nom', 'statut', '_responsable', )
1034 list_display_links
= ('_nom',)
1036 readonly_fields
= ('nom', )
1039 'responsable__employe__id',
1040 'responsable__employe__nom',
1041 'responsable__employe__prenom',
1044 inlines
= (ResponsableInline
, )
1046 def _region(self
, obj
):
1047 return obj
.region
.code
1048 _region
.short_description
= u
"Région"
1049 _region
.admin_order_field
= 'region__code'
1051 def _nom(self
, obj
):
1053 _nom
.short_description
= u
"Implantation"
1054 _nom
.admin_order_field
= 'nom'
1056 def _responsable(self
, obj
):
1058 employe
= obj
.responsable
.employe
1059 dossiers
= employe
.dossiers_encours()
1060 if len(dossiers
) == 0:
1061 return u
"<span style='color: red;'>%s %s </span>" % (
1062 employe
, u
"sans dossier actif")
1066 if obj
.statut
in (1, 2): # ouverte, ouverture imminente
1067 css
= "style='color: red;'"
1070 return u
"<span %s>Pas de responsable</span>" % css
1071 _responsable
.allow_tags
= True
1072 _responsable
.short_description
= u
"Responsable"
1073 _responsable
.admin_order_field
= 'responsable__employe__nom'
1075 def has_add_permission(self
, request
=None):
1078 def has_change_permission(self
, request
, obj
=None):
1079 return in_drh_or_admin(request
.user
)
1081 def has_delete_permission(self
, request
, obj
=None):
1085 class ServiceAdminBase(ArchivableAdmin
, DerniereModificationAdmin
, BaseAdmin
):
1086 list_display
= ('nom', '_archive', 'derniere_modification')
1087 list_filter
= ('archive', )
1089 (None, {'fields': ('nom', 'archive')}),
1093 class ServiceAdmin(reversion
.VersionAdmin
, ServiceAdminBase
):
1094 ignore_duplicate_revisions
= True
1097 class ServiceProxyAdmin(ServiceAdminBase
):
1098 list_display
= ('nom', '_organigramme', '_archive', )
1101 def __init__(self
, *args
, **kwargs
):
1102 super(ServiceProxyAdmin
, self
).__init__(*args
, **kwargs
)
1103 self
.list_display_links
= (None, )
1105 def queryset(self
, request
):
1106 return super(ServiceProxyAdmin
, self
).queryset(request
) \
1107 .annotate(num_postes
=Count('rh_postes')) \
1108 .filter(num_postes__gt
=0)
1110 def has_add_permission(self
, obj
):
1113 def has_change_permission(self
, request
, obj
=None):
1114 user_groups
= [g
.name
for g
in request
.user
.groups
.all()]
1115 if groups
.CORRESPONDANT_RH
in user_groups
or \
1116 groups
.ADMINISTRATEURS
in user_groups
or \
1117 groups
.DIRECTEUR_DE_BUREAU
in user_groups
or \
1118 in_drh_or_admin(request
.user
):
1122 def _organigramme(self
, obj
):
1123 return """<a href="%s"><strong>Organigramme</strong></a>""" % \
1124 (reverse('rho_service', args
=(obj
.id,)))
1125 _organigramme
.allow_tags
= True
1126 _organigramme
.short_description
= "Organigramme"
1129 class StatutAdmin(reversion
.VersionAdmin
, DerniereModificationAdmin
,
1131 ignore_duplicate_revisions
= True
1132 list_display
= ('code', 'nom', 'derniere_modification')
1135 'fields': ('code', 'nom', ),
1140 class TauxChangeAdmin(reversion
.VersionAdmin
, DerniereModificationAdmin
,
1142 ignore_duplicate_revisions
= True
1143 list_display
= ('taux', 'devise', 'annee', 'derniere_modification')
1144 list_filter
= ('devise',)
1147 'fields': ('taux', 'devise', 'annee', ),
1152 class TypeContratAdmin(reversion
.VersionAdmin
, DerniereModificationAdmin
,
1154 ignore_duplicate_revisions
= True
1155 list_display
= ('nom', 'nom_long', 'derniere_modification')
1158 'fields': ('nom', 'nom_long', ),
1163 class TypePosteAdmin(reversion
.VersionAdmin
, DerniereModificationAdmin
,
1165 ignore_duplicate_revisions
= True
1166 search_fields
= ('nom', 'nom_feminin', )
1167 list_display
= ('nom', 'categorie_emploi', 'derniere_modification')
1168 list_filter
= ('categorie_emploi', 'famille_professionnelle')
1172 'nom', 'nom_feminin', 'is_responsable', 'categorie_emploi',
1173 'famille_professionnelle',
1179 class TypeRemunerationAdmin(reversion
.VersionAdmin
, ArchivableAdmin
,
1180 DerniereModificationAdmin
, BaseAdmin
):
1181 ignore_duplicate_revisions
= True
1183 'nom', 'type_paiement', 'nature_remuneration', '_archive',
1184 'derniere_modification'
1186 list_filter
= ('archive', )
1190 'nom', 'type_paiement', 'nature_remuneration', 'archive'
1196 class TypeRevalorisationAdmin(reversion
.VersionAdmin
,
1197 DerniereModificationAdmin
, BaseAdmin
):
1198 ignore_duplicate_revisions
= True
1199 list_display
= ('nom', 'derniere_modification')
1201 (None, {'fields': ('nom',)}),
1205 class ValeurPointAdmin(reversion
.VersionAdmin
, DerniereModificationAdmin
,
1207 ignore_duplicate_revisions
= True
1209 '_devise_code', '_devise_nom', 'annee', 'implantation',
1210 'valeur', 'derniere_modification'
1212 list_filter
= ('annee', 'devise', 'implantation__region', )
1214 (None, {'fields': ('valeur', 'devise', 'implantation', 'annee')}),
1217 def _devise_code(self
, obj
):
1218 return obj
.devise
.code
1219 _devise_code
.short_description
= "Code de la devise"
1221 def _devise_nom(self
, obj
):
1222 return obj
.devise
.nom
1223 _devise_nom
.short_description
= "Nom de la devise"
1226 class ImplantationProxyAdmin(BaseAdmin
):
1227 list_display
= ('nom', '_organigramme')
1230 def __init__(self
, *args
, **kwargs
):
1231 super(ImplantationProxyAdmin
, self
).__init__(*args
, **kwargs
)
1232 self
.list_display_links
= (None, )
1234 def has_add_permission(self
, obj
):
1237 def has_change_permission(self
, request
, obj
=None):
1238 user_groups
= [g
.name
for g
in request
.user
.groups
.all()]
1239 if groups
.CORRESPONDANT_RH
in user_groups
or \
1240 groups
.ADMINISTRATEURS
in user_groups
or \
1241 groups
.DIRECTEUR_DE_BUREAU
in user_groups
or \
1242 in_drh_or_admin(request
.user
):
1246 def _organigramme(self
, obj
):
1247 return '<a href="%s"><strong>Organigramme</strong></a>' % (
1248 reverse('rho_implantation', args
=(obj
.id,))
1250 _organigramme
.allow_tags
= True
1251 _organigramme
.short_description
= "Organigramme"
1254 class RegionProxyAdmin(BaseAdmin
):
1255 list_display
= ('nom', '_organigramme')
1258 def __init__(self
, *args
, **kwargs
):
1259 super(RegionProxyAdmin
, self
).__init__(*args
, **kwargs
)
1260 self
.list_display_links
= (None, )
1262 def has_add_permission(self
, obj
):
1265 def has_change_permission(self
, request
, obj
=None):
1266 user_groups
= [g
.name
for g
in request
.user
.groups
.all()]
1267 if groups
.CORRESPONDANT_RH
in user_groups
or \
1268 groups
.ADMINISTRATEURS
in user_groups
or \
1269 groups
.DIRECTEUR_DE_BUREAU
in user_groups
or \
1270 in_drh_or_admin(request
.user
):
1274 def _organigramme(self
, obj
):
1275 return """<a href="%s"><strong>Organigramme</strong></a>""" % (
1276 reverse('rho_region', args
=(obj
.id,))
1278 _organigramme
.allow_tags
= True
1279 _organigramme
.short_description
= "Organigramme"
1282 admin
.site
.register(rh
.Classement
, ClassementAdmin
)
1283 admin
.site
.register(rh
.Devise
, DeviseAdmin
)
1284 admin
.site
.register(rh
.Dossier
, DossierAdmin
)
1285 admin
.site
.register(EmployeProxy
, EmployeProxyAdmin
)
1286 admin
.site
.register(ServiceProxy
, ServiceProxyAdmin
)
1287 admin
.site
.register(rh
.Employe
, EmployeAdmin
)
1288 admin
.site
.register(rh
.CategorieEmploi
, CategorieEmploiAdmin
)
1289 admin
.site
.register(rh
.FamilleProfessionnelle
)
1290 admin
.site
.register(rh
.OrganismeBstg
, OrganismeBstgAdmin
)
1291 admin
.site
.register(rh
.Poste
, PosteAdmin
)
1292 admin
.site
.register(
1293 rh
.ResponsableImplantationProxy
, ResponsableImplantationAdmin
1295 admin
.site
.register(rh
.Service
, ServiceAdmin
)
1296 admin
.site
.register(rh
.Statut
, StatutAdmin
)
1297 admin
.site
.register(rh
.TauxChange
, TauxChangeAdmin
)
1298 admin
.site
.register(rh
.TypeContrat
, TypeContratAdmin
)
1299 admin
.site
.register(rh
.TypePoste
, TypePosteAdmin
)
1300 admin
.site
.register(rh
.TypeRemuneration
, TypeRemunerationAdmin
)
1301 admin
.site
.register(rh
.TypeRevalorisation
, TypeRevalorisationAdmin
)
1302 admin
.site
.register(rh
.ValeurPoint
, ValeurPointAdmin
)
1303 admin
.site
.register(ImplantationProxy
, ImplantationProxyAdmin
)
1304 admin
.site
.register(RegionProxy
, RegionProxyAdmin
)