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
30 def listing_par_defaut(model
, request
):
32 Teste si la requete provient de la même page.
34 if not 'HTTP_REFERER' in request
.META
.keys():
36 referer
= request
.META
['HTTP_REFERER']
37 referer
= "/".join(referer
.split('/')[3:])
38 referer
= "/%s" % referer
.split('?')[0]
39 change_list_view
= 'admin:%s_%s_changelist' % (
40 model
._meta
.app_label
,
41 model
.__name__
.lower(),)
42 return referer
!= reverse(change_list_view
)
44 class BaseAdmin(admin
.ModelAdmin
):
48 'css/admin_custom.css',
49 'jquery-autocomplete/jquery.autocomplete.css',
52 'https://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js',
53 'jquery-autocomplete/jquery.autocomplete.min.js',
57 # Admin pour reversion
59 class ArchivableAdmin(admin
.ModelAdmin
):
61 Admin pour les modèles archivables
63 list_filter
= ('archive', )
65 def queryset(self
, request
):
66 return self
.model
.avec_archives
.all()
68 def _archive(self
, obj
):
73 _archive
.short_description
= u
'Archivé'
74 _archive
.admin_order_field
= 'archive'
77 class RegionProxy(ref
.Region
):
78 """ Proxy utilisé pour les organigrammes par région """
82 verbose_name
= u
"Organigramme par région"
83 verbose_name_plural
= u
"Organigramme par région"
86 class ImplantationProxy(ref
.Implantation
):
87 """ Proxy utilisé pour les organigrammes par implantation """
91 verbose_name
= u
"Organigramme par implantations"
92 verbose_name_plural
= u
"Organigramme par implantations"
95 class ServiceProxy(rh
.Service
):
96 """ Proxy utilisé pour les organigrammes par service """
101 verbose_name
= u
"Organigramme par services"
102 verbose_name_plural
= u
"Organigramme par services"
105 class EmployeProxy(rh
.Employe
):
106 """ Proxy utilisé pour les organigrammes des employés """
110 verbose_name
= u
"Organigramme des employés"
111 verbose_name_plural
= u
"Organigramme des employés"
114 class DateRangeMixin(object):
115 prefixe_recherche_temporelle
= ""
117 def get_changelist(self
, request
, **kwargs
):
119 On filtre par défaut sur les items 'actifs'.
120 Le changelist plug le filtrage temporel.
122 if listing_par_defaut(self
.model
, request
):
123 params
= request
.GET
.copy()
124 params
.update({'statut': 'Actif'})
129 # Override of the InlineModelAdmin to support the link in the tabular inline
130 class LinkedInline(admin
.options
.InlineModelAdmin
):
131 template
= "admin/linked.html"
132 admin_model_path
= None
134 def __init__(self
, *args
):
135 super(LinkedInline
, self
).__init__(*args
)
136 if self
.admin_model_path
is None:
137 self
.admin_model_path
= self
.model
.__name__
.lower()
140 class ProtectRegionMixin(object):
142 def changelist_view(self
, request
, extra_context
=None):
144 On filtre par défaut sur la ZA du user connecté
146 if listing_par_defaut(self
.model
, request
):
147 if user_gere_obj_de_sa_region(request
.user
):
148 params
= request
.GET
.copy()
149 employe
= groups
.get_employe_from_user(request
.user
)
150 za
= employe
.implantation
.zone_administrative
.code
151 prefix_za
= "%s__code__exact" % self
.model
.prefix_implantation
152 params
.update({prefix_za
: za
})
154 return super(ProtectRegionMixin
, self
).changelist_view(request
, extra_context
)
156 def queryset(self
, request
):
157 qs
= super(ProtectRegionMixin
, self
).queryset(request
)
159 if in_drh_or_admin(request
.user
):
162 if user_gere_obj_de_sa_region(request
.user
):
163 region_user
= get_region_user(request
.user
)
164 q
= Q(**{self
.model
.prefix_implantation
: \
166 qs
= qs
.filter(q
).distinct()
170 def has_add_permission(self
, request
):
171 return user_can_add_obj(request
.user
)
173 def has_change_permission(self
, request
, obj
=None):
174 return user_can_change_obj(request
.user
, obj
) if obj
else True
176 def has_delete_permission(self
, request
, obj
=None):
177 return user_can_delete_obj(request
.user
, obj
) if obj
else True
180 class DerniereModificationAdmin(admin
.ModelAdmin
):
182 def queryset(self
, request
):
183 qs
= super(DerniereModificationAdmin
, self
).queryset(request
)
184 ct
= ContentType
.objects
.get_for_model(self
.model
)
185 db_table
= self
.model
._meta
.db_table
186 pk
= self
.model
._meta
.pk
.column
187 return qs
.extra(select
={
189 "SELECT action_time FROM django_admin_log "
190 "WHERE content_type_id = %d AND object_id = %s.%s "
191 "ORDER BY action_time DESC "
192 "LIMIT 1" % (ct
.id, db_table
, pk
),
196 "INNER JOIN django_admin_log l ON l.user_id = u.id "
197 "WHERE l.content_type_id = %d AND object_id = %s.%s "
198 "ORDER BY action_time DESC "
199 "LIMIT 1" % (ct
.id, db_table
, pk
),
202 def derniere_modification(self
, obj
):
204 if obj
.date_modification
:
205 text
+= obj
.date_modification
.strftime('%d-%m-%Y %H:%M')
206 if obj
.user_modification
:
207 text
+= ' par ' + obj
.user_modification
209 derniere_modification
.short_description
= u
'dernière modification'
210 derniere_modification
.admin_order_field
= 'date_modification'
215 class CommentaireInlineForm(forms
.ModelForm
):
217 def save(self
, commit
=True):
219 # Hack: reversion.VersionAdmin ne sauvegarde pas les champs qui ne
220 # sont pas explicitement dans le formulaire. Il plante cependant
221 # leur valeur dans `self.initial`. Ceci est un peu fragile. Si
222 # c'est possible, il serait plus approprié que Reversion se rende
223 # compte qu'il manque des champs.
224 instance
= super(CommentaireInlineForm
, self
).save(commit
=False)
225 if instance
.owner_id
is None and 'owner' in self
.initial
:
226 instance
.owner_id
= self
.initial
['owner']
227 if instance
.date_creation
is None and 'date_creation' in self
.initial
:
228 instance
.date_creation
= self
.initial
['date_creation']
235 class ReadOnlyInlineMixin(object):
237 def get_readonly_fields(self
, request
, obj
=None):
238 return [f
.name
for f
in self
.model
._meta
.fields
]
241 class AyantDroitInline(admin
.StackedInline
):
242 model
= rh
.AyantDroit
243 form
= AyantDroitForm
250 ('nom_affichage', 'genre'),
258 class AyantDroitCommentaireInline(admin
.TabularInline
):
259 readonly_fields
= ('owner',)
260 model
= rh
.AyantDroitCommentaire
262 form
= CommentaireInlineForm
265 class ContratInline(admin
.TabularInline
):
271 class DossierROInline(ReadOnlyInlineMixin
, LinkedInline
):
272 template
= "admin/rh/dossier/linked.html"
277 def has_add_permission(self
, request
=None):
280 def has_change_permission(self
, request
, obj
=None):
283 def has_delete_permission(self
, request
, obj
=None):
287 class DossierCommentaireInline(admin
.TabularInline
):
288 readonly_fields
= ('owner',)
289 model
= rh
.DossierCommentaire
291 form
= CommentaireInlineForm
294 class DossierPieceInline(admin
.TabularInline
):
295 model
= rh
.DossierPiece
299 class EmployeInline(admin
.TabularInline
):
303 class EmployeCommentaireInline(admin
.TabularInline
):
304 readonly_fields
= ('owner',)
305 model
= rh
.EmployeCommentaire
307 form
= CommentaireInlineForm
310 class EmployePieceInline(admin
.TabularInline
):
311 model
= rh
.EmployePiece
315 class PosteCommentaireInline(admin
.TabularInline
):
316 readonly_fields
= ('owner',)
317 model
= rh
.PosteCommentaire
319 form
= CommentaireInlineForm
322 class PosteFinancementInline(admin
.TabularInline
):
323 model
= rh
.PosteFinancement
326 class PostePieceInline(admin
.TabularInline
):
327 model
= rh
.PostePiece
330 class RemunerationInline(admin
.TabularInline
):
331 model
= rh
.Remuneration
335 class RemunerationROInline(ReadOnlyInlineMixin
, RemunerationInline
):
339 class TypePosteInline(admin
.TabularInline
):
343 class PosteComparaisonInline(admin
.TabularInline
):
344 model
= rh
.PosteComparaison
347 class ClassementAdmin(reversion
.VersionAdmin
, DerniereModificationAdmin
,
349 ignore_duplicate_revisions
= True
350 list_display
= ('_classement', 'derniere_modification')
352 (None, {'fields': ('type', 'echelon', 'degre', 'coefficient',)}),
355 def _classement(self
, obj
):
357 _classement
.short_description
= u
"Classement"
360 class DeviseAdmin(reversion
.VersionAdmin
, ArchivableAdmin
,
361 DerniereModificationAdmin
, BaseAdmin
):
362 ignore_duplicate_revisions
= True
364 'code', 'nom', '_archive', 'derniere_modification',
366 list_filter
= ('archive', )
368 (None, {'fields': ('code', 'nom', 'archive', )}),
372 class DossierAdmin(DateRangeMixin
, ProtectRegionMixin
, reversion
.VersionAdmin
,
373 AjaxSelect
, DerniereModificationAdmin
, BaseAdmin
):
374 change_list_template
= "admin/rh/dossier/change_list.html"
375 ignore_duplicate_revisions
= True
376 alphabet_filter
= 'employe__nom'
384 'poste__nom_feminin',
385 'poste__implantation__nom',
393 '_zone_administrative',
397 'derniere_modification',
400 list_display_links
= ('_nom',)
402 'poste__implantation__zone_administrative',
403 'poste__implantation',
404 'poste__type_poste__categorie_emploi',
406 'rh_contrats__type_contrat',
409 inlines
= (DossierPieceInline
, ContratInline
,
411 DossierCommentaireInline
,
420 'organisme_bstg',)}),
425 'remplacement_de', )}),
429 ('regime_travail', 'regime_travail_nb_heure_semaine'),)}),
430 ('Occupation du Poste par cet Employe', {
431 'fields': (('date_debut', 'date_fin'), )}
434 form
= make_ajax_form(rh
.Dossier
, {
435 'employe': 'employes',
437 'remplacement_de': 'dossiers',
438 }, superclass
=DossierForm
)
440 def lookup_allowed(self
, key
, value
):
442 'employe__nom__istartswith',
443 'poste__implantation__zone_administrative__code__exact',
444 'poste__implantation__id__exact',
445 'poste__type_poste__id__exact',
446 'poste__type_poste__categorie_emploi__id__exact',
447 'rh_contrats__type_contrat__id__exact',
455 _id
.short_description
= u
"#"
456 _id
.admin_order_field
= "id"
458 def _apercu(self
, d
):
459 apercu_link
= u
"""<a title="Aperçu du dossier"
460 onclick="return showAddAnotherPopup(this);"
462 <img src="%simg/dossier-apercu.png" />
464 (reverse('dossier_apercu', args
=(d
.id,)),
468 _apercu
.allow_tags
= True
469 _apercu
.short_description
= u
""
473 _nom
.allow_tags
= True
474 _nom
.short_description
= u
"Dossier"
476 def _employe(self
, obj
):
477 employe
= obj
.employe
478 view_link
= reverse('employe_apercu', args
=(employe
.id,))
479 edit_link
= reverse('admin:rh_employe_change', args
=(employe
.id,))
481 view
= u
"""<a href="%s"
482 title="Aperçu l'employé"
483 onclick="return showAddAnotherPopup(this);">
484 <img src="%simg/employe-apercu.png" />
485 </a>""" % (view_link
, settings
.STATIC_URL
,)
486 return u
"""%s<a href='%s' style="%s;">%s</a>""" % \
487 (view
, edit_link
, style
, employe
)
488 _employe
.allow_tags
= True
489 _employe
.short_description
= u
"Employé"
490 _employe
.admin_order_field
= "employe__nom"
492 def _poste(self
, dossier
):
493 link
= u
"""<a title="Aperçu du poste"
494 onclick="return showAddAnotherPopup(this);"
495 href='%s'><img src="%simg/poste-apercu.png" />
497 <a href="%s" title="Modifier le poste">%s [%d]</a>""" % \
498 (reverse('poste_apercu', args
=(dossier
.poste
.id,)),
500 reverse('admin:rh_poste_change', args
=(dossier
.poste
.id,)),
505 _poste
.allow_tags
= True
506 _poste
.short_description
= u
'Poste'
507 _poste
.admin_order_field
= 'poste__nom'
509 def _zone_administrative(self
, obj
):
510 return obj
.poste
.implantation
.zone_administrative
.code
511 _zone_administrative
.short_description
= u
"Zone administrative"
512 _zone_administrative
.admin_order_field
= 'poste__implantation__zone_administrative__code'
514 def _implantation(self
, obj
):
515 return obj
.poste
.implantation
.nom
516 _implantation
.short_description
= u
"Implantation"
517 _implantation
.admin_order_field
= 'poste__implantation__nom'
519 def _date_debut(self
, obj
):
520 return date(obj
.date_debut
)
522 _date_debut
.short_description
= u
'Début'
523 _date_debut
.admin_order_field
= 'date_debut'
525 def _date_fin(self
, obj
):
526 return date(obj
.date_fin
)
527 _date_fin
.short_description
= u
'Fin'
528 _date_fin
.admin_order_field
= 'date_fin'
530 def _date_modification(self
, obj
):
531 return date(obj
.date_modification
) \
532 if obj
.date_modification
is not None else "(aucune)"
533 _date_modification
.short_description
= u
'date modification'
534 _date_modification
.admin_order_field
= 'date_modification'
538 dossiers_dae
= d
.dossiers_dae
.all()
539 if len(dossiers_dae
) > 0:
540 dossier_dae
= dossiers_dae
[0]
541 apercu_link
= u
"""<a title="Aperçu du dossier"
542 onclick="return showAddAnotherPopup(this);"
544 <img src="%simg/loupe.png" />
546 (reverse('embauche_consulter', args
=(dossier_dae
.id,)),
550 _dae
.allow_tags
= True
551 _dae
.short_description
= u
"DAE"
553 def save_formset(self
, request
, form
, formset
, change
):
554 instances
= formset
.save(commit
=False)
555 for instance
in instances
:
556 if instance
.__class__
== rh
.DossierCommentaire
:
557 instance
.owner
= request
.user
558 instance
.date_creation
= datetime
.datetime
.now()
562 class EmployeAdminBase(DateRangeMixin
, ProtectRegionMixin
,
563 DerniereModificationAdmin
, BaseAdmin
):
564 prefixe_recherche_temporelle
= "rh_dossiers__"
565 alphabet_filter
= 'nom'
566 DEFAULT_ALPHABET
= u
'ABCDEFGHIJKLMNOPQRSTUVWXYZ'
568 'id', 'nom', 'prenom', 'nom_affichage',
569 'rh_dossiers__poste__nom',
570 'rh_dossiers__poste__nom_feminin'
573 form
= EmployeAdminForm
575 '_id', '_apercu', '_nom', '_dossiers_postes',
576 #'_zone_administrative',
579 'derniere_modification'
581 list_display_links
= ('_nom',)
583 'rh_dossiers__poste__implantation__zone_administrative',
584 'rh_dossiers__poste__implantation', 'nb_postes'
587 AyantDroitInline
, DossierROInline
, EmployePieceInline
,
588 EmployeCommentaireInline
594 ('nom_affichage', 'genre'),
599 ('Informations personnelles', {
600 'fields': ('situation_famille', 'date_entree', )
602 ('Coordonnées personnelles', {
604 ('tel_domicile', 'tel_cellulaire'),
605 ('adresse', 'ville'),
606 ('code_postal', 'province'),
615 _id
.short_description
= u
"#"
616 _id
.admin_order_field
= "id"
618 def _apercu(self
, obj
):
619 return u
"""<a title="Aperçu de l'employé"
620 onclick="return showAddAnotherPopup(this);"
622 <img src="%simg/employe-apercu.png" />
624 (reverse('employe_apercu', args
=(obj
.id,)), settings
.STATIC_URL
)
625 _apercu
.allow_tags
= True
626 _apercu
.short_description
= u
""
629 edit_link
= reverse('admin:rh_employe_change', args
=(obj
.id,))
630 return u
"""<a href='%s'><strong>%s</strong></a>""" % \
631 (edit_link
, "%s %s" % (obj
.nom
.upper(), obj
.prenom
))
632 _nom
.allow_tags
= True
633 _nom
.short_description
= u
"Employé"
634 _nom
.admin_order_field
= "nom"
636 def _zone_administrative(self
, obj
):
638 d
= rh
.Dossier
.objects
.filter(employe
=obj
.id, principal
=True)[0]
639 zone
= d
.poste
.implantation
.zone_administrative
.code
643 _zone_administrative
.short_description
= u
"Zone administrative"
645 def _implantation(self
, obj
):
647 d
= rh
.Dossier
.objects
.filter(employe
=obj
.id, principal
=True)[0]
648 implantation
= d
.poste
.implantation
.nom
652 _implantation
.short_description
= u
"Implantation"
654 def _dossiers_postes(self
, obj
):
656 for d
in obj
.rh_dossiers
.all().order_by('-date_debut'):
659 if d
.date_fin
is not None and d
.date_fin
< datetime
.date
.today():
660 link_style
= u
' style="color:#666;"'
661 list_style
= u
' style="color:grey;"'
663 dossier
= u
"""<a title="Aperçu du dossier"
665 onclick="return showAddAnotherPopup(this);"
666 title="Aperçu du dossier">
667 <img src="%simg/dossier-apercu.png" />
669 <a href="%s"%s>Dossier</a>
671 (reverse('dossier_apercu', args
=(d
.id,)),
673 reverse('admin:rh_dossier_change', args
=(d
.id,)),
676 poste
= u
"""<a title="Aperçu du poste"
678 onclick="return showAddAnotherPopup(this);"
679 title="Aperçu du poste">
680 <img src="%simg/poste-apercu.png" />
682 <a href="%s"%s>%s [%d]</a>
684 (reverse('poste_apercu', args
=(d
.poste
.id,)),
686 reverse('admin:rh_poste_change', args
=(d
.poste
.id,)),
691 link
= u
"""<li%s>%s %s</li>""" % \
692 (list_style
, dossier
, poste
)
695 return "<ul>%s</ul>" % "\n".join(l
)
696 _dossiers_postes
.allow_tags
= True
697 _dossiers_postes
.short_description
= u
"Dossiers et postes"
699 def _date_modification(self
, obj
):
700 return date(obj
.date_modification
) \
701 if obj
.date_modification
is not None else "(aucune)"
702 _date_modification
.short_description
= u
'date modification'
703 _date_modification
.admin_order_field
= 'date_modification'
705 def queryset(self
, request
):
706 qs
= super(EmployeAdminBase
, self
).queryset(request
)
707 return qs
.select_related(depth
=1).order_by('nom')
709 def save_formset(self
, request
, form
, formset
, change
):
710 instances
= formset
.save(commit
=False)
711 for instance
in instances
:
712 if instance
.__class__
== rh
.EmployeCommentaire
:
713 instance
.owner
= request
.user
714 instance
.date_creation
= datetime
.datetime
.now()
718 class EmployeAdmin(reversion
.VersionAdmin
, EmployeAdminBase
):
719 change_list_template
= "admin/rh/employe/change_list.html"
720 ignore_duplicate_revisions
= True
723 class EmployeProxyAdmin(EmployeAdminBase
):
724 list_display
= ('_id', '_apercu', '_nom', '_organigramme')
728 def __init__(self
, *args
, **kwargs
):
729 super(EmployeProxyAdmin
, self
).__init__(*args
, **kwargs
)
730 self
.list_display_links
= (None, )
732 def queryset(self
, request
):
733 qs
= super(ProtectRegionMixin
, self
).queryset(request
)
735 if in_drh_or_admin(request
.user
) or \
736 user_gere_obj_de_sa_region(request
.user
):
741 def has_add_permission(self
, obj
):
744 def has_change_permission(self
, request
, obj
=None):
745 user_groups
= [g
.name
for g
in request
.user
.groups
.all()]
746 if groups
.CORRESPONDANT_RH
in user_groups
or \
747 groups
.ADMINISTRATEURS
in user_groups
or \
748 groups
.DIRECTEUR_DE_BUREAU
in user_groups
or \
749 in_drh_or_admin(request
.user
):
753 def _organigramme(self
, obj
):
755 for d
in rh
.Dossier
.objects
.filter(
756 Q(date_fin__gt
=datetime
.date
.today()) |
Q(date_fin
=None),
757 Q(date_debut__lt
=datetime
.date
.today()) |
Q(date_debut
=None),
761 u
'Organigramme, niveau: ' \
762 u
'<input type="text" id="level_%s" ' \
763 u
'style="width:30px;height:15px;" /> ' \
764 u
'<input type="button" value="Générer" ' \
765 u
"""onclick="window.location='%s' + """ \
766 u
"""document.getElementById('level_%s').value" />""" % (
768 reverse('rho_employe_sans_niveau', args
=(d
.poste
.id,)),
771 link
= u
"""<li>%s [%s]:<br />%s</li>""" % (
777 return "<ul>%s</ul>" % "\n".join(l
)
779 _organigramme
.allow_tags
= True
780 _organigramme
.short_description
= "Organigramme"
783 class CategorieEmploiAdmin(reversion
.VersionAdmin
,
784 DerniereModificationAdmin
, BaseAdmin
):
785 ignore_duplicate_revisions
= True
786 list_display
= ('nom', 'derniere_modification')
787 inlines
= (TypePosteInline
,)
789 (None, {'fields': ('nom', )}),
793 class OrganismeBstgAdmin(reversion
.VersionAdmin
, DerniereModificationAdmin
,
795 ignore_duplicate_revisions
= True
796 search_fields
= ('nom',)
797 list_display
= ('nom', 'type', 'pays', 'derniere_modification')
798 list_filter
= ('type', )
799 inlines
= (DossierROInline
,)
801 (None, {'fields': ('nom', 'type', 'pays',)}),
805 class PosteAdmin(DateRangeMixin
, ProtectRegionMixin
, reversion
.VersionAdmin
,
806 AjaxSelect
, DerniereModificationAdmin
, BaseAdmin
):
807 change_list_template
= "admin/rh/poste/change_list.html"
808 ignore_duplicate_revisions
= True
809 form
= make_ajax_form(rh
.Poste
, {
810 'implantation': 'implantations',
811 'type_poste': 'typepostes',
812 'responsable': 'postes',
813 'valeur_point_min': 'valeurpoints',
814 'valeur_point_max': 'valeurpoints',
816 alphabet_filter
= 'nom'
821 'implantation__zone_administrative__code',
822 'implantation__zone_administrative__nom',
823 'rh_dossiers__employe__id',
824 'rh_dossiers__employe__nom',
825 'rh_dossiers__employe__prenom',
828 '_id', '_apercu', '_nom', '_occupe_par', 'implantation', '_service',
829 '_responsable', 'date_debut', 'date_fin', 'derniere_modification',
833 'implantation__zone_administrative',
837 'type_poste__categorie_emploi',
838 'type_poste__famille_professionnelle',
841 list_display_links
= ('_nom',)
844 ('nom', 'nom_feminin'),
854 'regime_travail_nb_heure_semaine'),
858 'fields': (('local', 'expatrie', 'mise_a_disposition', 'appel'),)}
861 'fields': (('classement_min',
874 ('Comparatifs de rémunération', {
875 'fields': ('devise_comparaison',
876 ('comp_locale_min', 'comp_locale_max'),
877 ('comp_universite_min', 'comp_universite_max'),
878 ('comp_fonctionpub_min', 'comp_fonctionpub_max'),
879 ('comp_ong_min', 'comp_ong_max'),
880 ('comp_autre_min', 'comp_autre_max'))}
883 'fields': ('justification',)}
885 ('Autres Méta-données', {
886 'fields': ('date_debut', 'date_fin')}
890 inlines
= (PosteFinancementInline
,
893 PosteComparaisonInline
,
894 PosteCommentaireInline
, )
896 def lookup_allowed(self
, key
, value
):
898 'date_debut__gte', 'date_debut__isnull', 'date_fin__lte',
899 'date_fin__isnull', 'implantation__zone_administrative__code__exact',
900 'implantation__id__exact', 'type_poste__id__exact',
901 'type_poste__categorie_emploi__id__exact', 'service__id__exact',
902 'service__isnull', 'vacant__exact', 'vacant__isnull',
903 ) or super(PosteAdmin
, self
).lookup_allowed(key
, value
)
907 _id
.short_description
= '#'
908 _id
.admin_order_field
= 'id'
910 def _apercu(self
, poste
):
911 view_link
= u
"""<a onclick="return showAddAnotherPopup(this);"
912 title="Aperçu du poste"
914 <img src="%simg/poste-apercu.png" />
916 (reverse('poste_apercu', args
=(poste
.id,)),
917 settings
.STATIC_URL
,)
919 _apercu
.allow_tags
= True
920 _apercu
.short_description
= ''
922 def _nom(self
, poste
):
923 return """<a href="%s">%s</a>""" % \
924 (reverse('admin:rh_poste_change', args
=(poste
.id,)),
926 _nom
.allow_tags
= True
927 _nom
.short_description
= u
'Poste'
928 _nom
.admin_order_field
= 'nom'
930 def _occupe_par(self
, obj
):
931 """Formatte la méthode Poste.occupe_par() pour l'admin"""
933 if obj
.date_fin
is not None and obj
.date_fin
< datetime
.date
.today():
935 employes
= obj
.occupe_par()
939 link
= u
"""<a href='%s'
940 title='Aperçu de l\'employé'
941 onclick='return showAddAnotherPopup(this)'>
942 <img src='%simg/employe-apercu.png' />
944 <a href='%s'>%s</a>""" % \
945 (reverse('employe_apercu', args
=(e
.id,)),
947 reverse('admin:rh_employe_change', args
=(e
.id,)),
950 output
= "\n<br />".join(l
)
952 _occupe_par
.allow_tags
= True
953 _occupe_par
.short_description
= "Occupé par"
955 def _zone_administrative(self
, poste
):
956 return poste
.implantation
.zone_administrative
.code
957 _zone_administrative
.short_description
= 'Zone administrative'
958 _zone_administrative
.admin_order_field
= 'implantation__zone_administrative__code'
960 def _implantation(self
, poste
):
961 return poste
.implantation
.nom
962 _implantation
.short_description
= 'Implantation'
963 _implantation
.admin_order_field
= 'implantation'
965 def _service(self
, obj
):
967 _service
.short_description
= 'Service'
968 _service
.allow_tags
= True
970 def _responsable(self
, obj
):
972 responsable
= u
"""<a href="%s"
973 onclick="return showAddAnotherPopup(this)">
974 <img src="%simg/poste-apercu.png"
975 title="Aperçu du poste" />
977 <a href="%s">%s [%d]</a>
979 (reverse('poste_apercu', args
=(obj
.responsable
.id,)),
981 reverse('admin:rh_poste_change', args
=(obj
.responsable
.id,)),
988 dossier
= obj
.responsable
.rh_dossiers
.all() \
989 .order_by('-date_debut')[0]
990 employe_id
= dossier
.employe
.id
991 employe_html
= u
"""<br />
993 onclick="return showAddAnotherPopup(this)">
994 <img src="%simg/employe-apercu.png"
995 title="Aperçu de l'employé">
997 <a href="%s">%s</a>""" % \
998 (reverse('employe_apercu', args
=(employe_id
,)),
1000 reverse('admin:rh_employe_change', args
=(employe_id
,)),
1005 return "%s %s" % (responsable
, employe_html
)
1006 _responsable
.short_description
= 'Responsable'
1007 _responsable
.allow_tags
= True
1009 def _date_debut(self
, obj
):
1010 return date_format(obj
.date_debut
)
1011 _date_debut
.short_description
= u
'Début'
1012 _date_debut
.admin_order_field
= 'date_debut'
1014 def _date_fin(self
, obj
):
1015 return date_format(obj
.date_fin
)
1016 _date_fin
.short_description
= u
'Fin'
1017 _date_fin
.admin_order_field
= 'date_fin'
1019 def _dae(self
, poste
):
1021 postes_dae
= poste
.postes_dae
.all()
1022 if len(postes_dae
) > 0:
1023 poste_dae
= postes_dae
[0]
1025 u
'<a title="Aperçu du dossier" href="%s" ' \
1026 u
'onclick="return showAddAnotherPopup(this);">' \
1027 u
'<img src="%simg/loupe.png" /></a>' % (reverse(
1028 'poste_consulter', args
=("dae-%s" % poste_dae
.id,)
1029 ), settings
.STATIC_URL
)
1031 _dae
.allow_tags
= True
1032 _dae
.short_description
= u
"DAE"
1034 def save_formset(self
, request
, form
, formset
, change
):
1035 instances
= formset
.save(commit
=False)
1036 for instance
in instances
:
1037 if instance
.__class__
== rh
.PosteCommentaire
:
1038 instance
.owner
= request
.user
1039 instance
.date_creation
= datetime
.datetime
.now()
1044 class ResponsableInline(admin
.TabularInline
):
1045 model
= rh
.ResponsableImplantation
1047 fk_name
= "implantation"
1048 form
= ResponsableInlineForm
1051 class ResponsableImplantationAdmin(BaseAdmin
):
1054 inlines
= (ResponsableInline
, )
1055 list_filter
= ('zone_administrative', 'statut', )
1056 list_display
= ('_zone_administrative', '_nom', 'statut', '_responsable', )
1057 list_display_links
= ('_nom',)
1059 readonly_fields
= ('nom', )
1062 'responsable__employe__id',
1063 'responsable__employe__nom',
1064 'responsable__employe__prenom',
1067 inlines
= (ResponsableInline
, )
1069 def _zone_administrative(self
, obj
):
1070 return obj
.zone_administrative
.code
1071 _zone_administrative
.short_description
= u
"Zone administrative"
1072 _zone_administrative
.admin_order_field
= 'zone_administrative__code'
1074 def _nom(self
, obj
):
1076 _nom
.short_description
= u
"Implantation"
1077 _nom
.admin_order_field
= 'nom'
1079 def _responsable(self
, obj
):
1081 employe
= obj
.responsable
.employe
1082 dossiers
= employe
.dossiers_encours()
1083 if len(dossiers
) == 0:
1084 return u
"<span style='color: red;'>%s %s </span>" % (
1085 employe
, u
"sans dossier actif")
1089 if obj
.statut
in (1, 2): # ouverte, ouverture imminente
1090 css
= "style='color: red;'"
1093 return u
"<span %s>Pas de responsable</span>" % css
1094 _responsable
.allow_tags
= True
1095 _responsable
.short_description
= u
"Responsable"
1096 _responsable
.admin_order_field
= 'responsable__employe__nom'
1098 def has_add_permission(self
, request
=None):
1101 def has_change_permission(self
, request
, obj
=None):
1102 return in_drh_or_admin(request
.user
)
1104 def has_delete_permission(self
, request
, obj
=None):
1108 class ServiceAdminBase(ArchivableAdmin
, DerniereModificationAdmin
, BaseAdmin
):
1109 list_display
= ('nom', '_archive', 'derniere_modification')
1110 list_filter
= ('archive', )
1112 (None, {'fields': ('nom', 'archive')}),
1116 class ServiceAdmin(reversion
.VersionAdmin
, ServiceAdminBase
):
1117 ignore_duplicate_revisions
= True
1120 class ServiceProxyAdmin(ServiceAdminBase
):
1121 list_display
= ('nom', '_organigramme', '_archive', )
1124 def __init__(self
, *args
, **kwargs
):
1125 super(ServiceProxyAdmin
, self
).__init__(*args
, **kwargs
)
1126 self
.list_display_links
= (None, )
1128 def queryset(self
, request
):
1129 return super(ServiceProxyAdmin
, self
).queryset(request
) \
1130 .annotate(num_postes
=Count('rh_postes')) \
1131 .filter(num_postes__gt
=0)
1133 def has_add_permission(self
, obj
):
1136 def has_change_permission(self
, request
, obj
=None):
1137 user_groups
= [g
.name
for g
in request
.user
.groups
.all()]
1138 if groups
.CORRESPONDANT_RH
in user_groups
or \
1139 groups
.ADMINISTRATEURS
in user_groups
or \
1140 groups
.DIRECTEUR_DE_BUREAU
in user_groups
or \
1141 in_drh_or_admin(request
.user
):
1145 def _organigramme(self
, obj
):
1146 return """<a href="%s"><strong>Organigramme</strong></a>""" % \
1147 (reverse('rho_service', args
=(obj
.id,)))
1148 _organigramme
.allow_tags
= True
1149 _organigramme
.short_description
= "Organigramme"
1152 class StatutAdmin(reversion
.VersionAdmin
, DerniereModificationAdmin
,
1154 ignore_duplicate_revisions
= True
1155 list_display
= ('code', 'nom', 'derniere_modification')
1158 'fields': ('code', 'nom', ),
1163 class TauxChangeAdmin(reversion
.VersionAdmin
, DerniereModificationAdmin
,
1165 ignore_duplicate_revisions
= True
1166 list_display
= ('taux', 'devise', 'annee', 'derniere_modification')
1167 list_filter
= ('devise',)
1170 'fields': ('taux', 'devise', 'annee', ),
1175 class TypeContratAdmin(reversion
.VersionAdmin
, DerniereModificationAdmin
,
1177 ignore_duplicate_revisions
= True
1178 list_display
= ('nom', 'nom_long', 'derniere_modification')
1181 'fields': ('nom', 'nom_long', ),
1186 class TypePosteAdmin(reversion
.VersionAdmin
, DerniereModificationAdmin
,
1188 ignore_duplicate_revisions
= True
1189 search_fields
= ('nom', 'nom_feminin', )
1190 list_display
= ('nom', 'categorie_emploi', 'derniere_modification')
1191 list_filter
= ('categorie_emploi', 'famille_professionnelle')
1195 'nom', 'nom_feminin', 'is_responsable', 'categorie_emploi',
1196 'famille_professionnelle',
1202 class TypeRemunerationAdmin(reversion
.VersionAdmin
, ArchivableAdmin
,
1203 DerniereModificationAdmin
, BaseAdmin
):
1204 ignore_duplicate_revisions
= True
1206 'nom', 'type_paiement', 'nature_remuneration', '_archive',
1207 'derniere_modification'
1209 list_filter
= ('archive', )
1213 'nom', 'type_paiement', 'nature_remuneration', 'archive'
1219 class TypeRevalorisationAdmin(reversion
.VersionAdmin
,
1220 DerniereModificationAdmin
, BaseAdmin
):
1221 ignore_duplicate_revisions
= True
1222 list_display
= ('nom', 'derniere_modification')
1224 (None, {'fields': ('nom',)}),
1228 class ValeurPointAdmin(reversion
.VersionAdmin
, DerniereModificationAdmin
,
1230 ignore_duplicate_revisions
= True
1232 '_devise_code', '_devise_nom', 'annee', 'implantation',
1233 'valeur', 'derniere_modification'
1235 list_filter
= ('annee', 'devise', 'implantation__zone_administrative', )
1237 (None, {'fields': ('valeur', 'devise', 'implantation', 'annee')}),
1240 def _devise_code(self
, obj
):
1241 return obj
.devise
.code
1242 _devise_code
.short_description
= "Code de la devise"
1244 def _devise_nom(self
, obj
):
1245 return obj
.devise
.nom
1246 _devise_nom
.short_description
= "Nom de la devise"
1249 class ImplantationProxyAdmin(BaseAdmin
):
1250 list_display
= ('nom', '_organigramme')
1253 def __init__(self
, *args
, **kwargs
):
1254 super(ImplantationProxyAdmin
, self
).__init__(*args
, **kwargs
)
1255 self
.list_display_links
= (None, )
1257 def has_add_permission(self
, obj
):
1260 def has_change_permission(self
, request
, obj
=None):
1261 user_groups
= [g
.name
for g
in request
.user
.groups
.all()]
1262 if groups
.CORRESPONDANT_RH
in user_groups
or \
1263 groups
.ADMINISTRATEURS
in user_groups
or \
1264 groups
.DIRECTEUR_DE_BUREAU
in user_groups
or \
1265 in_drh_or_admin(request
.user
):
1269 def _organigramme(self
, obj
):
1270 return '<a href="%s"><strong>Organigramme</strong></a>' % (
1271 reverse('rho_implantation', args
=(obj
.id,))
1273 _organigramme
.allow_tags
= True
1274 _organigramme
.short_description
= "Organigramme"
1277 class RegionProxyAdmin(BaseAdmin
):
1278 list_display
= ('nom', '_organigramme')
1281 def __init__(self
, *args
, **kwargs
):
1282 super(RegionProxyAdmin
, self
).__init__(*args
, **kwargs
)
1283 self
.list_display_links
= (None, )
1285 def has_add_permission(self
, obj
):
1288 def has_change_permission(self
, request
, obj
=None):
1289 user_groups
= [g
.name
for g
in request
.user
.groups
.all()]
1290 if groups
.CORRESPONDANT_RH
in user_groups
or \
1291 groups
.ADMINISTRATEURS
in user_groups
or \
1292 groups
.DIRECTEUR_DE_BUREAU
in user_groups
or \
1293 in_drh_or_admin(request
.user
):
1297 def _organigramme(self
, obj
):
1298 return """<a href="%s"><strong>Organigramme</strong></a>""" % (
1299 reverse('rho_region', args
=(obj
.id,))
1301 _organigramme
.allow_tags
= True
1302 _organigramme
.short_description
= "Organigramme"
1305 admin
.site
.register(rh
.Classement
, ClassementAdmin
)
1306 admin
.site
.register(rh
.Devise
, DeviseAdmin
)
1307 admin
.site
.register(rh
.Dossier
, DossierAdmin
)
1308 admin
.site
.register(EmployeProxy
, EmployeProxyAdmin
)
1309 admin
.site
.register(ServiceProxy
, ServiceProxyAdmin
)
1310 admin
.site
.register(rh
.Employe
, EmployeAdmin
)
1311 admin
.site
.register(rh
.CategorieEmploi
, CategorieEmploiAdmin
)
1312 admin
.site
.register(rh
.FamilleProfessionnelle
)
1313 admin
.site
.register(rh
.OrganismeBstg
, OrganismeBstgAdmin
)
1314 admin
.site
.register(rh
.Poste
, PosteAdmin
)
1315 admin
.site
.register(
1316 rh
.ResponsableImplantationProxy
, ResponsableImplantationAdmin
1318 admin
.site
.register(rh
.Service
, ServiceAdmin
)
1319 admin
.site
.register(rh
.Statut
, StatutAdmin
)
1320 admin
.site
.register(rh
.TauxChange
, TauxChangeAdmin
)
1321 admin
.site
.register(rh
.TypeContrat
, TypeContratAdmin
)
1322 admin
.site
.register(rh
.TypePoste
, TypePosteAdmin
)
1323 admin
.site
.register(rh
.TypeRemuneration
, TypeRemunerationAdmin
)
1324 admin
.site
.register(rh
.TypeRevalorisation
, TypeRevalorisationAdmin
)
1325 admin
.site
.register(rh
.ValeurPoint
, ValeurPointAdmin
)
1326 admin
.site
.register(ImplantationProxy
, ImplantationProxyAdmin
)
1327 admin
.site
.register(RegionProxy
, RegionProxyAdmin
)