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 get_region_user
, \
21 user_gere_obj_de_sa_region
, \
23 user_can_change_obj
, \
26 import project
.rh
.models
as rh
27 from project
.rh
.forms
import \
28 ContratForm
, AyantDroitForm
, EmployeAdminForm
, AjaxSelect
, DossierForm
29 from project
.rh
.change_list
import ChangeList
30 from project
.rh
.forms
import ContratForm
, AyantDroitForm
, EmployeAdminForm
, \
31 AjaxSelect
, DossierForm
, ResponsableInlineForm
34 class BaseAdmin(admin
.ModelAdmin
):
38 'css/admin_custom.css',
39 'jquery-autocomplete/jquery.autocomplete.css',
42 'https://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js',
43 'jquery-autocomplete/jquery.autocomplete.min.js',
46 # Admin pour reversion
48 class ArchivableAdmin(admin
.ModelAdmin
):
50 Admin pour les modèles archivables
52 list_filter
= ('archive', )
54 def queryset(self
, request
):
55 return self
.model
.avec_archives
.all()
57 def _archive(self
, obj
):
62 _archive
.short_description
= u
'Archivé'
63 _archive
.admin_order_field
= 'archive'
66 class RegionProxy(ref
.Region
):
67 """ Proxy utilisé pour les organigrammes par région """
71 verbose_name
= u
"Organigramme par région"
72 verbose_name_plural
= u
"Organigramme par région"
75 class ImplantationProxy(ref
.Implantation
):
76 """ Proxy utilisé pour les organigrammes par implantation """
80 verbose_name
= u
"Organigramme par implantations"
81 verbose_name_plural
= u
"Organigramme par implantations"
84 class ServiceProxy(rh
.Service
):
85 """ Proxy utilisé pour les organigrammes par service """
90 verbose_name
= u
"Organigramme par services"
91 verbose_name_plural
= u
"Organigramme par services"
94 class EmployeProxy(rh
.Employe
):
95 """ Proxy utilisé pour les organigrammes des employés """
99 verbose_name
= u
"Organigramme des employés"
100 verbose_name_plural
= u
"Organigramme des employés"
103 class DateRangeMixin(object):
104 prefixe_recherche_temporelle
= ""
106 def get_changelist(self
, request
, **kwargs
):
107 if 'HTTP_REFERER' in request
.META
.keys():
108 referer
= request
.META
['HTTP_REFERER']
109 referer
= "/".join(referer
.split('/')[3:])
110 referer
= "/%s" % referer
.split('?')[0]
111 change_list_view
= 'admin:%s_%s_changelist' % (
112 self
.model
._meta
.app_label
,
113 self
.model
.__name__
.lower(),)
114 if referer
!= reverse(change_list_view
):
115 params
= request
.GET
.copy()
116 params
.update({'statut': 'Actif'})
121 # Override of the InlineModelAdmin to support the link in the tabular inline
122 class LinkedInline(admin
.options
.InlineModelAdmin
):
123 template
= "admin/linked.html"
124 admin_model_path
= None
126 def __init__(self
, *args
):
127 super(LinkedInline
, self
).__init__(*args
)
128 if self
.admin_model_path
is None:
129 self
.admin_model_path
= self
.model
.__name__
.lower()
132 class ProtectRegionMixin(object):
134 def queryset(self
, request
):
135 qs
= super(ProtectRegionMixin
, self
).queryset(request
)
137 if in_drh_or_admin(request
.user
):
140 if user_gere_obj_de_sa_region(request
.user
):
141 region_user
= get_region_user(request
.user
)
142 q
= Q(**{self
.model
.prefix_implantation
: \
144 qs
= qs
.filter(q
).distinct()
148 def has_add_permission(self
, request
):
149 return user_can_add_obj(request
.user
)
151 def has_change_permission(self
, request
, obj
=None):
152 return user_can_change_obj(request
.user
, obj
) if obj
else True
154 def has_delete_permission(self
, request
, obj
=None):
155 return user_can_delete_obj(request
.user
, obj
) if obj
else True
158 class DerniereModificationAdmin(admin
.ModelAdmin
):
160 def queryset(self
, request
):
161 qs
= super(DerniereModificationAdmin
, self
).queryset(request
)
162 ct
= ContentType
.objects
.get_for_model(self
.model
)
163 db_table
= self
.model
._meta
.db_table
164 pk
= self
.model
._meta
.pk
.column
165 return qs
.extra(select
={
167 "SELECT action_time FROM django_admin_log "
168 "WHERE content_type_id = %d AND object_id = %s.%s "
169 "ORDER BY action_time DESC "
170 "LIMIT 1" % (ct
.id, db_table
, pk
),
174 "INNER JOIN django_admin_log l ON l.user_id = u.id "
175 "WHERE l.content_type_id = %d AND object_id = %s.%s "
176 "ORDER BY action_time DESC "
177 "LIMIT 1" % (ct
.id, db_table
, pk
),
180 def derniere_modification(self
, obj
):
182 if obj
.date_modification
:
183 text
+= obj
.date_modification
.strftime('%d-%m-%Y %H:%M')
184 if obj
.user_modification
:
185 text
+= ' par ' + obj
.user_modification
187 derniere_modification
.short_description
= u
'dernière modification'
188 derniere_modification
.admin_order_field
= 'date_modification'
193 class CommentaireInlineForm(forms
.ModelForm
):
195 def save(self
, commit
=True):
197 # Hack: reversion.VersionAdmin ne sauvegarde pas les champs qui ne
198 # sont pas explicitement dans le formulaire. Il plante cependant
199 # leur valeur dans `self.initial`. Ceci est un peu fragile. Si
200 # c'est possible, il serait plus approprié que Reversion se rende
201 # compte qu'il manque des champs.
202 instance
= super(CommentaireInlineForm
, self
).save(commit
=False)
203 if instance
.owner_id
is None and 'owner' in self
.initial
:
204 instance
.owner_id
= self
.initial
['owner']
205 if instance
.date_creation
is None and 'date_creation' in self
.initial
:
206 instance
.date_creation
= self
.initial
['date_creation']
213 class ReadOnlyInlineMixin(object):
215 def get_readonly_fields(self
, request
, obj
=None):
216 return [f
.name
for f
in self
.model
._meta
.fields
]
219 class AyantDroitInline(admin
.StackedInline
):
220 model
= rh
.AyantDroit
221 form
= AyantDroitForm
228 ('nom_affichage', 'genre'),
236 class AyantDroitCommentaireInline(admin
.TabularInline
):
237 readonly_fields
= ('owner',)
238 model
= rh
.AyantDroitCommentaire
240 form
= CommentaireInlineForm
243 class ContratInline(admin
.TabularInline
):
249 class DossierROInline(ReadOnlyInlineMixin
, LinkedInline
):
250 template
= "admin/rh/dossier/linked.html"
255 def has_add_permission(self
, request
=None):
258 def has_change_permission(self
, request
, obj
=None):
261 def has_delete_permission(self
, request
, obj
=None):
265 class DossierCommentaireInline(admin
.TabularInline
):
266 readonly_fields
= ('owner',)
267 model
= rh
.DossierCommentaire
269 form
= CommentaireInlineForm
272 class DossierPieceInline(admin
.TabularInline
):
273 model
= rh
.DossierPiece
277 class EmployeInline(admin
.TabularInline
):
281 class EmployeCommentaireInline(admin
.TabularInline
):
282 readonly_fields
= ('owner',)
283 model
= rh
.EmployeCommentaire
285 form
= CommentaireInlineForm
288 class EmployePieceInline(admin
.TabularInline
):
289 model
= rh
.EmployePiece
293 class PosteCommentaireInline(admin
.TabularInline
):
294 readonly_fields
= ('owner',)
295 model
= rh
.PosteCommentaire
297 form
= CommentaireInlineForm
300 class PosteFinancementInline(admin
.TabularInline
):
301 model
= rh
.PosteFinancement
304 class PostePieceInline(admin
.TabularInline
):
305 model
= rh
.PostePiece
308 class RemunerationInline(admin
.TabularInline
):
309 model
= rh
.Remuneration
313 class RemunerationROInline(ReadOnlyInlineMixin
, RemunerationInline
):
317 class TypePosteInline(admin
.TabularInline
):
321 class PosteComparaisonInline(admin
.TabularInline
):
322 model
= rh
.PosteComparaison
325 class ClassementAdmin(reversion
.VersionAdmin
, DerniereModificationAdmin
,
327 ignore_duplicate_revisions
= True
328 list_display
= ('_classement', 'derniere_modification')
330 (None, {'fields': ('type', 'echelon', 'degre', 'coefficient',)}),
333 def _classement(self
, obj
):
335 _classement
.short_description
= u
"Classement"
338 class DeviseAdmin(reversion
.VersionAdmin
, ArchivableAdmin
,
339 DerniereModificationAdmin
, BaseAdmin
):
340 ignore_duplicate_revisions
= True
342 'code', 'nom', '_archive', 'derniere_modification',
344 list_filter
= ('archive', )
346 (None, {'fields': ('code', 'nom', 'archive', )}),
350 class DossierAdmin(DateRangeMixin
, ProtectRegionMixin
, reversion
.VersionAdmin
,
351 AjaxSelect
, DerniereModificationAdmin
, BaseAdmin
):
352 change_list_template
= "admin/rh/dossier/change_list.html"
353 ignore_duplicate_revisions
= True
354 alphabet_filter
= 'employe__nom'
362 'poste__nom_feminin',
363 'poste__implantation__nom',
375 'derniere_modification',
378 list_display_links
= ('_nom',)
380 'poste__implantation__region',
381 'poste__implantation',
382 'poste__type_poste__categorie_emploi',
384 'rh_contrats__type_contrat',
387 inlines
= (DossierPieceInline
, ContratInline
,
389 DossierCommentaireInline
,
398 'organisme_bstg',)}),
403 'remplacement_de', )}),
407 ('regime_travail', 'regime_travail_nb_heure_semaine'),)}),
408 ('Occupation du Poste par cet Employe', {
409 'fields': (('date_debut', 'date_fin'), )}
412 form
= make_ajax_form(rh
.Dossier
, {
413 'employe': 'employes',
415 'remplacement_de': 'dossiers',
416 }, superclass
=DossierForm
)
418 def lookup_allowed(self
, key
, value
):
420 'employe__nom__istartswith',
421 'poste__implantation__region__id__exact',
422 'poste__implantation__id__exact',
423 'poste__type_poste__id__exact',
424 'poste__type_poste__categorie_emploi__id__exact',
425 'rh_contrats__type_contrat__id__exact',
433 _id
.short_description
= u
"#"
434 _id
.admin_order_field
= "id"
436 def _apercu(self
, d
):
437 apercu_link
= u
"""<a title="Aperçu du dossier"
438 onclick="return showAddAnotherPopup(this);"
440 <img src="%simg/dossier-apercu.png" />
442 (reverse('dossier_apercu', args
=(d
.id,)),
446 _apercu
.allow_tags
= True
447 _apercu
.short_description
= u
""
451 _nom
.allow_tags
= True
452 _nom
.short_description
= u
"Dossier"
454 def _employe(self
, obj
):
455 employe
= obj
.employe
456 view_link
= reverse('employe_apercu', args
=(employe
.id,))
457 edit_link
= reverse('admin:rh_employe_change', args
=(employe
.id,))
459 view
= u
"""<a href="%s"
460 title="Aperçu l'employé"
461 onclick="return showAddAnotherPopup(this);">
462 <img src="%simg/employe-apercu.png" />
463 </a>""" % (view_link
, settings
.STATIC_URL
,)
464 return u
"""%s<a href='%s' style="%s;">%s</a>""" % \
465 (view
, edit_link
, style
, employe
)
466 _employe
.allow_tags
= True
467 _employe
.short_description
= u
"Employé"
468 _employe
.admin_order_field
= "employe__nom"
470 def _poste(self
, dossier
):
471 link
= u
"""<a title="Aperçu du poste"
472 onclick="return showAddAnotherPopup(this);"
473 href='%s'><img src="%simg/poste-apercu.png" />
475 <a href="%s" title="Modifier le poste">%s [%d]</a>""" % \
476 (reverse('poste_apercu', args
=(dossier
.poste
.id,)),
478 reverse('admin:rh_poste_change', args
=(dossier
.poste
.id,)),
483 _poste
.allow_tags
= True
484 _poste
.short_description
= u
'Poste'
485 _poste
.admin_order_field
= 'poste__nom'
487 def _region(self
, obj
):
488 return obj
.poste
.implantation
.region
.code
489 _region
.short_description
= u
"Région"
490 _region
.admin_order_field
= 'poste__implantation__region__code'
492 def _implantation(self
, obj
):
493 return obj
.poste
.implantation
.nom
494 _implantation
.short_description
= u
"Implantation"
495 _implantation
.admin_order_field
= 'poste__implantation__nom'
497 def _date_debut(self
, obj
):
498 return date(obj
.date_debut
)
500 _date_debut
.short_description
= u
'Début'
501 _date_debut
.admin_order_field
= 'date_debut'
503 def _date_fin(self
, obj
):
504 return date(obj
.date_fin
)
505 _date_fin
.short_description
= u
'Fin'
506 _date_fin
.admin_order_field
= 'date_fin'
508 def _date_modification(self
, obj
):
509 return date(obj
.date_modification
) \
510 if obj
.date_modification
is not None else "(aucune)"
511 _date_modification
.short_description
= u
'date modification'
512 _date_modification
.admin_order_field
= 'date_modification'
516 dossiers_dae
= d
.dossiers_dae
.all()
517 if len(dossiers_dae
) > 0:
518 dossier_dae
= dossiers_dae
[0]
519 apercu_link
= u
"""<a title="Aperçu du dossier"
520 onclick="return showAddAnotherPopup(this);"
522 <img src="%simg/loupe.png" />
524 (reverse('embauche_consulter', args
=(dossier_dae
.id,)),
528 _dae
.allow_tags
= True
529 _dae
.short_description
= u
"DAE"
531 def save_formset(self
, request
, form
, formset
, change
):
532 instances
= formset
.save(commit
=False)
533 for instance
in instances
:
534 if instance
.__class__
== rh
.DossierCommentaire
:
535 instance
.owner
= request
.user
536 instance
.date_creation
= datetime
.datetime
.now()
540 class EmployeAdminBase(DateRangeMixin
, ProtectRegionMixin
,
541 DerniereModificationAdmin
, BaseAdmin
):
542 prefixe_recherche_temporelle
= "rh_dossiers__"
543 alphabet_filter
= 'nom'
544 DEFAULT_ALPHABET
= u
'ABCDEFGHIJKLMNOPQRSTUVWXYZ'
546 'id', 'nom', 'prenom', 'nom_affichage',
547 'rh_dossiers__poste__nom',
548 'rh_dossiers__poste__nom_feminin'
551 form
= EmployeAdminForm
553 '_id', '_apercu', '_nom', '_dossiers_postes',
557 'derniere_modification'
559 list_display_links
= ('_nom',)
561 'rh_dossiers__poste__implantation__region',
562 'rh_dossiers__poste__implantation', 'nb_postes'
565 AyantDroitInline
, DossierROInline
, EmployePieceInline
,
566 EmployeCommentaireInline
572 ('nom_affichage', 'genre'),
577 ('Informations personnelles', {
578 'fields': ('situation_famille', 'date_entree', )
580 ('Coordonnées personnelles', {
582 ('tel_domicile', 'tel_cellulaire'),
583 ('adresse', 'ville'),
584 ('code_postal', 'province'),
593 _id
.short_description
= u
"#"
594 _id
.admin_order_field
= "id"
596 def _apercu(self
, obj
):
597 return u
"""<a title="Aperçu de l'employé"
598 onclick="return showAddAnotherPopup(this);"
600 <img src="%simg/employe-apercu.png" />
602 (reverse('employe_apercu', args
=(obj
.id,)), settings
.STATIC_URL
)
603 _apercu
.allow_tags
= True
604 _apercu
.short_description
= u
""
607 edit_link
= reverse('admin:rh_employe_change', args
=(obj
.id,))
608 return u
"""<a href='%s'><strong>%s</strong></a>""" % \
609 (edit_link
, "%s %s" % (obj
.nom
.upper(), obj
.prenom
))
610 _nom
.allow_tags
= True
611 _nom
.short_description
= u
"Employé"
612 _nom
.admin_order_field
= "nom"
614 def _region(self
, obj
):
616 d
= rh
.Dossier
.objects
.filter(employe
=obj
.id, principal
=True)[0]
617 region
= d
.poste
.implantation
.region
.code
621 _region
.short_description
= u
"Région"
623 def _implantation(self
, obj
):
625 d
= rh
.Dossier
.objects
.filter(employe
=obj
.id, principal
=True)[0]
626 implantation
= d
.poste
.implantation
.nom
630 _implantation
.short_description
= u
"Implantation"
632 def _dossiers_postes(self
, obj
):
634 for d
in obj
.rh_dossiers
.all().order_by('-date_debut'):
637 if d
.date_fin
is not None and d
.date_fin
< datetime
.date
.today():
638 link_style
= u
' style="color:#666;"'
639 list_style
= u
' style="color:grey;"'
641 dossier
= u
"""<a title="Aperçu du dossier"
643 onclick="return showAddAnotherPopup(this);"
644 title="Aperçu du dossier">
645 <img src="%simg/dossier-apercu.png" />
647 <a href="%s"%s>Dossier</a>
649 (reverse('dossier_apercu', args
=(d
.id,)),
651 reverse('admin:rh_dossier_change', args
=(d
.id,)),
654 poste
= u
"""<a title="Aperçu du poste"
656 onclick="return showAddAnotherPopup(this);"
657 title="Aperçu du poste">
658 <img src="%simg/poste-apercu.png" />
660 <a href="%s"%s>%s [%d]</a>
662 (reverse('poste_apercu', args
=(d
.poste
.id,)),
664 reverse('admin:rh_poste_change', args
=(d
.poste
.id,)),
669 link
= u
"""<li%s>%s %s</li>""" % \
670 (list_style
, dossier
, poste
)
673 return "<ul>%s</ul>" % "\n".join(l
)
674 _dossiers_postes
.allow_tags
= True
675 _dossiers_postes
.short_description
= u
"Dossiers et postes"
677 def _date_modification(self
, obj
):
678 return date(obj
.date_modification
) \
679 if obj
.date_modification
is not None else "(aucune)"
680 _date_modification
.short_description
= u
'date modification'
681 _date_modification
.admin_order_field
= 'date_modification'
683 def queryset(self
, request
):
684 qs
= super(EmployeAdminBase
, self
).queryset(request
)
685 return qs
.select_related(depth
=1).order_by('nom')
687 def save_formset(self
, request
, form
, formset
, change
):
688 instances
= formset
.save(commit
=False)
689 for instance
in instances
:
690 if instance
.__class__
== rh
.EmployeCommentaire
:
691 instance
.owner
= request
.user
692 instance
.date_creation
= datetime
.datetime
.now()
696 class EmployeAdmin(reversion
.VersionAdmin
, EmployeAdminBase
):
697 change_list_template
= "admin/rh/employe/change_list.html"
698 ignore_duplicate_revisions
= True
701 class EmployeProxyAdmin(EmployeAdminBase
):
702 list_display
= ('_id', '_apercu', '_nom', '_organigramme')
706 def __init__(self
, *args
, **kwargs
):
707 super(EmployeProxyAdmin
, self
).__init__(*args
, **kwargs
)
708 self
.list_display_links
= (None, )
710 def queryset(self
, request
):
711 qs
= super(ProtectRegionMixin
, self
).queryset(request
)
713 if in_drh_or_admin(request
.user
) or \
714 user_gere_obj_de_sa_region(request
.user
):
719 def has_add_permission(self
, obj
):
722 def has_change_permission(self
, request
, obj
=None):
723 user_groups
= [g
.name
for g
in request
.user
.groups
.all()]
724 if groups
.CORRESPONDANT_RH
in user_groups
or \
725 groups
.ADMINISTRATEURS
in user_groups
or \
726 groups
.DIRECTEUR_DE_BUREAU
in user_groups
or \
727 in_drh_or_admin(request
.user
):
731 def _organigramme(self
, obj
):
733 for d
in rh
.Dossier
.objects
.filter(
734 Q(date_fin__gt
=datetime
.date
.today()) |
Q(date_fin
=None),
735 Q(date_debut__lt
=datetime
.date
.today()) |
Q(date_debut
=None),
739 u
'Organigramme, niveau: ' \
740 u
'<input type="text" id="level_%s" ' \
741 u
'style="width:30px;height:15px;" /> ' \
742 u
'<input type="button" value="Générer" ' \
743 u
"""onclick="window.location='%s' + """ \
744 u
"""document.getElementById('level_%s').value" />""" % (
746 reverse('rho_employe_sans_niveau', args
=(d
.poste
.id,)),
749 link
= u
"""<li>%s [%s]:<br />%s</li>""" % (
755 return "<ul>%s</ul>" % "\n".join(l
)
757 _organigramme
.allow_tags
= True
758 _organigramme
.short_description
= "Organigramme"
761 class CategorieEmploiAdmin(reversion
.VersionAdmin
,
762 DerniereModificationAdmin
, BaseAdmin
):
763 ignore_duplicate_revisions
= True
764 list_display
= ('nom', 'derniere_modification')
765 inlines
= (TypePosteInline
,)
767 (None, {'fields': ('nom', )}),
771 class OrganismeBstgAdmin(reversion
.VersionAdmin
, DerniereModificationAdmin
,
773 ignore_duplicate_revisions
= True
774 search_fields
= ('nom',)
775 list_display
= ('nom', 'type', 'pays', 'derniere_modification')
776 list_filter
= ('type', )
777 inlines
= (DossierROInline
,)
779 (None, {'fields': ('nom', 'type', 'pays',)}),
783 class PosteAdmin(DateRangeMixin
, ProtectRegionMixin
, reversion
.VersionAdmin
,
784 AjaxSelect
, DerniereModificationAdmin
, BaseAdmin
):
785 change_list_template
= "admin/rh/poste/change_list.html"
786 ignore_duplicate_revisions
= True
787 form
= make_ajax_form(rh
.Poste
, {
788 'implantation': 'implantations',
789 'type_poste': 'typepostes',
790 'responsable': 'postes',
791 'valeur_point_min': 'valeurpoints',
792 'valeur_point_max': 'valeurpoints',
794 alphabet_filter
= 'nom'
799 'implantation__region__code',
800 'implantation__region__nom',
801 'rh_dossiers__employe__id',
802 'rh_dossiers__employe__nom',
803 'rh_dossiers__employe__prenom',
806 '_id', '_apercu', '_nom', '_occupe_par', 'implantation', '_service',
807 '_responsable', 'date_debut', 'date_fin', 'derniere_modification',
811 'implantation__region',
815 'type_poste__categorie_emploi',
816 'type_poste__famille_professionnelle',
819 list_display_links
= ('_nom',)
822 ('nom', 'nom_feminin'),
832 'regime_travail_nb_heure_semaine'),
836 'fields': (('local', 'expatrie', 'mise_a_disposition', 'appel'),)}
839 'fields': (('classement_min',
852 ('Comparatifs de rémunération', {
853 'fields': ('devise_comparaison',
854 ('comp_locale_min', 'comp_locale_max'),
855 ('comp_universite_min', 'comp_universite_max'),
856 ('comp_fonctionpub_min', 'comp_fonctionpub_max'),
857 ('comp_ong_min', 'comp_ong_max'),
858 ('comp_autre_min', 'comp_autre_max'))}
861 'fields': ('justification',)}
863 ('Autres Méta-données', {
864 'fields': ('date_debut', 'date_fin')}
868 inlines
= (PosteFinancementInline
,
871 PosteComparaisonInline
,
872 PosteCommentaireInline
, )
874 def lookup_allowed(self
, key
, value
):
876 'date_debut__gte', 'date_debut__isnull', 'date_fin__lte',
877 'date_fin__isnull', 'implantation__region__id__exact',
878 'implantation__id__exact', 'type_poste__id__exact',
879 'type_poste__categorie_emploi__id__exact', 'service__id__exact',
880 'service__isnull', 'vacant__exact', 'vacant__isnull',
881 ) or super(PosteAdmin
, self
).lookup_allowed(key
, value
)
885 _id
.short_description
= '#'
886 _id
.admin_order_field
= 'id'
888 def _apercu(self
, poste
):
889 view_link
= u
"""<a onclick="return showAddAnotherPopup(this);"
890 title="Aperçu du poste"
892 <img src="%simg/poste-apercu.png" />
894 (reverse('poste_apercu', args
=(poste
.id,)),
895 settings
.STATIC_URL
,)
897 _apercu
.allow_tags
= True
898 _apercu
.short_description
= ''
900 def _nom(self
, poste
):
901 return """<a href="%s">%s</a>""" % \
902 (reverse('admin:rh_poste_change', args
=(poste
.id,)),
904 _nom
.allow_tags
= True
905 _nom
.short_description
= u
'Poste'
906 _nom
.admin_order_field
= 'nom'
908 def _occupe_par(self
, obj
):
909 """Formatte la méthode Poste.occupe_par() pour l'admin"""
911 if obj
.date_fin
is not None and obj
.date_fin
< datetime
.date
.today():
913 employes
= obj
.occupe_par()
917 link
= u
"""<a href='%s'
918 title='Aperçu de l\'employé'
919 onclick='return showAddAnotherPopup(this)'>
920 <img src='%simg/employe-apercu.png' />
922 <a href='%s'>%s</a>""" % \
923 (reverse('employe_apercu', args
=(e
.id,)),
925 reverse('admin:rh_employe_change', args
=(e
.id,)),
928 output
= "\n<br />".join(l
)
930 _occupe_par
.allow_tags
= True
931 _occupe_par
.short_description
= "Occupé par"
933 def _region(self
, poste
):
934 return poste
.implantation
.region
.code
935 _region
.short_description
= 'Région'
936 _region
.admin_order_field
= 'implantation__region__code'
938 def _implantation(self
, poste
):
939 return poste
.implantation
.nom
940 _implantation
.short_description
= 'Implantation'
941 _implantation
.admin_order_field
= 'implantation'
943 def _service(self
, obj
):
945 _service
.short_description
= 'Service'
946 _service
.allow_tags
= True
948 def _responsable(self
, obj
):
950 responsable
= u
"""<a href="%s"
951 onclick="return showAddAnotherPopup(this)">
952 <img src="%simg/poste-apercu.png"
953 title="Aperçu du poste" />
955 <a href="%s">%s [%d]</a>
957 (reverse('poste_apercu', args
=(obj
.responsable
.id,)),
959 reverse('admin:rh_poste_change', args
=(obj
.responsable
.id,)),
966 dossier
= obj
.responsable
.rh_dossiers
.all() \
967 .order_by('-date_debut')[0]
968 employe_id
= dossier
.employe
.id
969 employe_html
= u
"""<br />
971 onclick="return showAddAnotherPopup(this)">
972 <img src="%simg/employe-apercu.png"
973 title="Aperçu de l'employé">
975 <a href="%s">%s</a>""" % \
976 (reverse('employe_apercu', args
=(employe_id
,)),
978 reverse('admin:rh_employe_change', args
=(employe_id
,)),
983 return "%s %s" % (responsable
, employe_html
)
984 _responsable
.short_description
= 'Responsable'
985 _responsable
.allow_tags
= True
987 def _date_debut(self
, obj
):
988 return date_format(obj
.date_debut
)
989 _date_debut
.short_description
= u
'Début'
990 _date_debut
.admin_order_field
= 'date_debut'
992 def _date_fin(self
, obj
):
993 return date_format(obj
.date_fin
)
994 _date_fin
.short_description
= u
'Fin'
995 _date_fin
.admin_order_field
= 'date_fin'
997 def _dae(self
, poste
):
999 postes_dae
= poste
.postes_dae
.all()
1000 if len(postes_dae
) > 0:
1001 poste_dae
= postes_dae
[0]
1003 u
'<a title="Aperçu du dossier" href="%s" ' \
1004 u
'onclick="return showAddAnotherPopup(this);">' \
1005 u
'<img src="%simg/loupe.png" /></a>' % (reverse(
1006 'poste_consulter', args
=("dae-%s" % poste_dae
.id,)
1007 ), settings
.STATIC_URL
)
1009 _dae
.allow_tags
= True
1010 _dae
.short_description
= u
"DAE"
1012 def save_formset(self
, request
, form
, formset
, change
):
1013 instances
= formset
.save(commit
=False)
1014 for instance
in instances
:
1015 if instance
.__class__
== rh
.PosteCommentaire
:
1016 instance
.owner
= request
.user
1017 instance
.date_creation
= datetime
.datetime
.now()
1022 class ResponsableInline(admin
.TabularInline
):
1023 model
= rh
.ResponsableImplantation
1025 fk_name
= "implantation"
1026 form
= ResponsableInlineForm
1029 class ResponsableImplantationAdmin(BaseAdmin
):
1032 inlines
= (ResponsableInline
, )
1033 list_filter
= ('region', 'statut', )
1034 list_display
= ('_region', '_nom', 'statut', '_responsable', )
1035 list_display_links
= ('_nom',)
1037 readonly_fields
= ('nom', )
1040 'responsable__employe__id',
1041 'responsable__employe__nom',
1042 'responsable__employe__prenom',
1045 inlines
= (ResponsableInline
, )
1047 def _region(self
, obj
):
1048 return obj
.region
.code
1049 _region
.short_description
= u
"Région"
1050 _region
.admin_order_field
= 'region__code'
1052 def _nom(self
, obj
):
1054 _nom
.short_description
= u
"Implantation"
1055 _nom
.admin_order_field
= 'nom'
1057 def _responsable(self
, obj
):
1059 employe
= obj
.responsable
.employe
1060 dossiers
= employe
.dossiers_encours()
1061 if len(dossiers
) == 0:
1062 return u
"<span style='color: red;'>%s %s </span>" % (
1063 employe
, u
"sans dossier actif")
1067 if obj
.statut
in (1, 2): # ouverte, ouverture imminente
1068 css
= "style='color: red;'"
1071 return u
"<span %s>Pas de responsable</span>" % css
1072 _responsable
.allow_tags
= True
1073 _responsable
.short_description
= u
"Responsable"
1074 _responsable
.admin_order_field
= 'responsable__employe__nom'
1076 def has_add_permission(self
, request
=None):
1079 def has_change_permission(self
, request
, obj
=None):
1080 return in_drh_or_admin(request
.user
)
1082 def has_delete_permission(self
, request
, obj
=None):
1086 class ServiceAdminBase(ArchivableAdmin
, DerniereModificationAdmin
, BaseAdmin
):
1087 list_display
= ('nom', '_archive', 'derniere_modification')
1088 list_filter
= ('archive', )
1090 (None, {'fields': ('nom', 'archive')}),
1094 class ServiceAdmin(reversion
.VersionAdmin
, ServiceAdminBase
):
1095 ignore_duplicate_revisions
= True
1098 class ServiceProxyAdmin(ServiceAdminBase
):
1099 list_display
= ('nom', '_organigramme', '_archive', )
1102 def __init__(self
, *args
, **kwargs
):
1103 super(ServiceProxyAdmin
, self
).__init__(*args
, **kwargs
)
1104 self
.list_display_links
= (None, )
1106 def queryset(self
, request
):
1107 return super(ServiceProxyAdmin
, self
).queryset(request
) \
1108 .annotate(num_postes
=Count('rh_postes')) \
1109 .filter(num_postes__gt
=0)
1111 def has_add_permission(self
, obj
):
1114 def has_change_permission(self
, request
, obj
=None):
1115 user_groups
= [g
.name
for g
in request
.user
.groups
.all()]
1116 if groups
.CORRESPONDANT_RH
in user_groups
or \
1117 groups
.ADMINISTRATEURS
in user_groups
or \
1118 groups
.DIRECTEUR_DE_BUREAU
in user_groups
or \
1119 in_drh_or_admin(request
.user
):
1123 def _organigramme(self
, obj
):
1124 return """<a href="%s"><strong>Organigramme</strong></a>""" % \
1125 (reverse('rho_service', args
=(obj
.id,)))
1126 _organigramme
.allow_tags
= True
1127 _organigramme
.short_description
= "Organigramme"
1130 class StatutAdmin(reversion
.VersionAdmin
, DerniereModificationAdmin
,
1132 ignore_duplicate_revisions
= True
1133 list_display
= ('code', 'nom', 'derniere_modification')
1136 'fields': ('code', 'nom', ),
1141 class TauxChangeAdmin(reversion
.VersionAdmin
, DerniereModificationAdmin
,
1143 ignore_duplicate_revisions
= True
1144 list_display
= ('taux', 'devise', 'annee', 'derniere_modification')
1145 list_filter
= ('devise',)
1148 'fields': ('taux', 'devise', 'annee', ),
1153 class TypeContratAdmin(reversion
.VersionAdmin
, DerniereModificationAdmin
,
1155 ignore_duplicate_revisions
= True
1156 list_display
= ('nom', 'nom_long', 'derniere_modification')
1159 'fields': ('nom', 'nom_long', ),
1164 class TypePosteAdmin(reversion
.VersionAdmin
, DerniereModificationAdmin
,
1166 ignore_duplicate_revisions
= True
1167 search_fields
= ('nom', 'nom_feminin', )
1168 list_display
= ('nom', 'categorie_emploi', 'derniere_modification')
1169 list_filter
= ('categorie_emploi', 'famille_professionnelle')
1173 'nom', 'nom_feminin', 'is_responsable', 'categorie_emploi',
1174 'famille_professionnelle',
1180 class TypeRemunerationAdmin(reversion
.VersionAdmin
, ArchivableAdmin
,
1181 DerniereModificationAdmin
, BaseAdmin
):
1182 ignore_duplicate_revisions
= True
1184 'nom', 'type_paiement', 'nature_remuneration', '_archive',
1185 'derniere_modification'
1187 list_filter
= ('archive', )
1191 'nom', 'type_paiement', 'nature_remuneration', 'archive'
1197 class TypeRevalorisationAdmin(reversion
.VersionAdmin
,
1198 DerniereModificationAdmin
, BaseAdmin
):
1199 ignore_duplicate_revisions
= True
1200 list_display
= ('nom', 'derniere_modification')
1202 (None, {'fields': ('nom',)}),
1206 class ValeurPointAdmin(reversion
.VersionAdmin
, DerniereModificationAdmin
,
1208 ignore_duplicate_revisions
= True
1210 '_devise_code', '_devise_nom', 'annee', 'implantation',
1211 'valeur', 'derniere_modification'
1213 list_filter
= ('annee', 'devise', 'implantation__region', )
1215 (None, {'fields': ('valeur', 'devise', 'implantation', 'annee')}),
1218 def _devise_code(self
, obj
):
1219 return obj
.devise
.code
1220 _devise_code
.short_description
= "Code de la devise"
1222 def _devise_nom(self
, obj
):
1223 return obj
.devise
.nom
1224 _devise_nom
.short_description
= "Nom de la devise"
1227 class ImplantationProxyAdmin(BaseAdmin
):
1228 list_display
= ('nom', '_organigramme')
1231 def __init__(self
, *args
, **kwargs
):
1232 super(ImplantationProxyAdmin
, self
).__init__(*args
, **kwargs
)
1233 self
.list_display_links
= (None, )
1235 def has_add_permission(self
, obj
):
1238 def has_change_permission(self
, request
, obj
=None):
1239 user_groups
= [g
.name
for g
in request
.user
.groups
.all()]
1240 if groups
.CORRESPONDANT_RH
in user_groups
or \
1241 groups
.ADMINISTRATEURS
in user_groups
or \
1242 groups
.DIRECTEUR_DE_BUREAU
in user_groups
or \
1243 in_drh_or_admin(request
.user
):
1247 def _organigramme(self
, obj
):
1248 return '<a href="%s"><strong>Organigramme</strong></a>' % (
1249 reverse('rho_implantation', args
=(obj
.id,))
1251 _organigramme
.allow_tags
= True
1252 _organigramme
.short_description
= "Organigramme"
1255 class RegionProxyAdmin(BaseAdmin
):
1256 list_display
= ('nom', '_organigramme')
1259 def __init__(self
, *args
, **kwargs
):
1260 super(RegionProxyAdmin
, self
).__init__(*args
, **kwargs
)
1261 self
.list_display_links
= (None, )
1263 def has_add_permission(self
, obj
):
1266 def has_change_permission(self
, request
, obj
=None):
1267 user_groups
= [g
.name
for g
in request
.user
.groups
.all()]
1268 if groups
.CORRESPONDANT_RH
in user_groups
or \
1269 groups
.ADMINISTRATEURS
in user_groups
or \
1270 groups
.DIRECTEUR_DE_BUREAU
in user_groups
or \
1271 in_drh_or_admin(request
.user
):
1275 def _organigramme(self
, obj
):
1276 return """<a href="%s"><strong>Organigramme</strong></a>""" % (
1277 reverse('rho_region', args
=(obj
.id,))
1279 _organigramme
.allow_tags
= True
1280 _organigramme
.short_description
= "Organigramme"
1283 admin
.site
.register(rh
.Classement
, ClassementAdmin
)
1284 admin
.site
.register(rh
.Devise
, DeviseAdmin
)
1285 admin
.site
.register(rh
.Dossier
, DossierAdmin
)
1286 admin
.site
.register(EmployeProxy
, EmployeProxyAdmin
)
1287 admin
.site
.register(ServiceProxy
, ServiceProxyAdmin
)
1288 admin
.site
.register(rh
.Employe
, EmployeAdmin
)
1289 admin
.site
.register(rh
.CategorieEmploi
, CategorieEmploiAdmin
)
1290 admin
.site
.register(rh
.FamilleProfessionnelle
)
1291 admin
.site
.register(rh
.OrganismeBstg
, OrganismeBstgAdmin
)
1292 admin
.site
.register(rh
.Poste
, PosteAdmin
)
1293 admin
.site
.register(
1294 rh
.ResponsableImplantationProxy
, ResponsableImplantationAdmin
1296 admin
.site
.register(rh
.Service
, ServiceAdmin
)
1297 admin
.site
.register(rh
.Statut
, StatutAdmin
)
1298 admin
.site
.register(rh
.TauxChange
, TauxChangeAdmin
)
1299 admin
.site
.register(rh
.TypeContrat
, TypeContratAdmin
)
1300 admin
.site
.register(rh
.TypePoste
, TypePosteAdmin
)
1301 admin
.site
.register(rh
.TypeRemuneration
, TypeRemunerationAdmin
)
1302 admin
.site
.register(rh
.TypeRevalorisation
, TypeRevalorisationAdmin
)
1303 admin
.site
.register(rh
.ValeurPoint
, ValeurPointAdmin
)
1304 admin
.site
.register(ImplantationProxy
, ImplantationProxyAdmin
)
1305 admin
.site
.register(RegionProxy
, RegionProxyAdmin
)