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 user_can_add_obj(request
.user
)
147 def has_change_permission(self
, request
, obj
=None):
148 return user_can_change_obj(request
.user
, obj
) if obj
else True
150 def has_delete_permission(self
, request
, obj
=None):
151 return user_can_delete_obj(request
.user
, obj
) if obj
else True
154 class DerniereModificationAdmin(admin
.ModelAdmin
):
156 def queryset(self
, request
):
157 qs
= super(DerniereModificationAdmin
, self
).queryset(request
)
158 ct
= ContentType
.objects
.get_for_model(self
.model
)
159 db_table
= self
.model
._meta
.db_table
160 pk
= self
.model
._meta
.pk
.column
161 return qs
.extra(select
={
163 "SELECT action_time FROM django_admin_log "
164 "WHERE content_type_id = %d AND object_id = %s.%s "
165 "ORDER BY action_time DESC "
166 "LIMIT 1" % (ct
.id, db_table
, pk
),
170 "INNER JOIN django_admin_log l ON l.user_id = u.id "
171 "WHERE l.content_type_id = %d AND object_id = %s.%s "
172 "ORDER BY action_time DESC "
173 "LIMIT 1" % (ct
.id, db_table
, pk
),
176 def derniere_modification(self
, obj
):
178 if obj
.date_modification
:
179 text
+= obj
.date_modification
.strftime('%d-%m-%Y %H:%M')
180 if obj
.user_modification
:
181 text
+= ' par ' + obj
.user_modification
183 derniere_modification
.short_description
= u
'dernière modification'
184 derniere_modification
.admin_order_field
= 'date_modification'
189 class CommentaireInlineForm(forms
.ModelForm
):
191 def save(self
, commit
=True):
193 # Hack: reversion.VersionAdmin ne sauvegarde pas les champs qui ne
194 # sont pas explicitement dans le formulaire. Il plante cependant
195 # leur valeur dans `self.initial`. Ceci est un peu fragile. Si
196 # c'est possible, il serait plus approprié que Reversion se rende
197 # compte qu'il manque des champs.
198 instance
= super(CommentaireInlineForm
, self
).save(commit
=False)
199 if instance
.owner_id
is None and 'owner' in self
.initial
:
200 instance
.owner_id
= self
.initial
['owner']
201 if instance
.date_creation
is None and 'date_creation' in self
.initial
:
202 instance
.date_creation
= self
.initial
['date_creation']
209 class ReadOnlyInlineMixin(object):
211 def get_readonly_fields(self
, request
, obj
=None):
212 return [f
.name
for f
in self
.model
._meta
.fields
]
215 class AyantDroitInline(admin
.StackedInline
):
216 model
= rh
.AyantDroit
217 form
= AyantDroitForm
224 ('nom_affichage', 'genre'),
232 class AyantDroitCommentaireInline(admin
.TabularInline
):
233 readonly_fields
= ('owner',)
234 model
= rh
.AyantDroitCommentaire
236 form
= CommentaireInlineForm
239 class ContratInline(admin
.TabularInline
):
245 class DossierROInline(ReadOnlyInlineMixin
, LinkedInline
):
246 template
= "admin/rh/dossier/linked.html"
251 def has_add_permission(self
, request
=None):
254 def has_change_permission(self
, request
, obj
=None):
257 def has_delete_permission(self
, request
, obj
=None):
261 class DossierCommentaireInline(admin
.TabularInline
):
262 readonly_fields
= ('owner',)
263 model
= rh
.DossierCommentaire
265 form
= CommentaireInlineForm
268 class DossierPieceInline(admin
.TabularInline
):
269 model
= rh
.DossierPiece
273 class EmployeInline(admin
.TabularInline
):
277 class EmployeCommentaireInline(admin
.TabularInline
):
278 readonly_fields
= ('owner',)
279 model
= rh
.EmployeCommentaire
281 form
= CommentaireInlineForm
284 class EmployePieceInline(admin
.TabularInline
):
285 model
= rh
.EmployePiece
289 class PosteCommentaireInline(admin
.TabularInline
):
290 readonly_fields
= ('owner',)
291 model
= rh
.PosteCommentaire
293 form
= CommentaireInlineForm
296 class PosteFinancementInline(admin
.TabularInline
):
297 model
= rh
.PosteFinancement
300 class PostePieceInline(admin
.TabularInline
):
301 model
= rh
.PostePiece
304 class RemunerationInline(admin
.TabularInline
):
305 model
= rh
.Remuneration
309 class RemunerationROInline(ReadOnlyInlineMixin
, RemunerationInline
):
313 class TypePosteInline(admin
.TabularInline
):
317 class PosteComparaisonInline(admin
.TabularInline
):
318 model
= rh
.PosteComparaison
321 class ClassementAdmin(reversion
.VersionAdmin
, DerniereModificationAdmin
,
323 ignore_duplicate_revisions
= True
324 list_display
= ('_classement', 'derniere_modification')
326 (None, {'fields': ('type', 'echelon', 'degre', 'coefficient',)}),
329 def _classement(self
, obj
):
331 _classement
.short_description
= u
"Classement"
334 class DeviseAdmin(reversion
.VersionAdmin
, ArchivableAdmin
,
335 DerniereModificationAdmin
, BaseAdmin
):
336 ignore_duplicate_revisions
= True
338 'code', 'nom', '_archive', 'derniere_modification',
340 list_filter
= ('archive', )
342 (None, {'fields': ('code', 'nom', 'archive', )}),
346 class DossierAdmin(DateRangeMixin
, ProtectRegionMixin
, reversion
.VersionAdmin
,
347 AjaxSelect
, DerniereModificationAdmin
, BaseAdmin
):
348 change_list_template
= "admin/rh/dossier/change_list.html"
349 ignore_duplicate_revisions
= True
350 alphabet_filter
= 'employe__nom'
358 'poste__nom_feminin',
359 'poste__implantation__nom',
371 'derniere_modification',
374 list_display_links
= ('_nom',)
376 'poste__implantation__region',
377 'poste__implantation',
378 'poste__type_poste__categorie_emploi',
380 'rh_contrats__type_contrat',
383 inlines
= (DossierPieceInline
, ContratInline
,
385 DossierCommentaireInline
,
394 'organisme_bstg',)}),
399 'remplacement_de', )}),
403 ('regime_travail', 'regime_travail_nb_heure_semaine'),)}),
404 ('Occupation du Poste par cet Employe', {
405 'fields': (('date_debut', 'date_fin'), )}
408 form
= make_ajax_form(rh
.Dossier
, {
409 'employe': 'employes',
411 'remplacement_de': 'dossiers',
412 }, superclass
=DossierForm
)
414 def lookup_allowed(self
, key
, value
):
416 'employe__nom__istartswith',
417 'poste__implantation__region__id__exact',
418 'poste__implantation__id__exact',
419 'poste__type_poste__id__exact',
420 'poste__type_poste__categorie_emploi__id__exact',
421 'rh_contrats__type_contrat__id__exact',
429 _id
.short_description
= u
"#"
430 _id
.admin_order_field
= "id"
432 def _apercu(self
, d
):
433 apercu_link
= u
"""<a title="Aperçu du dossier"
434 onclick="return showAddAnotherPopup(this);"
436 <img src="%simg/dossier-apercu.png" />
438 (reverse('dossier_apercu', args
=(d
.id,)),
442 _apercu
.allow_tags
= True
443 _apercu
.short_description
= u
""
447 _nom
.allow_tags
= True
448 _nom
.short_description
= u
"Dossier"
450 def _employe(self
, obj
):
451 employe
= obj
.employe
452 view_link
= reverse('employe_apercu', args
=(employe
.id,))
453 edit_link
= reverse('admin:rh_employe_change', args
=(employe
.id,))
455 view
= u
"""<a href="%s"
456 title="Aperçu l'employé"
457 onclick="return showAddAnotherPopup(this);">
458 <img src="%simg/employe-apercu.png" />
459 </a>""" % (view_link
, settings
.STATIC_URL
,)
460 return u
"""%s<a href='%s' style="%s;">%s</a>""" % \
461 (view
, edit_link
, style
, employe
)
462 _employe
.allow_tags
= True
463 _employe
.short_description
= u
"Employé"
464 _employe
.admin_order_field
= "employe__nom"
466 def _poste(self
, dossier
):
467 link
= u
"""<a title="Aperçu du poste"
468 onclick="return showAddAnotherPopup(this);"
469 href='%s'><img src="%simg/poste-apercu.png" />
471 <a href="%s" title="Modifier le poste">%s [%d]</a>""" % \
472 (reverse('poste_apercu', args
=(dossier
.poste
.id,)),
474 reverse('admin:rh_poste_change', args
=(dossier
.poste
.id,)),
479 _poste
.allow_tags
= True
480 _poste
.short_description
= u
'Poste'
481 _poste
.admin_order_field
= 'poste__nom'
483 def _region(self
, obj
):
484 return obj
.poste
.implantation
.region
.code
485 _region
.short_description
= u
"Région"
486 _region
.admin_order_field
= 'poste__implantation__region__code'
488 def _implantation(self
, obj
):
489 return obj
.poste
.implantation
.nom
490 _implantation
.short_description
= u
"Implantation"
491 _implantation
.admin_order_field
= 'poste__implantation__nom'
493 def _date_debut(self
, obj
):
494 return date(obj
.date_debut
)
496 _date_debut
.short_description
= u
'Début'
497 _date_debut
.admin_order_field
= 'date_debut'
499 def _date_fin(self
, obj
):
500 return date(obj
.date_fin
)
501 _date_fin
.short_description
= u
'Fin'
502 _date_fin
.admin_order_field
= 'date_fin'
504 def _date_modification(self
, obj
):
505 return date(obj
.date_modification
) \
506 if obj
.date_modification
is not None else "(aucune)"
507 _date_modification
.short_description
= u
'date modification'
508 _date_modification
.admin_order_field
= 'date_modification'
512 dossiers_dae
= d
.dossiers_dae
.all()
513 if len(dossiers_dae
) > 0:
514 dossier_dae
= dossiers_dae
[0]
515 apercu_link
= u
"""<a title="Aperçu du dossier"
516 onclick="return showAddAnotherPopup(this);"
518 <img src="%simg/loupe.png" />
520 (reverse('embauche_consulter', args
=(dossier_dae
.id,)),
524 _dae
.allow_tags
= True
525 _dae
.short_description
= u
"DAE"
527 def save_formset(self
, request
, form
, formset
, change
):
528 instances
= formset
.save(commit
=False)
529 for instance
in instances
:
530 if instance
.__class__
== rh
.DossierCommentaire
:
531 instance
.owner
= request
.user
532 instance
.date_creation
= datetime
.datetime
.now()
536 class EmployeAdminBase(DateRangeMixin
, ProtectRegionMixin
,
537 DerniereModificationAdmin
, BaseAdmin
):
538 prefixe_recherche_temporelle
= "rh_dossiers__"
539 alphabet_filter
= 'nom'
540 DEFAULT_ALPHABET
= u
'ABCDEFGHIJKLMNOPQRSTUVWXYZ'
542 'id', 'nom', 'prenom', 'nom_affichage',
543 'rh_dossiers__poste__nom',
544 'rh_dossiers__poste__nom_feminin'
547 form
= EmployeAdminForm
549 '_id', '_apercu', '_nom', '_dossiers_postes',
553 'derniere_modification'
555 list_display_links
= ('_nom',)
557 'rh_dossiers__poste__implantation__region',
558 'rh_dossiers__poste__implantation', 'nb_postes'
561 AyantDroitInline
, DossierROInline
, EmployePieceInline
,
562 EmployeCommentaireInline
568 ('nom_affichage', 'genre'),
573 ('Informations personnelles', {
574 'fields': ('situation_famille', 'date_entree', )
576 ('Coordonnées personnelles', {
578 ('tel_domicile', 'tel_cellulaire'),
579 ('adresse', 'ville'),
580 ('code_postal', 'province'),
589 _id
.short_description
= u
"#"
590 _id
.admin_order_field
= "id"
592 def _apercu(self
, obj
):
593 return u
"""<a title="Aperçu de l'employé"
594 onclick="return showAddAnotherPopup(this);"
596 <img src="%simg/employe-apercu.png" />
598 (reverse('employe_apercu', args
=(obj
.id,)), settings
.STATIC_URL
)
599 _apercu
.allow_tags
= True
600 _apercu
.short_description
= u
""
603 edit_link
= reverse('admin:rh_employe_change', args
=(obj
.id,))
604 return u
"""<a href='%s'><strong>%s</strong></a>""" % \
605 (edit_link
, "%s %s" % (obj
.nom
.upper(), obj
.prenom
))
606 _nom
.allow_tags
= True
607 _nom
.short_description
= u
"Employé"
608 _nom
.admin_order_field
= "nom"
610 def _region(self
, obj
):
612 d
= rh
.Dossier
.objects
.filter(employe
=obj
.id, principal
=True)[0]
613 region
= d
.poste
.implantation
.region
.code
617 _region
.short_description
= u
"Région"
619 def _implantation(self
, obj
):
621 d
= rh
.Dossier
.objects
.filter(employe
=obj
.id, principal
=True)[0]
622 implantation
= d
.poste
.implantation
.nom
626 _implantation
.short_description
= u
"Implantation"
628 def _dossiers_postes(self
, obj
):
630 for d
in obj
.rh_dossiers
.all().order_by('-date_debut'):
633 if d
.date_fin
is not None and d
.date_fin
< datetime
.date
.today():
634 link_style
= u
' style="color:#666;"'
635 list_style
= u
' style="color:grey;"'
637 dossier
= u
"""<a title="Aperçu du dossier"
639 onclick="return showAddAnotherPopup(this);"
640 title="Aperçu du dossier">
641 <img src="%simg/dossier-apercu.png" />
643 <a href="%s"%s>Dossier</a>
645 (reverse('dossier_apercu', args
=(d
.id,)),
647 reverse('admin:rh_dossier_change', args
=(d
.id,)),
650 poste
= u
"""<a title="Aperçu du poste"
652 onclick="return showAddAnotherPopup(this);"
653 title="Aperçu du poste">
654 <img src="%simg/poste-apercu.png" />
656 <a href="%s"%s>%s [%d]</a>
658 (reverse('poste_apercu', args
=(d
.poste
.id,)),
660 reverse('admin:rh_poste_change', args
=(d
.poste
.id,)),
665 link
= u
"""<li%s>%s %s</li>""" % \
666 (list_style
, dossier
, poste
)
669 return "<ul>%s</ul>" % "\n".join(l
)
670 _dossiers_postes
.allow_tags
= True
671 _dossiers_postes
.short_description
= u
"Dossiers et postes"
673 def _date_modification(self
, obj
):
674 return date(obj
.date_modification
) \
675 if obj
.date_modification
is not None else "(aucune)"
676 _date_modification
.short_description
= u
'date modification'
677 _date_modification
.admin_order_field
= 'date_modification'
679 def queryset(self
, request
):
680 qs
= super(EmployeAdminBase
, self
).queryset(request
)
681 return qs
.select_related(depth
=1).order_by('nom')
683 def save_formset(self
, request
, form
, formset
, change
):
684 instances
= formset
.save(commit
=False)
685 for instance
in instances
:
686 if instance
.__class__
== rh
.EmployeCommentaire
:
687 instance
.owner
= request
.user
688 instance
.date_creation
= datetime
.datetime
.now()
692 class EmployeAdmin(reversion
.VersionAdmin
, EmployeAdminBase
):
693 change_list_template
= "admin/rh/employe/change_list.html"
694 ignore_duplicate_revisions
= True
697 class EmployeProxyAdmin(EmployeAdminBase
):
698 list_display
= ('_id', '_apercu', '_nom', '_organigramme')
702 def __init__(self
, *args
, **kwargs
):
703 super(EmployeProxyAdmin
, self
).__init__(*args
, **kwargs
)
704 self
.list_display_links
= (None, )
706 def queryset(self
, request
):
707 qs
= super(ProtectRegionMixin
, self
).queryset(request
)
709 if in_drh_or_admin(request
.user
) or \
710 user_gere_obj_de_sa_region(request
.user
):
715 def has_add_permission(self
, obj
):
718 def has_change_permission(self
, request
, obj
=None):
719 user_groups
= [g
.name
for g
in request
.user
.groups
.all()]
720 if groups
.CORRESPONDANT_RH
in user_groups
or \
721 groups
.ADMINISTRATEURS
in user_groups
or \
722 groups
.DIRECTEUR_DE_BUREAU
in user_groups
or \
723 in_drh_or_admin(request
.user
):
727 def _organigramme(self
, obj
):
729 for d
in rh
.Dossier
.objects
.filter(
730 Q(date_fin__gt
=datetime
.date
.today()) |
Q(date_fin
=None),
731 Q(date_debut__lt
=datetime
.date
.today()) |
Q(date_debut
=None),
735 u
'Organigramme, niveau: ' \
736 u
'<input type="text" id="level_%s" ' \
737 u
'style="width:30px;height:15px;" /> ' \
738 u
'<input type="button" value="Générer" ' \
739 u
"""onclick="window.location='%s' + """ \
740 u
"""document.getElementById('level_%s').value" />""" % (
742 reverse('rho_employe_sans_niveau', args
=(d
.poste
.id,)),
745 link
= u
"""<li>%s [%s]:<br />%s</li>""" % (
751 return "<ul>%s</ul>" % "\n".join(l
)
753 _organigramme
.allow_tags
= True
754 _organigramme
.short_description
= "Organigramme"
757 class CategorieEmploiAdmin(reversion
.VersionAdmin
,
758 DerniereModificationAdmin
, BaseAdmin
):
759 ignore_duplicate_revisions
= True
760 list_display
= ('nom', 'derniere_modification')
761 inlines
= (TypePosteInline
,)
763 (None, {'fields': ('nom', )}),
767 class OrganismeBstgAdmin(reversion
.VersionAdmin
, DerniereModificationAdmin
,
769 ignore_duplicate_revisions
= True
770 search_fields
= ('nom',)
771 list_display
= ('nom', 'type', 'pays', 'derniere_modification')
772 list_filter
= ('type', )
773 inlines
= (DossierROInline
,)
775 (None, {'fields': ('nom', 'type', 'pays',)}),
779 class PosteAdmin(DateRangeMixin
, ProtectRegionMixin
, reversion
.VersionAdmin
,
780 AjaxSelect
, DerniereModificationAdmin
, BaseAdmin
):
781 change_list_template
= "admin/rh/poste/change_list.html"
782 ignore_duplicate_revisions
= True
783 form
= make_ajax_form(rh
.Poste
, {
784 'implantation': 'implantations',
785 'type_poste': 'typepostes',
786 'responsable': 'postes',
787 'valeur_point_min': 'valeurpoints',
788 'valeur_point_max': 'valeurpoints',
790 alphabet_filter
= 'nom'
795 'implantation__region__code',
796 'implantation__region__nom',
797 'rh_dossiers__employe__id',
798 'rh_dossiers__employe__nom',
799 'rh_dossiers__employe__prenom',
802 '_id', '_apercu', '_nom', '_occupe_par', 'implantation', '_service',
803 '_responsable', 'date_debut', 'date_fin', 'derniere_modification',
807 'implantation__region',
811 'type_poste__categorie_emploi',
812 'type_poste__famille_professionnelle',
815 list_display_links
= ('_nom',)
818 ('nom', 'nom_feminin'),
828 'regime_travail_nb_heure_semaine'),
832 'fields': (('local', 'expatrie', 'mise_a_disposition', 'appel'),)}
835 'fields': (('classement_min',
848 ('Comparatifs de rémunération', {
849 'fields': ('devise_comparaison',
850 ('comp_locale_min', 'comp_locale_max'),
851 ('comp_universite_min', 'comp_universite_max'),
852 ('comp_fonctionpub_min', 'comp_fonctionpub_max'),
853 ('comp_ong_min', 'comp_ong_max'),
854 ('comp_autre_min', 'comp_autre_max'))}
857 'fields': ('justification',)}
859 ('Autres Méta-données', {
860 'fields': ('date_debut', 'date_fin')}
864 inlines
= (PosteFinancementInline
,
867 PosteComparaisonInline
,
868 PosteCommentaireInline
, )
870 def lookup_allowed(self
, key
, value
):
872 'date_debut__gte', 'date_debut__isnull', 'date_fin__lte',
873 'date_fin__isnull', 'implantation__region__id__exact',
874 'implantation__id__exact', 'type_poste__id__exact',
875 'type_poste__categorie_emploi__id__exact', 'service__id__exact',
876 'service__isnull', 'vacant__exact', 'vacant__isnull',
877 ) or super(PosteAdmin
, self
).lookup_allowed(key
, value
)
881 _id
.short_description
= '#'
882 _id
.admin_order_field
= 'id'
884 def _apercu(self
, poste
):
885 view_link
= u
"""<a onclick="return showAddAnotherPopup(this);"
886 title="Aperçu du poste"
888 <img src="%simg/poste-apercu.png" />
890 (reverse('poste_apercu', args
=(poste
.id,)),
891 settings
.STATIC_URL
,)
893 _apercu
.allow_tags
= True
894 _apercu
.short_description
= ''
896 def _nom(self
, poste
):
897 return """<a href="%s">%s</a>""" % \
898 (reverse('admin:rh_poste_change', args
=(poste
.id,)),
900 _nom
.allow_tags
= True
901 _nom
.short_description
= u
'Poste'
902 _nom
.admin_order_field
= 'nom'
904 def _occupe_par(self
, obj
):
905 """Formatte la méthode Poste.occupe_par() pour l'admin"""
907 if obj
.date_fin
is not None and obj
.date_fin
< datetime
.date
.today():
909 employes
= obj
.occupe_par()
913 link
= u
"""<a href='%s'
914 title='Aperçu de l\'employé'
915 onclick='return showAddAnotherPopup(this)'>
916 <img src='%simg/employe-apercu.png' />
918 <a href='%s'>%s</a>""" % \
919 (reverse('employe_apercu', args
=(e
.id,)),
921 reverse('admin:rh_employe_change', args
=(e
.id,)),
924 output
= "\n<br />".join(l
)
926 _occupe_par
.allow_tags
= True
927 _occupe_par
.short_description
= "Occupé par"
929 def _region(self
, poste
):
930 return poste
.implantation
.region
.code
931 _region
.short_description
= 'Région'
932 _region
.admin_order_field
= 'implantation__region__code'
934 def _implantation(self
, poste
):
935 return poste
.implantation
.nom
936 _implantation
.short_description
= 'Implantation'
937 _implantation
.admin_order_field
= 'implantation'
939 def _service(self
, obj
):
941 _service
.short_description
= 'Service'
942 _service
.allow_tags
= True
944 def _responsable(self
, obj
):
946 responsable
= u
"""<a href="%s"
947 onclick="return showAddAnotherPopup(this)">
948 <img src="%simg/poste-apercu.png"
949 title="Aperçu du poste" />
951 <a href="%s">%s [%d]</a>
953 (reverse('poste_apercu', args
=(obj
.responsable
.id,)),
955 reverse('admin:rh_poste_change', args
=(obj
.responsable
.id,)),
962 dossier
= obj
.responsable
.rh_dossiers
.all() \
963 .order_by('-date_debut')[0]
964 employe_id
= dossier
.employe
.id
965 employe_html
= u
"""<br />
967 onclick="return showAddAnotherPopup(this)">
968 <img src="%simg/employe-apercu.png"
969 title="Aperçu de l'employé">
971 <a href="%s">%s</a>""" % \
972 (reverse('employe_apercu', args
=(employe_id
,)),
974 reverse('admin:rh_employe_change', args
=(employe_id
,)),
979 return "%s %s" % (responsable
, employe_html
)
980 _responsable
.short_description
= 'Responsable'
981 _responsable
.allow_tags
= True
983 def _date_debut(self
, obj
):
984 return date_format(obj
.date_debut
)
985 _date_debut
.short_description
= u
'Début'
986 _date_debut
.admin_order_field
= 'date_debut'
988 def _date_fin(self
, obj
):
989 return date_format(obj
.date_fin
)
990 _date_fin
.short_description
= u
'Fin'
991 _date_fin
.admin_order_field
= 'date_fin'
993 def _dae(self
, poste
):
995 postes_dae
= poste
.postes_dae
.all()
996 if len(postes_dae
) > 0:
997 poste_dae
= postes_dae
[0]
999 u
'<a title="Aperçu du dossier" href="%s" ' \
1000 u
'onclick="return showAddAnotherPopup(this);">' \
1001 u
'<img src="%simg/loupe.png" /></a>' % (reverse(
1002 'poste_consulter', args
=("dae-%s" % poste_dae
.id,)
1003 ), settings
.STATIC_URL
)
1005 _dae
.allow_tags
= True
1006 _dae
.short_description
= u
"DAE"
1008 def save_formset(self
, request
, form
, formset
, change
):
1009 instances
= formset
.save(commit
=False)
1010 for instance
in instances
:
1011 if instance
.__class__
== rh
.PosteCommentaire
:
1012 instance
.owner
= request
.user
1013 instance
.date_creation
= datetime
.datetime
.now()
1018 class ResponsableInline(admin
.TabularInline
):
1019 model
= rh
.ResponsableImplantation
1021 fk_name
= "implantation"
1022 form
= ResponsableInlineForm
1025 class ResponsableImplantationAdmin(BaseAdmin
):
1028 inlines
= (ResponsableInline
, )
1029 list_filter
= ('region', 'statut', )
1030 list_display
= ('_region', '_nom', 'statut', '_responsable', )
1031 list_display_links
= ('_nom',)
1033 readonly_fields
= ('nom', )
1036 'responsable__employe__id',
1037 'responsable__employe__nom',
1038 'responsable__employe__prenom',
1041 inlines
= (ResponsableInline
, )
1043 def _region(self
, obj
):
1044 return obj
.region
.code
1045 _region
.short_description
= u
"Région"
1046 _region
.admin_order_field
= 'region__code'
1048 def _nom(self
, obj
):
1050 _nom
.short_description
= u
"Implantation"
1051 _nom
.admin_order_field
= 'nom'
1053 def _responsable(self
, obj
):
1055 employe
= obj
.responsable
.employe
1056 dossiers
= employe
.dossiers_encours()
1057 if len(dossiers
) == 0:
1058 return u
"<span style='color: red;'>%s %s </span>" % (
1059 employe
, u
"sans dossier actif")
1063 if obj
.statut
in (1, 2): # ouverte, ouverture imminente
1064 css
= "style='color: red;'"
1067 return u
"<span %s>Pas de responsable</span>" % css
1068 _responsable
.allow_tags
= True
1069 _responsable
.short_description
= u
"Responsable"
1070 _responsable
.admin_order_field
= 'responsable__employe__nom'
1072 def has_add_permission(self
, request
=None):
1075 def has_change_permission(self
, request
, obj
=None):
1076 return in_drh_or_admin(request
.user
)
1078 def has_delete_permission(self
, request
, obj
=None):
1082 class ServiceAdminBase(ArchivableAdmin
, DerniereModificationAdmin
, BaseAdmin
):
1083 list_display
= ('nom', '_archive', 'derniere_modification')
1084 list_filter
= ('archive', )
1086 (None, {'fields': ('nom', 'archive')}),
1090 class ServiceAdmin(reversion
.VersionAdmin
, ServiceAdminBase
):
1091 ignore_duplicate_revisions
= True
1094 class ServiceProxyAdmin(ServiceAdminBase
):
1095 list_display
= ('nom', '_organigramme', '_archive', )
1098 def __init__(self
, *args
, **kwargs
):
1099 super(ServiceProxyAdmin
, self
).__init__(*args
, **kwargs
)
1100 self
.list_display_links
= (None, )
1102 def queryset(self
, request
):
1103 return super(ServiceProxyAdmin
, self
).queryset(request
) \
1104 .annotate(num_postes
=Count('rh_postes')) \
1105 .filter(num_postes__gt
=0)
1107 def has_add_permission(self
, obj
):
1110 def has_change_permission(self
, request
, obj
=None):
1111 user_groups
= [g
.name
for g
in request
.user
.groups
.all()]
1112 if groups
.CORRESPONDANT_RH
in user_groups
or \
1113 groups
.ADMINISTRATEURS
in user_groups
or \
1114 groups
.DIRECTEUR_DE_BUREAU
in user_groups
or \
1115 in_drh_or_admin(request
.user
):
1119 def _organigramme(self
, obj
):
1120 return """<a href="%s"><strong>Organigramme</strong></a>""" % \
1121 (reverse('rho_service', args
=(obj
.id,)))
1122 _organigramme
.allow_tags
= True
1123 _organigramme
.short_description
= "Organigramme"
1126 class StatutAdmin(reversion
.VersionAdmin
, DerniereModificationAdmin
,
1128 ignore_duplicate_revisions
= True
1129 list_display
= ('code', 'nom', 'derniere_modification')
1132 'fields': ('code', 'nom', ),
1137 class TauxChangeAdmin(reversion
.VersionAdmin
, DerniereModificationAdmin
,
1139 ignore_duplicate_revisions
= True
1140 list_display
= ('taux', 'devise', 'annee', 'derniere_modification')
1141 list_filter
= ('devise',)
1144 'fields': ('taux', 'devise', 'annee', ),
1149 class TypeContratAdmin(reversion
.VersionAdmin
, DerniereModificationAdmin
,
1151 ignore_duplicate_revisions
= True
1152 list_display
= ('nom', 'nom_long', 'derniere_modification')
1155 'fields': ('nom', 'nom_long', ),
1160 class TypePosteAdmin(reversion
.VersionAdmin
, DerniereModificationAdmin
,
1162 ignore_duplicate_revisions
= True
1163 search_fields
= ('nom', 'nom_feminin', )
1164 list_display
= ('nom', 'categorie_emploi', 'derniere_modification')
1165 list_filter
= ('categorie_emploi', 'famille_professionnelle')
1169 'nom', 'nom_feminin', 'is_responsable', 'categorie_emploi',
1170 'famille_professionnelle',
1176 class TypeRemunerationAdmin(reversion
.VersionAdmin
, ArchivableAdmin
,
1177 DerniereModificationAdmin
, BaseAdmin
):
1178 ignore_duplicate_revisions
= True
1180 'nom', 'type_paiement', 'nature_remuneration', '_archive',
1181 'derniere_modification'
1183 list_filter
= ('archive', )
1187 'nom', 'type_paiement', 'nature_remuneration', 'archive'
1193 class TypeRevalorisationAdmin(reversion
.VersionAdmin
,
1194 DerniereModificationAdmin
, BaseAdmin
):
1195 ignore_duplicate_revisions
= True
1196 list_display
= ('nom', 'derniere_modification')
1198 (None, {'fields': ('nom',)}),
1202 class ValeurPointAdmin(reversion
.VersionAdmin
, DerniereModificationAdmin
,
1204 ignore_duplicate_revisions
= True
1206 '_devise_code', '_devise_nom', 'annee', 'implantation',
1207 'valeur', 'derniere_modification'
1209 list_filter
= ('annee', 'devise', 'implantation__region', )
1211 (None, {'fields': ('valeur', 'devise', 'implantation', 'annee')}),
1214 def _devise_code(self
, obj
):
1215 return obj
.devise
.code
1216 _devise_code
.short_description
= "Code de la devise"
1218 def _devise_nom(self
, obj
):
1219 return obj
.devise
.nom
1220 _devise_nom
.short_description
= "Nom de la devise"
1223 class ImplantationProxyAdmin(BaseAdmin
):
1224 list_display
= ('nom', '_organigramme')
1227 def __init__(self
, *args
, **kwargs
):
1228 super(ImplantationProxyAdmin
, 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 user_groups
= [g
.name
for g
in request
.user
.groups
.all()]
1236 if groups
.CORRESPONDANT_RH
in user_groups
or \
1237 groups
.ADMINISTRATEURS
in user_groups
or \
1238 groups
.DIRECTEUR_DE_BUREAU
in user_groups
or \
1239 in_drh_or_admin(request
.user
):
1243 def _organigramme(self
, obj
):
1244 return '<a href="%s"><strong>Organigramme</strong></a>' % (
1245 reverse('rho_implantation', args
=(obj
.id,))
1247 _organigramme
.allow_tags
= True
1248 _organigramme
.short_description
= "Organigramme"
1251 class RegionProxyAdmin(BaseAdmin
):
1252 list_display
= ('nom', '_organigramme')
1255 def __init__(self
, *args
, **kwargs
):
1256 super(RegionProxyAdmin
, self
).__init__(*args
, **kwargs
)
1257 self
.list_display_links
= (None, )
1259 def has_add_permission(self
, obj
):
1262 def has_change_permission(self
, request
, obj
=None):
1263 user_groups
= [g
.name
for g
in request
.user
.groups
.all()]
1264 if groups
.CORRESPONDANT_RH
in user_groups
or \
1265 groups
.ADMINISTRATEURS
in user_groups
or \
1266 groups
.DIRECTEUR_DE_BUREAU
in user_groups
or \
1267 in_drh_or_admin(request
.user
):
1271 def _organigramme(self
, obj
):
1272 return """<a href="%s"><strong>Organigramme</strong></a>""" % (
1273 reverse('rho_region', args
=(obj
.id,))
1275 _organigramme
.allow_tags
= True
1276 _organigramme
.short_description
= "Organigramme"
1279 admin
.site
.register(rh
.Classement
, ClassementAdmin
)
1280 admin
.site
.register(rh
.Devise
, DeviseAdmin
)
1281 admin
.site
.register(rh
.Dossier
, DossierAdmin
)
1282 admin
.site
.register(EmployeProxy
, EmployeProxyAdmin
)
1283 admin
.site
.register(ServiceProxy
, ServiceProxyAdmin
)
1284 admin
.site
.register(rh
.Employe
, EmployeAdmin
)
1285 admin
.site
.register(rh
.CategorieEmploi
, CategorieEmploiAdmin
)
1286 admin
.site
.register(rh
.FamilleProfessionnelle
)
1287 admin
.site
.register(rh
.OrganismeBstg
, OrganismeBstgAdmin
)
1288 admin
.site
.register(rh
.Poste
, PosteAdmin
)
1289 admin
.site
.register(
1290 rh
.ResponsableImplantationProxy
, ResponsableImplantationAdmin
1292 admin
.site
.register(rh
.Service
, ServiceAdmin
)
1293 admin
.site
.register(rh
.Statut
, StatutAdmin
)
1294 admin
.site
.register(rh
.TauxChange
, TauxChangeAdmin
)
1295 admin
.site
.register(rh
.TypeContrat
, TypeContratAdmin
)
1296 admin
.site
.register(rh
.TypePoste
, TypePosteAdmin
)
1297 admin
.site
.register(rh
.TypeRemuneration
, TypeRemunerationAdmin
)
1298 admin
.site
.register(rh
.TypeRevalorisation
, TypeRevalorisationAdmin
)
1299 admin
.site
.register(rh
.ValeurPoint
, ValeurPointAdmin
)
1300 admin
.site
.register(ImplantationProxy
, ImplantationProxyAdmin
)
1301 admin
.site
.register(RegionProxy
, RegionProxyAdmin
)