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
, \
23 user_can_delete_obj
, \
26 from project
.rh
.forms
import ContratForm
, AyantDroitForm
, EmployeAdminForm
, \
27 AjaxSelect
, DossierForm
, ResponsableInlineForm
28 from project
.rh
.change_list
import ChangeList
31 class BaseAdmin(admin
.ModelAdmin
):
35 'css/admin_custom.css',
36 'jquery-autocomplete/jquery.autocomplete.css',
39 'https://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js',
40 'jquery-autocomplete/jquery.autocomplete.min.js',
44 # Admin pour reversion
46 class ArchivableAdmin(admin
.ModelAdmin
):
48 Admin pour les modèles archivables
50 list_filter
= ('archive', )
52 def queryset(self
, request
):
53 return self
.model
.avec_archives
.all()
55 def _archive(self
, obj
):
60 _archive
.short_description
= u
'Archivé'
61 _archive
.admin_order_field
= 'archive'
64 class RegionProxy(ref
.Region
):
65 """ Proxy utilisé pour les organigrammes par région """
69 verbose_name
= u
"Organigramme par région"
70 verbose_name_plural
= u
"Organigramme par région"
73 class ImplantationProxy(ref
.Implantation
):
74 """ Proxy utilisé pour les organigrammes par implantation """
78 verbose_name
= u
"Organigramme par implantations"
79 verbose_name_plural
= u
"Organigramme par implantations"
82 class ServiceProxy(rh
.Service
):
83 """ Proxy utilisé pour les organigrammes par service """
88 verbose_name
= u
"Organigramme par services"
89 verbose_name_plural
= u
"Organigramme par services"
92 class EmployeProxy(rh
.Employe
):
93 """ Proxy utilisé pour les organigrammes des employés """
97 verbose_name
= u
"Organigramme des employés"
98 verbose_name_plural
= u
"Organigramme des employés"
101 class DateRangeMixin(object):
102 prefixe_recherche_temporelle
= ""
104 def get_changelist(self
, request
, **kwargs
):
105 if 'HTTP_REFERER' in request
.META
.keys():
106 referer
= request
.META
['HTTP_REFERER']
107 referer
= "/".join(referer
.split('/')[3:])
108 referer
= "/%s" % referer
.split('?')[0]
109 change_list_view
= 'admin:%s_%s_changelist' % (
110 self
.model
._meta
.app_label
,
111 self
.model
.__name__
.lower(),)
112 if referer
!= reverse(change_list_view
):
113 params
= request
.GET
.copy()
114 params
.update({'statut': 'Actif'})
119 # Override of the InlineModelAdmin to support the link in the tabular inline
120 class LinkedInline(admin
.options
.InlineModelAdmin
):
121 template
= "admin/linked.html"
122 admin_model_path
= None
124 def __init__(self
, *args
):
125 super(LinkedInline
, self
).__init__(*args
)
126 if self
.admin_model_path
is None:
127 self
.admin_model_path
= self
.model
.__name__
.lower()
130 class ProtectRegionMixin(object):
132 def queryset(self
, request
):
133 qs
= super(ProtectRegionMixin
, self
).queryset(request
)
135 if in_drh_or_admin(request
.user
):
138 if user_gere_obj_de_sa_region(request
.user
):
139 region_user
= get_region_user(request
.user
)
140 q
= Q(**{self
.model
.prefix_implantation
: \
142 qs
= qs
.filter(q
).distinct()
146 def has_add_permission(self
, request
):
147 return user_can_add_obj(request
.user
)
149 def has_change_permission(self
, request
, obj
=None):
150 return user_can_change_obj(request
.user
, obj
) if obj
else True
152 def has_delete_permission(self
, request
, obj
=None):
153 return user_can_delete_obj(request
.user
, obj
) if obj
else True
156 class DerniereModificationAdmin(admin
.ModelAdmin
):
158 def queryset(self
, request
):
159 qs
= super(DerniereModificationAdmin
, self
).queryset(request
)
160 ct
= ContentType
.objects
.get_for_model(self
.model
)
161 db_table
= self
.model
._meta
.db_table
162 pk
= self
.model
._meta
.pk
.column
163 return qs
.extra(select
={
165 "SELECT action_time FROM django_admin_log "
166 "WHERE content_type_id = %d AND object_id = %s.%s "
167 "ORDER BY action_time DESC "
168 "LIMIT 1" % (ct
.id, db_table
, pk
),
172 "INNER JOIN django_admin_log l ON l.user_id = u.id "
173 "WHERE l.content_type_id = %d AND object_id = %s.%s "
174 "ORDER BY action_time DESC "
175 "LIMIT 1" % (ct
.id, db_table
, pk
),
178 def derniere_modification(self
, obj
):
180 if obj
.date_modification
:
181 text
+= obj
.date_modification
.strftime('%d-%m-%Y %H:%M')
182 if obj
.user_modification
:
183 text
+= ' par ' + obj
.user_modification
185 derniere_modification
.short_description
= u
'dernière modification'
186 derniere_modification
.admin_order_field
= 'date_modification'
191 class CommentaireInlineForm(forms
.ModelForm
):
193 def save(self
, commit
=True):
195 # Hack: reversion.VersionAdmin ne sauvegarde pas les champs qui ne
196 # sont pas explicitement dans le formulaire. Il plante cependant
197 # leur valeur dans `self.initial`. Ceci est un peu fragile. Si
198 # c'est possible, il serait plus approprié que Reversion se rende
199 # compte qu'il manque des champs.
200 instance
= super(CommentaireInlineForm
, self
).save(commit
=False)
201 if instance
.owner_id
is None and 'owner' in self
.initial
:
202 instance
.owner_id
= self
.initial
['owner']
203 if instance
.date_creation
is None and 'date_creation' in self
.initial
:
204 instance
.date_creation
= self
.initial
['date_creation']
211 class ReadOnlyInlineMixin(object):
213 def get_readonly_fields(self
, request
, obj
=None):
214 return [f
.name
for f
in self
.model
._meta
.fields
]
217 class AyantDroitInline(admin
.StackedInline
):
218 model
= rh
.AyantDroit
219 form
= AyantDroitForm
226 ('nom_affichage', 'genre'),
234 class AyantDroitCommentaireInline(admin
.TabularInline
):
235 readonly_fields
= ('owner',)
236 model
= rh
.AyantDroitCommentaire
238 form
= CommentaireInlineForm
241 class ContratInline(admin
.TabularInline
):
247 class DossierROInline(ReadOnlyInlineMixin
, LinkedInline
):
248 template
= "admin/rh/dossier/linked.html"
253 def has_add_permission(self
, request
=None):
256 def has_change_permission(self
, request
, obj
=None):
259 def has_delete_permission(self
, request
, obj
=None):
263 class DossierCommentaireInline(admin
.TabularInline
):
264 readonly_fields
= ('owner',)
265 model
= rh
.DossierCommentaire
267 form
= CommentaireInlineForm
270 class DossierPieceInline(admin
.TabularInline
):
271 model
= rh
.DossierPiece
275 class EmployeInline(admin
.TabularInline
):
279 class EmployeCommentaireInline(admin
.TabularInline
):
280 readonly_fields
= ('owner',)
281 model
= rh
.EmployeCommentaire
283 form
= CommentaireInlineForm
286 class EmployePieceInline(admin
.TabularInline
):
287 model
= rh
.EmployePiece
291 class PosteCommentaireInline(admin
.TabularInline
):
292 readonly_fields
= ('owner',)
293 model
= rh
.PosteCommentaire
295 form
= CommentaireInlineForm
298 class PosteFinancementInline(admin
.TabularInline
):
299 model
= rh
.PosteFinancement
302 class PostePieceInline(admin
.TabularInline
):
303 model
= rh
.PostePiece
306 class RemunerationInline(admin
.TabularInline
):
307 model
= rh
.Remuneration
311 class RemunerationROInline(ReadOnlyInlineMixin
, RemunerationInline
):
315 class TypePosteInline(admin
.TabularInline
):
319 class PosteComparaisonInline(admin
.TabularInline
):
320 model
= rh
.PosteComparaison
323 class ClassementAdmin(reversion
.VersionAdmin
, DerniereModificationAdmin
,
325 ignore_duplicate_revisions
= True
326 list_display
= ('_classement', 'derniere_modification')
328 (None, {'fields': ('type', 'echelon', 'degre', 'coefficient',)}),
331 def _classement(self
, obj
):
333 _classement
.short_description
= u
"Classement"
336 class DeviseAdmin(reversion
.VersionAdmin
, ArchivableAdmin
,
337 DerniereModificationAdmin
, BaseAdmin
):
338 ignore_duplicate_revisions
= True
340 'code', 'nom', '_archive', 'derniere_modification',
342 list_filter
= ('archive', )
344 (None, {'fields': ('code', 'nom', 'archive', )}),
348 class DossierAdmin(DateRangeMixin
, ProtectRegionMixin
, reversion
.VersionAdmin
,
349 AjaxSelect
, DerniereModificationAdmin
, BaseAdmin
):
350 change_list_template
= "admin/rh/dossier/change_list.html"
351 ignore_duplicate_revisions
= True
352 alphabet_filter
= 'employe__nom'
360 'poste__nom_feminin',
361 'poste__implantation__nom',
369 '_zone_administrative',
373 'derniere_modification',
376 list_display_links
= ('_nom',)
378 'poste__implantation__zone_administrative',
379 'poste__implantation',
380 'poste__type_poste__categorie_emploi',
382 'rh_contrats__type_contrat',
385 inlines
= (DossierPieceInline
, ContratInline
,
387 DossierCommentaireInline
,
396 'organisme_bstg',)}),
401 'remplacement_de', )}),
405 ('regime_travail', 'regime_travail_nb_heure_semaine'),)}),
406 ('Occupation du Poste par cet Employe', {
407 'fields': (('date_debut', 'date_fin'), )}
410 form
= make_ajax_form(rh
.Dossier
, {
411 'employe': 'employes',
413 'remplacement_de': 'dossiers',
414 }, superclass
=DossierForm
)
416 def lookup_allowed(self
, key
, value
):
418 'employe__nom__istartswith',
419 'poste__implantation__zone_administrative__code__exact',
420 'poste__implantation__id__exact',
421 'poste__type_poste__id__exact',
422 'poste__type_poste__categorie_emploi__id__exact',
423 'rh_contrats__type_contrat__id__exact',
431 _id
.short_description
= u
"#"
432 _id
.admin_order_field
= "id"
434 def _apercu(self
, d
):
435 apercu_link
= u
"""<a title="Aperçu du dossier"
436 onclick="return showAddAnotherPopup(this);"
438 <img src="%simg/dossier-apercu.png" />
440 (reverse('dossier_apercu', args
=(d
.id,)),
444 _apercu
.allow_tags
= True
445 _apercu
.short_description
= u
""
449 _nom
.allow_tags
= True
450 _nom
.short_description
= u
"Dossier"
452 def _employe(self
, obj
):
453 employe
= obj
.employe
454 view_link
= reverse('employe_apercu', args
=(employe
.id,))
455 edit_link
= reverse('admin:rh_employe_change', args
=(employe
.id,))
457 view
= u
"""<a href="%s"
458 title="Aperçu l'employé"
459 onclick="return showAddAnotherPopup(this);">
460 <img src="%simg/employe-apercu.png" />
461 </a>""" % (view_link
, settings
.STATIC_URL
,)
462 return u
"""%s<a href='%s' style="%s;">%s</a>""" % \
463 (view
, edit_link
, style
, employe
)
464 _employe
.allow_tags
= True
465 _employe
.short_description
= u
"Employé"
466 _employe
.admin_order_field
= "employe__nom"
468 def _poste(self
, dossier
):
469 link
= u
"""<a title="Aperçu du poste"
470 onclick="return showAddAnotherPopup(this);"
471 href='%s'><img src="%simg/poste-apercu.png" />
473 <a href="%s" title="Modifier le poste">%s [%d]</a>""" % \
474 (reverse('poste_apercu', args
=(dossier
.poste
.id,)),
476 reverse('admin:rh_poste_change', args
=(dossier
.poste
.id,)),
481 _poste
.allow_tags
= True
482 _poste
.short_description
= u
'Poste'
483 _poste
.admin_order_field
= 'poste__nom'
485 def _zone_administrative(self
, obj
):
486 return obj
.poste
.implantation
.zone_administrative
.code
487 _zone_administrative
.short_description
= u
"Zone administrative"
488 _zone_administrative
.admin_order_field
= 'poste__implantation__zone_administrative__code'
490 def _implantation(self
, obj
):
491 return obj
.poste
.implantation
.nom
492 _implantation
.short_description
= u
"Implantation"
493 _implantation
.admin_order_field
= 'poste__implantation__nom'
495 def _date_debut(self
, obj
):
496 return date(obj
.date_debut
)
498 _date_debut
.short_description
= u
'Début'
499 _date_debut
.admin_order_field
= 'date_debut'
501 def _date_fin(self
, obj
):
502 return date(obj
.date_fin
)
503 _date_fin
.short_description
= u
'Fin'
504 _date_fin
.admin_order_field
= 'date_fin'
506 def _date_modification(self
, obj
):
507 return date(obj
.date_modification
) \
508 if obj
.date_modification
is not None else "(aucune)"
509 _date_modification
.short_description
= u
'date modification'
510 _date_modification
.admin_order_field
= 'date_modification'
514 dossiers_dae
= d
.dossiers_dae
.all()
515 if len(dossiers_dae
) > 0:
516 dossier_dae
= dossiers_dae
[0]
517 apercu_link
= u
"""<a title="Aperçu du dossier"
518 onclick="return showAddAnotherPopup(this);"
520 <img src="%simg/loupe.png" />
522 (reverse('embauche_consulter', args
=(dossier_dae
.id,)),
526 _dae
.allow_tags
= True
527 _dae
.short_description
= u
"DAE"
529 def save_formset(self
, request
, form
, formset
, change
):
530 instances
= formset
.save(commit
=False)
531 for instance
in instances
:
532 if instance
.__class__
== rh
.DossierCommentaire
:
533 instance
.owner
= request
.user
534 instance
.date_creation
= datetime
.datetime
.now()
538 class EmployeAdminBase(DateRangeMixin
, ProtectRegionMixin
,
539 DerniereModificationAdmin
, BaseAdmin
):
540 prefixe_recherche_temporelle
= "rh_dossiers__"
541 alphabet_filter
= 'nom'
542 DEFAULT_ALPHABET
= u
'ABCDEFGHIJKLMNOPQRSTUVWXYZ'
544 'id', 'nom', 'prenom', 'nom_affichage',
545 'rh_dossiers__poste__nom',
546 'rh_dossiers__poste__nom_feminin'
549 form
= EmployeAdminForm
551 '_id', '_apercu', '_nom', '_dossiers_postes',
552 #'_zone_administrative',
555 'derniere_modification'
557 list_display_links
= ('_nom',)
559 'rh_dossiers__poste__implantation__zone_administrative',
560 'rh_dossiers__poste__implantation', 'nb_postes'
563 AyantDroitInline
, DossierROInline
, EmployePieceInline
,
564 EmployeCommentaireInline
570 ('nom_affichage', 'genre'),
575 ('Informations personnelles', {
576 'fields': ('situation_famille', 'date_entree', )
578 ('Coordonnées personnelles', {
580 ('tel_domicile', 'tel_cellulaire'),
581 ('adresse', 'ville'),
582 ('code_postal', 'province'),
591 _id
.short_description
= u
"#"
592 _id
.admin_order_field
= "id"
594 def _apercu(self
, obj
):
595 return u
"""<a title="Aperçu de l'employé"
596 onclick="return showAddAnotherPopup(this);"
598 <img src="%simg/employe-apercu.png" />
600 (reverse('employe_apercu', args
=(obj
.id,)), settings
.STATIC_URL
)
601 _apercu
.allow_tags
= True
602 _apercu
.short_description
= u
""
605 edit_link
= reverse('admin:rh_employe_change', args
=(obj
.id,))
606 return u
"""<a href='%s'><strong>%s</strong></a>""" % \
607 (edit_link
, "%s %s" % (obj
.nom
.upper(), obj
.prenom
))
608 _nom
.allow_tags
= True
609 _nom
.short_description
= u
"Employé"
610 _nom
.admin_order_field
= "nom"
612 def _zone_administrative(self
, obj
):
614 d
= rh
.Dossier
.objects
.filter(employe
=obj
.id, principal
=True)[0]
615 zone
= d
.poste
.implantation
.zone_administrative
.code
619 _zone_administrative
.short_description
= u
"Zone administrative"
621 def _implantation(self
, obj
):
623 d
= rh
.Dossier
.objects
.filter(employe
=obj
.id, principal
=True)[0]
624 implantation
= d
.poste
.implantation
.nom
628 _implantation
.short_description
= u
"Implantation"
630 def _dossiers_postes(self
, obj
):
632 for d
in obj
.rh_dossiers
.all().order_by('-date_debut'):
635 if d
.date_fin
is not None and d
.date_fin
< datetime
.date
.today():
636 link_style
= u
' style="color:#666;"'
637 list_style
= u
' style="color:grey;"'
639 dossier
= u
"""<a title="Aperçu du dossier"
641 onclick="return showAddAnotherPopup(this);"
642 title="Aperçu du dossier">
643 <img src="%simg/dossier-apercu.png" />
645 <a href="%s"%s>Dossier</a>
647 (reverse('dossier_apercu', args
=(d
.id,)),
649 reverse('admin:rh_dossier_change', args
=(d
.id,)),
652 poste
= u
"""<a title="Aperçu du poste"
654 onclick="return showAddAnotherPopup(this);"
655 title="Aperçu du poste">
656 <img src="%simg/poste-apercu.png" />
658 <a href="%s"%s>%s [%d]</a>
660 (reverse('poste_apercu', args
=(d
.poste
.id,)),
662 reverse('admin:rh_poste_change', args
=(d
.poste
.id,)),
667 link
= u
"""<li%s>%s %s</li>""" % \
668 (list_style
, dossier
, poste
)
671 return "<ul>%s</ul>" % "\n".join(l
)
672 _dossiers_postes
.allow_tags
= True
673 _dossiers_postes
.short_description
= u
"Dossiers et postes"
675 def _date_modification(self
, obj
):
676 return date(obj
.date_modification
) \
677 if obj
.date_modification
is not None else "(aucune)"
678 _date_modification
.short_description
= u
'date modification'
679 _date_modification
.admin_order_field
= 'date_modification'
681 def queryset(self
, request
):
682 qs
= super(EmployeAdminBase
, self
).queryset(request
)
683 return qs
.select_related(depth
=1).order_by('nom')
685 def save_formset(self
, request
, form
, formset
, change
):
686 instances
= formset
.save(commit
=False)
687 for instance
in instances
:
688 if instance
.__class__
== rh
.EmployeCommentaire
:
689 instance
.owner
= request
.user
690 instance
.date_creation
= datetime
.datetime
.now()
694 class EmployeAdmin(reversion
.VersionAdmin
, EmployeAdminBase
):
695 change_list_template
= "admin/rh/employe/change_list.html"
696 ignore_duplicate_revisions
= True
699 class EmployeProxyAdmin(EmployeAdminBase
):
700 list_display
= ('_id', '_apercu', '_nom', '_organigramme')
704 def __init__(self
, *args
, **kwargs
):
705 super(EmployeProxyAdmin
, self
).__init__(*args
, **kwargs
)
706 self
.list_display_links
= (None, )
708 def queryset(self
, request
):
709 qs
= super(ProtectRegionMixin
, self
).queryset(request
)
711 if in_drh_or_admin(request
.user
) or \
712 user_gere_obj_de_sa_region(request
.user
):
717 def has_add_permission(self
, obj
):
720 def has_change_permission(self
, request
, obj
=None):
721 user_groups
= [g
.name
for g
in request
.user
.groups
.all()]
722 if groups
.CORRESPONDANT_RH
in user_groups
or \
723 groups
.ADMINISTRATEURS
in user_groups
or \
724 groups
.DIRECTEUR_DE_BUREAU
in user_groups
or \
725 in_drh_or_admin(request
.user
):
729 def _organigramme(self
, obj
):
731 for d
in rh
.Dossier
.objects
.filter(
732 Q(date_fin__gt
=datetime
.date
.today()) |
Q(date_fin
=None),
733 Q(date_debut__lt
=datetime
.date
.today()) |
Q(date_debut
=None),
737 u
'Organigramme, niveau: ' \
738 u
'<input type="text" id="level_%s" ' \
739 u
'style="width:30px;height:15px;" /> ' \
740 u
'<input type="button" value="Générer" ' \
741 u
"""onclick="window.location='%s' + """ \
742 u
"""document.getElementById('level_%s').value" />""" % (
744 reverse('rho_employe_sans_niveau', args
=(d
.poste
.id,)),
747 link
= u
"""<li>%s [%s]:<br />%s</li>""" % (
753 return "<ul>%s</ul>" % "\n".join(l
)
755 _organigramme
.allow_tags
= True
756 _organigramme
.short_description
= "Organigramme"
759 class CategorieEmploiAdmin(reversion
.VersionAdmin
,
760 DerniereModificationAdmin
, BaseAdmin
):
761 ignore_duplicate_revisions
= True
762 list_display
= ('nom', 'derniere_modification')
763 inlines
= (TypePosteInline
,)
765 (None, {'fields': ('nom', )}),
769 class OrganismeBstgAdmin(reversion
.VersionAdmin
, DerniereModificationAdmin
,
771 ignore_duplicate_revisions
= True
772 search_fields
= ('nom',)
773 list_display
= ('nom', 'type', 'pays', 'derniere_modification')
774 list_filter
= ('type', )
775 inlines
= (DossierROInline
,)
777 (None, {'fields': ('nom', 'type', 'pays',)}),
781 class PosteAdmin(DateRangeMixin
, ProtectRegionMixin
, reversion
.VersionAdmin
,
782 AjaxSelect
, DerniereModificationAdmin
, BaseAdmin
):
783 change_list_template
= "admin/rh/poste/change_list.html"
784 ignore_duplicate_revisions
= True
785 form
= make_ajax_form(rh
.Poste
, {
786 'implantation': 'implantations',
787 'type_poste': 'typepostes',
788 'responsable': 'postes',
789 'valeur_point_min': 'valeurpoints',
790 'valeur_point_max': 'valeurpoints',
792 alphabet_filter
= 'nom'
797 'implantation__zone_administrative__code',
798 'implantation__zone_administrative__nom',
799 'rh_dossiers__employe__id',
800 'rh_dossiers__employe__nom',
801 'rh_dossiers__employe__prenom',
804 '_id', '_apercu', '_nom', '_occupe_par', 'implantation', '_service',
805 '_responsable', 'date_debut', 'date_fin', 'derniere_modification',
809 'implantation__zone_administrative',
813 'type_poste__categorie_emploi',
814 'type_poste__famille_professionnelle',
817 list_display_links
= ('_nom',)
820 ('nom', 'nom_feminin'),
830 'regime_travail_nb_heure_semaine'),
834 'fields': (('local', 'expatrie', 'mise_a_disposition', 'appel'),)}
837 'fields': (('classement_min',
850 ('Comparatifs de rémunération', {
851 'fields': ('devise_comparaison',
852 ('comp_locale_min', 'comp_locale_max'),
853 ('comp_universite_min', 'comp_universite_max'),
854 ('comp_fonctionpub_min', 'comp_fonctionpub_max'),
855 ('comp_ong_min', 'comp_ong_max'),
856 ('comp_autre_min', 'comp_autre_max'))}
859 'fields': ('justification',)}
861 ('Autres Méta-données', {
862 'fields': ('date_debut', 'date_fin')}
866 inlines
= (PosteFinancementInline
,
869 PosteComparaisonInline
,
870 PosteCommentaireInline
, )
872 def lookup_allowed(self
, key
, value
):
874 'date_debut__gte', 'date_debut__isnull', 'date_fin__lte',
875 'date_fin__isnull', 'implantation__zone_administrative__code__exact',
876 'implantation__id__exact', 'type_poste__id__exact',
877 'type_poste__categorie_emploi__id__exact', 'service__id__exact',
878 'service__isnull', 'vacant__exact', 'vacant__isnull',
879 ) or super(PosteAdmin
, self
).lookup_allowed(key
, value
)
883 _id
.short_description
= '#'
884 _id
.admin_order_field
= 'id'
886 def _apercu(self
, poste
):
887 view_link
= u
"""<a onclick="return showAddAnotherPopup(this);"
888 title="Aperçu du poste"
890 <img src="%simg/poste-apercu.png" />
892 (reverse('poste_apercu', args
=(poste
.id,)),
893 settings
.STATIC_URL
,)
895 _apercu
.allow_tags
= True
896 _apercu
.short_description
= ''
898 def _nom(self
, poste
):
899 return """<a href="%s">%s</a>""" % \
900 (reverse('admin:rh_poste_change', args
=(poste
.id,)),
902 _nom
.allow_tags
= True
903 _nom
.short_description
= u
'Poste'
904 _nom
.admin_order_field
= 'nom'
906 def _occupe_par(self
, obj
):
907 """Formatte la méthode Poste.occupe_par() pour l'admin"""
909 if obj
.date_fin
is not None and obj
.date_fin
< datetime
.date
.today():
911 employes
= obj
.occupe_par()
915 link
= u
"""<a href='%s'
916 title='Aperçu de l\'employé'
917 onclick='return showAddAnotherPopup(this)'>
918 <img src='%simg/employe-apercu.png' />
920 <a href='%s'>%s</a>""" % \
921 (reverse('employe_apercu', args
=(e
.id,)),
923 reverse('admin:rh_employe_change', args
=(e
.id,)),
926 output
= "\n<br />".join(l
)
928 _occupe_par
.allow_tags
= True
929 _occupe_par
.short_description
= "Occupé par"
931 def _zone_administrative(self
, poste
):
932 return poste
.implantation
.zone_administrative
.code
933 _zone_administrative
.short_description
= 'Zone administrative'
934 _zone_administrative
.admin_order_field
= 'implantation__zone_administrative__code'
936 def _implantation(self
, poste
):
937 return poste
.implantation
.nom
938 _implantation
.short_description
= 'Implantation'
939 _implantation
.admin_order_field
= 'implantation'
941 def _service(self
, obj
):
943 _service
.short_description
= 'Service'
944 _service
.allow_tags
= True
946 def _responsable(self
, obj
):
948 responsable
= u
"""<a href="%s"
949 onclick="return showAddAnotherPopup(this)">
950 <img src="%simg/poste-apercu.png"
951 title="Aperçu du poste" />
953 <a href="%s">%s [%d]</a>
955 (reverse('poste_apercu', args
=(obj
.responsable
.id,)),
957 reverse('admin:rh_poste_change', args
=(obj
.responsable
.id,)),
964 dossier
= obj
.responsable
.rh_dossiers
.all() \
965 .order_by('-date_debut')[0]
966 employe_id
= dossier
.employe
.id
967 employe_html
= u
"""<br />
969 onclick="return showAddAnotherPopup(this)">
970 <img src="%simg/employe-apercu.png"
971 title="Aperçu de l'employé">
973 <a href="%s">%s</a>""" % \
974 (reverse('employe_apercu', args
=(employe_id
,)),
976 reverse('admin:rh_employe_change', args
=(employe_id
,)),
981 return "%s %s" % (responsable
, employe_html
)
982 _responsable
.short_description
= 'Responsable'
983 _responsable
.allow_tags
= True
985 def _date_debut(self
, obj
):
986 return date_format(obj
.date_debut
)
987 _date_debut
.short_description
= u
'Début'
988 _date_debut
.admin_order_field
= 'date_debut'
990 def _date_fin(self
, obj
):
991 return date_format(obj
.date_fin
)
992 _date_fin
.short_description
= u
'Fin'
993 _date_fin
.admin_order_field
= 'date_fin'
995 def _dae(self
, poste
):
997 postes_dae
= poste
.postes_dae
.all()
998 if len(postes_dae
) > 0:
999 poste_dae
= postes_dae
[0]
1001 u
'<a title="Aperçu du dossier" href="%s" ' \
1002 u
'onclick="return showAddAnotherPopup(this);">' \
1003 u
'<img src="%simg/loupe.png" /></a>' % (reverse(
1004 'poste_consulter', args
=("dae-%s" % poste_dae
.id,)
1005 ), settings
.STATIC_URL
)
1007 _dae
.allow_tags
= True
1008 _dae
.short_description
= u
"DAE"
1010 def save_formset(self
, request
, form
, formset
, change
):
1011 instances
= formset
.save(commit
=False)
1012 for instance
in instances
:
1013 if instance
.__class__
== rh
.PosteCommentaire
:
1014 instance
.owner
= request
.user
1015 instance
.date_creation
= datetime
.datetime
.now()
1020 class ResponsableInline(admin
.TabularInline
):
1021 model
= rh
.ResponsableImplantation
1023 fk_name
= "implantation"
1024 form
= ResponsableInlineForm
1027 class ResponsableImplantationAdmin(BaseAdmin
):
1030 inlines
= (ResponsableInline
, )
1031 list_filter
= ('zone_administrative', 'statut', )
1032 list_display
= ('_zone_administrative', '_nom', 'statut', '_responsable', )
1033 list_display_links
= ('_nom',)
1035 readonly_fields
= ('nom', )
1038 'responsable__employe__id',
1039 'responsable__employe__nom',
1040 'responsable__employe__prenom',
1043 inlines
= (ResponsableInline
, )
1045 def _zone_administrative(self
, obj
):
1046 return obj
.zone_administrative
.code
1047 _zone_administrative
.short_description
= u
"Zone administrative"
1048 _zone_administrative
.admin_order_field
= 'zone_administrative__code'
1050 def _nom(self
, obj
):
1052 _nom
.short_description
= u
"Implantation"
1053 _nom
.admin_order_field
= 'nom'
1055 def _responsable(self
, obj
):
1057 employe
= obj
.responsable
.employe
1058 dossiers
= employe
.dossiers_encours()
1059 if len(dossiers
) == 0:
1060 return u
"<span style='color: red;'>%s %s </span>" % (
1061 employe
, u
"sans dossier actif")
1065 if obj
.statut
in (1, 2): # ouverte, ouverture imminente
1066 css
= "style='color: red;'"
1069 return u
"<span %s>Pas de responsable</span>" % css
1070 _responsable
.allow_tags
= True
1071 _responsable
.short_description
= u
"Responsable"
1072 _responsable
.admin_order_field
= 'responsable__employe__nom'
1074 def has_add_permission(self
, request
=None):
1077 def has_change_permission(self
, request
, obj
=None):
1078 return in_drh_or_admin(request
.user
)
1080 def has_delete_permission(self
, request
, obj
=None):
1084 class ServiceAdminBase(ArchivableAdmin
, DerniereModificationAdmin
, BaseAdmin
):
1085 list_display
= ('nom', '_archive', 'derniere_modification')
1086 list_filter
= ('archive', )
1088 (None, {'fields': ('nom', 'archive')}),
1092 class ServiceAdmin(reversion
.VersionAdmin
, ServiceAdminBase
):
1093 ignore_duplicate_revisions
= True
1096 class ServiceProxyAdmin(ServiceAdminBase
):
1097 list_display
= ('nom', '_organigramme', '_archive', )
1100 def __init__(self
, *args
, **kwargs
):
1101 super(ServiceProxyAdmin
, self
).__init__(*args
, **kwargs
)
1102 self
.list_display_links
= (None, )
1104 def queryset(self
, request
):
1105 return super(ServiceProxyAdmin
, self
).queryset(request
) \
1106 .annotate(num_postes
=Count('rh_postes')) \
1107 .filter(num_postes__gt
=0)
1109 def has_add_permission(self
, obj
):
1112 def has_change_permission(self
, request
, obj
=None):
1113 user_groups
= [g
.name
for g
in request
.user
.groups
.all()]
1114 if groups
.CORRESPONDANT_RH
in user_groups
or \
1115 groups
.ADMINISTRATEURS
in user_groups
or \
1116 groups
.DIRECTEUR_DE_BUREAU
in user_groups
or \
1117 in_drh_or_admin(request
.user
):
1121 def _organigramme(self
, obj
):
1122 return """<a href="%s"><strong>Organigramme</strong></a>""" % \
1123 (reverse('rho_service', args
=(obj
.id,)))
1124 _organigramme
.allow_tags
= True
1125 _organigramme
.short_description
= "Organigramme"
1128 class StatutAdmin(reversion
.VersionAdmin
, DerniereModificationAdmin
,
1130 ignore_duplicate_revisions
= True
1131 list_display
= ('code', 'nom', 'derniere_modification')
1134 'fields': ('code', 'nom', ),
1139 class TauxChangeAdmin(reversion
.VersionAdmin
, DerniereModificationAdmin
,
1141 ignore_duplicate_revisions
= True
1142 list_display
= ('taux', 'devise', 'annee', 'derniere_modification')
1143 list_filter
= ('devise',)
1146 'fields': ('taux', 'devise', 'annee', ),
1151 class TypeContratAdmin(reversion
.VersionAdmin
, DerniereModificationAdmin
,
1153 ignore_duplicate_revisions
= True
1154 list_display
= ('nom', 'nom_long', 'derniere_modification')
1157 'fields': ('nom', 'nom_long', ),
1162 class TypePosteAdmin(reversion
.VersionAdmin
, DerniereModificationAdmin
,
1164 ignore_duplicate_revisions
= True
1165 search_fields
= ('nom', 'nom_feminin', )
1166 list_display
= ('nom', 'categorie_emploi', 'derniere_modification')
1167 list_filter
= ('categorie_emploi', 'famille_professionnelle')
1171 'nom', 'nom_feminin', 'is_responsable', 'categorie_emploi',
1172 'famille_professionnelle',
1178 class TypeRemunerationAdmin(reversion
.VersionAdmin
, ArchivableAdmin
,
1179 DerniereModificationAdmin
, BaseAdmin
):
1180 ignore_duplicate_revisions
= True
1182 'nom', 'type_paiement', 'nature_remuneration', '_archive',
1183 'derniere_modification'
1185 list_filter
= ('archive', )
1189 'nom', 'type_paiement', 'nature_remuneration', 'archive'
1195 class TypeRevalorisationAdmin(reversion
.VersionAdmin
,
1196 DerniereModificationAdmin
, BaseAdmin
):
1197 ignore_duplicate_revisions
= True
1198 list_display
= ('nom', 'derniere_modification')
1200 (None, {'fields': ('nom',)}),
1204 class ValeurPointAdmin(reversion
.VersionAdmin
, DerniereModificationAdmin
,
1206 ignore_duplicate_revisions
= True
1208 '_devise_code', '_devise_nom', 'annee', 'implantation',
1209 'valeur', 'derniere_modification'
1211 list_filter
= ('annee', 'devise', 'implantation__zone_administrative', )
1213 (None, {'fields': ('valeur', 'devise', 'implantation', 'annee')}),
1216 def _devise_code(self
, obj
):
1217 return obj
.devise
.code
1218 _devise_code
.short_description
= "Code de la devise"
1220 def _devise_nom(self
, obj
):
1221 return obj
.devise
.nom
1222 _devise_nom
.short_description
= "Nom de la devise"
1225 class ImplantationProxyAdmin(BaseAdmin
):
1226 list_display
= ('nom', '_organigramme')
1229 def __init__(self
, *args
, **kwargs
):
1230 super(ImplantationProxyAdmin
, self
).__init__(*args
, **kwargs
)
1231 self
.list_display_links
= (None, )
1233 def has_add_permission(self
, obj
):
1236 def has_change_permission(self
, request
, obj
=None):
1237 user_groups
= [g
.name
for g
in request
.user
.groups
.all()]
1238 if groups
.CORRESPONDANT_RH
in user_groups
or \
1239 groups
.ADMINISTRATEURS
in user_groups
or \
1240 groups
.DIRECTEUR_DE_BUREAU
in user_groups
or \
1241 in_drh_or_admin(request
.user
):
1245 def _organigramme(self
, obj
):
1246 return '<a href="%s"><strong>Organigramme</strong></a>' % (
1247 reverse('rho_implantation', args
=(obj
.id,))
1249 _organigramme
.allow_tags
= True
1250 _organigramme
.short_description
= "Organigramme"
1253 class RegionProxyAdmin(BaseAdmin
):
1254 list_display
= ('nom', '_organigramme')
1257 def __init__(self
, *args
, **kwargs
):
1258 super(RegionProxyAdmin
, self
).__init__(*args
, **kwargs
)
1259 self
.list_display_links
= (None, )
1261 def has_add_permission(self
, obj
):
1264 def has_change_permission(self
, request
, obj
=None):
1265 user_groups
= [g
.name
for g
in request
.user
.groups
.all()]
1266 if groups
.CORRESPONDANT_RH
in user_groups
or \
1267 groups
.ADMINISTRATEURS
in user_groups
or \
1268 groups
.DIRECTEUR_DE_BUREAU
in user_groups
or \
1269 in_drh_or_admin(request
.user
):
1273 def _organigramme(self
, obj
):
1274 return """<a href="%s"><strong>Organigramme</strong></a>""" % (
1275 reverse('rho_region', args
=(obj
.id,))
1277 _organigramme
.allow_tags
= True
1278 _organigramme
.short_description
= "Organigramme"
1281 admin
.site
.register(rh
.Classement
, ClassementAdmin
)
1282 admin
.site
.register(rh
.Devise
, DeviseAdmin
)
1283 admin
.site
.register(rh
.Dossier
, DossierAdmin
)
1284 admin
.site
.register(EmployeProxy
, EmployeProxyAdmin
)
1285 admin
.site
.register(ServiceProxy
, ServiceProxyAdmin
)
1286 admin
.site
.register(rh
.Employe
, EmployeAdmin
)
1287 admin
.site
.register(rh
.CategorieEmploi
, CategorieEmploiAdmin
)
1288 admin
.site
.register(rh
.FamilleProfessionnelle
)
1289 admin
.site
.register(rh
.OrganismeBstg
, OrganismeBstgAdmin
)
1290 admin
.site
.register(rh
.Poste
, PosteAdmin
)
1291 admin
.site
.register(
1292 rh
.ResponsableImplantationProxy
, ResponsableImplantationAdmin
1294 admin
.site
.register(rh
.Service
, ServiceAdmin
)
1295 admin
.site
.register(rh
.Statut
, StatutAdmin
)
1296 admin
.site
.register(rh
.TauxChange
, TauxChangeAdmin
)
1297 admin
.site
.register(rh
.TypeContrat
, TypeContratAdmin
)
1298 admin
.site
.register(rh
.TypePoste
, TypePosteAdmin
)
1299 admin
.site
.register(rh
.TypeRemuneration
, TypeRemunerationAdmin
)
1300 admin
.site
.register(rh
.TypeRevalorisation
, TypeRevalorisationAdmin
)
1301 admin
.site
.register(rh
.ValeurPoint
, ValeurPointAdmin
)
1302 admin
.site
.register(ImplantationProxy
, ImplantationProxyAdmin
)
1303 admin
.site
.register(RegionProxy
, RegionProxyAdmin
)