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 DossierCommentaireInline(admin
.TabularInline
):
272 readonly_fields
= ('owner',)
273 model
= rh
.DossierCommentaire
275 form
= CommentaireInlineForm
278 class DossierPieceInline(admin
.TabularInline
):
279 model
= rh
.DossierPiece
283 class EmployeInline(admin
.TabularInline
):
287 class EmployeCommentaireInline(admin
.TabularInline
):
288 readonly_fields
= ('owner',)
289 model
= rh
.EmployeCommentaire
291 form
= CommentaireInlineForm
294 class EmployePieceInline(admin
.TabularInline
):
295 model
= rh
.EmployePiece
299 class PosteCommentaireInline(admin
.TabularInline
):
300 readonly_fields
= ('owner',)
301 model
= rh
.PosteCommentaire
303 form
= CommentaireInlineForm
306 class PosteFinancementInline(admin
.TabularInline
):
307 model
= rh
.PosteFinancement
310 class PostePieceInline(admin
.TabularInline
):
311 model
= rh
.PostePiece
314 class RemunerationInline(admin
.TabularInline
):
315 model
= rh
.Remuneration
319 class RemunerationROInline(ReadOnlyInlineMixin
, RemunerationInline
):
323 class TypePosteInline(admin
.TabularInline
):
327 class PosteComparaisonInline(admin
.TabularInline
):
328 model
= rh
.PosteComparaison
331 class ClassementAdmin(reversion
.VersionAdmin
, DerniereModificationAdmin
,
333 ignore_duplicate_revisions
= True
334 list_display
= ('_classement', 'derniere_modification')
336 (None, {'fields': ('type', 'echelon', 'degre', 'coefficient',)}),
339 def _classement(self
, obj
):
341 _classement
.short_description
= u
"Classement"
344 class DeviseAdmin(reversion
.VersionAdmin
, ArchivableAdmin
,
345 DerniereModificationAdmin
, BaseAdmin
):
346 ignore_duplicate_revisions
= True
348 'code', 'nom', '_archive', 'derniere_modification',
350 list_filter
= ('archive', )
352 (None, {'fields': ('code', 'nom', 'archive', )}),
356 class DossierAdmin(DateRangeMixin
, ProtectRegionMixin
, reversion
.VersionAdmin
,
357 AjaxSelect
, DerniereModificationAdmin
, BaseAdmin
):
358 change_list_template
= "admin/rh/dossier/change_list.html"
359 ignore_duplicate_revisions
= True
360 alphabet_filter
= 'employe__nom'
368 'poste__nom_feminin',
369 'poste__implantation__nom',
377 '_zone_administrative',
381 'derniere_modification',
384 list_display_links
= ('_nom',)
386 'poste__implantation__zone_administrative',
387 'poste__implantation',
388 'poste__type_poste__categorie_emploi',
390 'rh_contrats__type_contrat',
393 inlines
= (DossierPieceInline
, ContratInline
,
395 DossierCommentaireInline
,
404 'organisme_bstg',)}),
409 'remplacement_de', )}),
413 ('regime_travail', 'regime_travail_nb_heure_semaine'),)}),
414 ('Occupation du Poste par cet Employe', {
415 'fields': (('date_debut', 'date_fin'), )}
418 form
= make_ajax_form(rh
.Dossier
, {
419 'employe': 'employes',
421 'remplacement_de': 'dossiers',
422 }, superclass
=DossierForm
)
424 def lookup_allowed(self
, key
, value
):
426 'employe__nom__istartswith',
427 'poste__implantation__zone_administrative__code__exact',
428 'poste__implantation__id__exact',
429 'poste__type_poste__id__exact',
430 'poste__type_poste__categorie_emploi__id__exact',
431 'rh_contrats__type_contrat__id__exact',
439 _id
.short_description
= u
"#"
440 _id
.admin_order_field
= "id"
442 def _apercu(self
, d
):
443 apercu_link
= u
"""<a title="Aperçu du dossier"
444 onclick="return showAddAnotherPopup(this);"
446 <img src="%simg/dossier-apercu.png" />
448 (reverse('dossier_apercu', args
=(d
.id,)),
452 _apercu
.allow_tags
= True
453 _apercu
.short_description
= u
""
457 _nom
.allow_tags
= True
458 _nom
.short_description
= u
"Dossier"
460 def _employe(self
, obj
):
461 employe
= obj
.employe
462 view_link
= reverse('employe_apercu', args
=(employe
.id,))
463 edit_link
= reverse('admin:rh_employe_change', args
=(employe
.id,))
465 view
= u
"""<a href="%s"
466 title="Aperçu l'employé"
467 onclick="return showAddAnotherPopup(this);">
468 <img src="%simg/employe-apercu.png" />
469 </a>""" % (view_link
, settings
.STATIC_URL
,)
470 return u
"""%s<a href='%s' style="%s;">%s</a>""" % \
471 (view
, edit_link
, style
, employe
)
472 _employe
.allow_tags
= True
473 _employe
.short_description
= u
"Employé"
474 _employe
.admin_order_field
= "employe__nom"
476 def _poste(self
, dossier
):
477 link
= u
"""<a title="Aperçu du poste"
478 onclick="return showAddAnotherPopup(this);"
479 href='%s'><img src="%simg/poste-apercu.png" />
481 <a href="%s" title="Modifier le poste">%s [%d]</a>""" % \
482 (reverse('poste_apercu', args
=(dossier
.poste
.id,)),
484 reverse('admin:rh_poste_change', args
=(dossier
.poste
.id,)),
489 _poste
.allow_tags
= True
490 _poste
.short_description
= u
'Poste'
491 _poste
.admin_order_field
= 'poste__nom'
493 def _zone_administrative(self
, obj
):
494 return obj
.poste
.implantation
.zone_administrative
.code
495 _zone_administrative
.short_description
= u
"Zone administrative"
496 _zone_administrative
.admin_order_field
= 'poste__implantation__zone_administrative__code'
498 def _implantation(self
, obj
):
499 return obj
.poste
.implantation
.nom
500 _implantation
.short_description
= u
"Implantation"
501 _implantation
.admin_order_field
= 'poste__implantation__nom'
503 def _date_debut(self
, obj
):
504 return date(obj
.date_debut
)
506 _date_debut
.short_description
= u
'Début'
507 _date_debut
.admin_order_field
= 'date_debut'
509 def _date_fin(self
, obj
):
510 return date(obj
.date_fin
)
511 _date_fin
.short_description
= u
'Fin'
512 _date_fin
.admin_order_field
= 'date_fin'
514 def _date_modification(self
, obj
):
515 return date(obj
.date_modification
) \
516 if obj
.date_modification
is not None else "(aucune)"
517 _date_modification
.short_description
= u
'date modification'
518 _date_modification
.admin_order_field
= 'date_modification'
522 dossiers_dae
= d
.dossiers_dae
.all()
523 if len(dossiers_dae
) > 0:
524 dossier_dae
= dossiers_dae
[0]
525 apercu_link
= u
"""<a title="Aperçu du dossier"
526 onclick="return showAddAnotherPopup(this);"
528 <img src="%simg/loupe.png" />
530 (reverse('embauche_consulter', args
=(dossier_dae
.id,)),
534 _dae
.allow_tags
= True
535 _dae
.short_description
= u
"DAE"
537 def save_formset(self
, request
, form
, formset
, change
):
538 instances
= formset
.save(commit
=False)
539 for instance
in instances
:
540 if instance
.__class__
== rh
.DossierCommentaire
:
541 instance
.owner
= request
.user
542 instance
.date_creation
= datetime
.datetime
.now()
546 class EmployeAdminBase(DateRangeMixin
, ProtectRegionMixin
,
547 DerniereModificationAdmin
, BaseAdmin
):
548 prefixe_recherche_temporelle
= "rh_dossiers__"
549 alphabet_filter
= 'nom'
550 DEFAULT_ALPHABET
= u
'ABCDEFGHIJKLMNOPQRSTUVWXYZ'
552 'id', 'nom', 'prenom', 'nom_affichage',
553 'rh_dossiers__poste__nom',
554 'rh_dossiers__poste__nom_feminin'
557 form
= EmployeAdminForm
559 '_id', '_apercu', '_nom', '_dossiers_postes',
560 #'_zone_administrative',
563 'derniere_modification'
565 list_display_links
= ('_nom',)
567 'rh_dossiers__poste__implantation__zone_administrative',
568 'rh_dossiers__poste__implantation', 'nb_postes'
571 AyantDroitInline
, EmployePieceInline
,
572 EmployeCommentaireInline
578 ('nom_affichage', 'genre'),
583 ('Informations personnelles', {
584 'fields': ('situation_famille', 'date_entree', )
586 ('Coordonnées personnelles', {
588 ('tel_domicile', 'tel_cellulaire'),
589 ('adresse', 'ville'),
590 ('code_postal', 'province'),
599 _id
.short_description
= u
"#"
600 _id
.admin_order_field
= "id"
602 def _apercu(self
, obj
):
603 return u
"""<a title="Aperçu de l'employé"
604 onclick="return showAddAnotherPopup(this);"
606 <img src="%simg/employe-apercu.png" />
608 (reverse('employe_apercu', args
=(obj
.id,)), settings
.STATIC_URL
)
609 _apercu
.allow_tags
= True
610 _apercu
.short_description
= u
""
613 edit_link
= reverse('admin:rh_employe_change', args
=(obj
.id,))
614 return u
"""<a href='%s'><strong>%s</strong></a>""" % \
615 (edit_link
, "%s %s" % (obj
.nom
.upper(), obj
.prenom
))
616 _nom
.allow_tags
= True
617 _nom
.short_description
= u
"Employé"
618 _nom
.admin_order_field
= "nom"
620 def _zone_administrative(self
, obj
):
622 d
= rh
.Dossier
.objects
.filter(employe
=obj
.id, principal
=True)[0]
623 zone
= d
.poste
.implantation
.zone_administrative
.code
627 _zone_administrative
.short_description
= u
"Zone administrative"
629 def _implantation(self
, obj
):
631 d
= rh
.Dossier
.objects
.filter(employe
=obj
.id, principal
=True)[0]
632 implantation
= d
.poste
.implantation
.nom
636 _implantation
.short_description
= u
"Implantation"
638 def _dossiers_postes(self
, obj
):
640 for d
in obj
.rh_dossiers
.all().order_by('-date_debut'):
643 if d
.date_fin
is not None and d
.date_fin
< datetime
.date
.today():
644 link_style
= u
' style="color:#666;"'
645 list_style
= u
' style="color:grey;"'
647 dossier
= u
"""<a title="Aperçu du dossier"
649 onclick="return showAddAnotherPopup(this);"
650 title="Aperçu du dossier">
651 <img src="%simg/dossier-apercu.png" />
653 <a href="%s"%s>Dossier</a>
655 (reverse('dossier_apercu', args
=(d
.id,)),
657 reverse('admin:rh_dossier_change', args
=(d
.id,)),
660 poste
= u
"""<a title="Aperçu du poste"
662 onclick="return showAddAnotherPopup(this);"
663 title="Aperçu du poste">
664 <img src="%simg/poste-apercu.png" />
666 <a href="%s"%s>%s [%d]</a>
668 (reverse('poste_apercu', args
=(d
.poste
.id,)),
670 reverse('admin:rh_poste_change', args
=(d
.poste
.id,)),
675 link
= u
"""<li%s>%s %s</li>""" % \
676 (list_style
, dossier
, poste
)
679 return "<ul>%s</ul>" % "\n".join(l
)
680 _dossiers_postes
.allow_tags
= True
681 _dossiers_postes
.short_description
= u
"Dossiers et postes"
683 def _date_modification(self
, obj
):
684 return date(obj
.date_modification
) \
685 if obj
.date_modification
is not None else "(aucune)"
686 _date_modification
.short_description
= u
'date modification'
687 _date_modification
.admin_order_field
= 'date_modification'
689 def queryset(self
, request
):
690 qs
= super(EmployeAdminBase
, self
).queryset(request
)
691 return qs
.select_related(depth
=1).order_by('nom')
693 def save_formset(self
, request
, form
, formset
, change
):
694 instances
= formset
.save(commit
=False)
695 for instance
in instances
:
696 if instance
.__class__
== rh
.EmployeCommentaire
:
697 instance
.owner
= request
.user
698 instance
.date_creation
= datetime
.datetime
.now()
702 class EmployeAdmin(reversion
.VersionAdmin
, EmployeAdminBase
):
703 change_list_template
= "admin/rh/employe/change_list.html"
704 ignore_duplicate_revisions
= True
707 class EmployeProxyAdmin(EmployeAdminBase
):
708 list_display
= ('_id', '_apercu', '_nom', '_organigramme')
712 def __init__(self
, *args
, **kwargs
):
713 super(EmployeProxyAdmin
, self
).__init__(*args
, **kwargs
)
714 self
.list_display_links
= (None, )
716 def queryset(self
, request
):
717 qs
= super(ProtectRegionMixin
, self
).queryset(request
)
719 if in_drh_or_admin(request
.user
) or \
720 user_gere_obj_de_sa_region(request
.user
):
725 def has_add_permission(self
, obj
):
728 def has_change_permission(self
, request
, obj
=None):
729 user_groups
= [g
.name
for g
in request
.user
.groups
.all()]
730 if groups
.CORRESPONDANT_RH
in user_groups
or \
731 groups
.ADMINISTRATEURS
in user_groups
or \
732 groups
.DIRECTEUR_DE_BUREAU
in user_groups
or \
733 in_drh_or_admin(request
.user
):
737 def _organigramme(self
, obj
):
739 for d
in rh
.Dossier
.objects
.filter(
740 Q(date_fin__gt
=datetime
.date
.today()) |
Q(date_fin
=None),
741 Q(date_debut__lt
=datetime
.date
.today()) |
Q(date_debut
=None),
745 u
'Organigramme, niveau: ' \
746 u
'<input type="text" id="level_%s" ' \
747 u
'style="width:30px;height:15px;" /> ' \
748 u
'<input type="button" value="Générer" ' \
749 u
"""onclick="window.location='%s' + """ \
750 u
"""document.getElementById('level_%s').value" />""" % (
752 reverse('rho_employe_sans_niveau', args
=(d
.poste
.id,)),
755 link
= u
"""<li>%s [%s]:<br />%s</li>""" % (
761 return "<ul>%s</ul>" % "\n".join(l
)
763 _organigramme
.allow_tags
= True
764 _organigramme
.short_description
= "Organigramme"
767 class CategorieEmploiAdmin(reversion
.VersionAdmin
,
768 DerniereModificationAdmin
, BaseAdmin
):
769 ignore_duplicate_revisions
= True
770 list_display
= ('nom', 'derniere_modification')
771 inlines
= (TypePosteInline
,)
773 (None, {'fields': ('nom', )}),
777 class OrganismeBstgAdmin(reversion
.VersionAdmin
, DerniereModificationAdmin
,
779 ignore_duplicate_revisions
= True
780 search_fields
= ('nom',)
781 list_display
= ('nom', 'type', 'pays', 'derniere_modification')
782 list_filter
= ('type', )
784 (None, {'fields': ('nom', 'type', 'pays',)}),
788 class PosteAdmin(DateRangeMixin
, ProtectRegionMixin
, reversion
.VersionAdmin
,
789 AjaxSelect
, DerniereModificationAdmin
, BaseAdmin
):
790 change_list_template
= "admin/rh/poste/change_list.html"
791 ignore_duplicate_revisions
= True
792 form
= make_ajax_form(rh
.Poste
, {
793 'implantation': 'implantations',
794 'type_poste': 'typepostes',
795 'responsable': 'postes',
796 'valeur_point_min': 'valeurpoints',
797 'valeur_point_max': 'valeurpoints',
799 alphabet_filter
= 'nom'
804 'implantation__zone_administrative__code',
805 'implantation__zone_administrative__nom',
806 'rh_dossiers__employe__id',
807 'rh_dossiers__employe__nom',
808 'rh_dossiers__employe__prenom',
811 '_id', '_apercu', '_nom', '_occupe_par', 'implantation', '_service',
812 '_responsable', 'date_debut', 'date_fin', 'derniere_modification',
816 'implantation__zone_administrative',
820 'type_poste__categorie_emploi',
821 'type_poste__famille_professionnelle',
824 list_display_links
= ('_nom',)
827 ('nom', 'nom_feminin'),
837 'regime_travail_nb_heure_semaine'),
841 'fields': (('local', 'expatrie', 'mise_a_disposition', 'appel'),)}
844 'fields': (('classement_min',
857 ('Comparatifs de rémunération', {
858 'fields': ('devise_comparaison',
859 ('comp_locale_min', 'comp_locale_max'),
860 ('comp_universite_min', 'comp_universite_max'),
861 ('comp_fonctionpub_min', 'comp_fonctionpub_max'),
862 ('comp_ong_min', 'comp_ong_max'),
863 ('comp_autre_min', 'comp_autre_max'))}
866 'fields': ('justification',)}
868 ('Autres Méta-données', {
869 'fields': ('date_debut', 'date_fin')}
873 inlines
= (PosteFinancementInline
,
875 PosteComparaisonInline
,
876 PosteCommentaireInline
, )
878 def lookup_allowed(self
, key
, value
):
880 'date_debut__gte', 'date_debut__isnull', 'date_fin__lte',
881 'date_fin__isnull', 'implantation__zone_administrative__code__exact',
882 'implantation__id__exact', 'type_poste__id__exact',
883 'type_poste__categorie_emploi__id__exact', 'service__id__exact',
884 'service__isnull', 'vacant__exact', 'vacant__isnull',
885 ) or super(PosteAdmin
, self
).lookup_allowed(key
, value
)
889 _id
.short_description
= '#'
890 _id
.admin_order_field
= 'id'
892 def _apercu(self
, poste
):
893 view_link
= u
"""<a onclick="return showAddAnotherPopup(this);"
894 title="Aperçu du poste"
896 <img src="%simg/poste-apercu.png" />
898 (reverse('poste_apercu', args
=(poste
.id,)),
899 settings
.STATIC_URL
,)
901 _apercu
.allow_tags
= True
902 _apercu
.short_description
= ''
904 def _nom(self
, poste
):
905 return """<a href="%s">%s</a>""" % \
906 (reverse('admin:rh_poste_change', args
=(poste
.id,)),
908 _nom
.allow_tags
= True
909 _nom
.short_description
= u
'Poste'
910 _nom
.admin_order_field
= 'nom'
912 def _occupe_par(self
, obj
):
913 """Formatte la méthode Poste.occupe_par() pour l'admin"""
915 if obj
.date_fin
is not None and obj
.date_fin
< datetime
.date
.today():
917 employes
= obj
.occupe_par()
921 link
= u
"""<a href='%s'
922 title='Aperçu de l\'employé'
923 onclick='return showAddAnotherPopup(this)'>
924 <img src='%simg/employe-apercu.png' />
926 <a href='%s'>%s</a>""" % \
927 (reverse('employe_apercu', args
=(e
.id,)),
929 reverse('admin:rh_employe_change', args
=(e
.id,)),
932 output
= "\n<br />".join(l
)
934 _occupe_par
.allow_tags
= True
935 _occupe_par
.short_description
= "Occupé par"
937 def _zone_administrative(self
, poste
):
938 return poste
.implantation
.zone_administrative
.code
939 _zone_administrative
.short_description
= 'Zone administrative'
940 _zone_administrative
.admin_order_field
= 'implantation__zone_administrative__code'
942 def _implantation(self
, poste
):
943 return poste
.implantation
.nom
944 _implantation
.short_description
= 'Implantation'
945 _implantation
.admin_order_field
= 'implantation'
947 def _service(self
, obj
):
949 _service
.short_description
= 'Service'
950 _service
.allow_tags
= True
952 def _responsable(self
, obj
):
954 responsable
= u
"""<a href="%s"
955 onclick="return showAddAnotherPopup(this)">
956 <img src="%simg/poste-apercu.png"
957 title="Aperçu du poste" />
959 <a href="%s">%s [%d]</a>
961 (reverse('poste_apercu', args
=(obj
.responsable
.id,)),
963 reverse('admin:rh_poste_change', args
=(obj
.responsable
.id,)),
970 dossier
= obj
.responsable
.rh_dossiers
.all() \
971 .order_by('-date_debut')[0]
972 employe_id
= dossier
.employe
.id
973 employe_html
= u
"""<br />
975 onclick="return showAddAnotherPopup(this)">
976 <img src="%simg/employe-apercu.png"
977 title="Aperçu de l'employé">
979 <a href="%s">%s</a>""" % \
980 (reverse('employe_apercu', args
=(employe_id
,)),
982 reverse('admin:rh_employe_change', args
=(employe_id
,)),
987 return "%s %s" % (responsable
, employe_html
)
988 _responsable
.short_description
= 'Responsable'
989 _responsable
.allow_tags
= True
991 def _date_debut(self
, obj
):
992 return date_format(obj
.date_debut
)
993 _date_debut
.short_description
= u
'Début'
994 _date_debut
.admin_order_field
= 'date_debut'
996 def _date_fin(self
, obj
):
997 return date_format(obj
.date_fin
)
998 _date_fin
.short_description
= u
'Fin'
999 _date_fin
.admin_order_field
= 'date_fin'
1001 def _dae(self
, poste
):
1003 postes_dae
= poste
.postes_dae
.all()
1004 if len(postes_dae
) > 0:
1005 poste_dae
= postes_dae
[0]
1007 u
'<a title="Aperçu du dossier" href="%s" ' \
1008 u
'onclick="return showAddAnotherPopup(this);">' \
1009 u
'<img src="%simg/loupe.png" /></a>' % (reverse(
1010 'poste_consulter', args
=("dae-%s" % poste_dae
.id,)
1011 ), settings
.STATIC_URL
)
1013 _dae
.allow_tags
= True
1014 _dae
.short_description
= u
"DAE"
1016 def save_formset(self
, request
, form
, formset
, change
):
1017 instances
= formset
.save(commit
=False)
1018 for instance
in instances
:
1019 if instance
.__class__
== rh
.PosteCommentaire
:
1020 instance
.owner
= request
.user
1021 instance
.date_creation
= datetime
.datetime
.now()
1026 class ResponsableInline(admin
.TabularInline
):
1027 model
= rh
.ResponsableImplantation
1029 fk_name
= "implantation"
1030 form
= ResponsableInlineForm
1033 class ResponsableImplantationAdmin(BaseAdmin
):
1036 inlines
= (ResponsableInline
, )
1037 list_filter
= ('zone_administrative', 'statut', )
1038 list_display
= ('_zone_administrative', '_nom', 'statut', '_responsable', )
1039 list_display_links
= ('_nom',)
1041 readonly_fields
= ('nom', )
1044 'responsable__employe__id',
1045 'responsable__employe__nom',
1046 'responsable__employe__prenom',
1049 inlines
= (ResponsableInline
, )
1051 def _zone_administrative(self
, obj
):
1052 return obj
.zone_administrative
.code
1053 _zone_administrative
.short_description
= u
"Zone administrative"
1054 _zone_administrative
.admin_order_field
= 'zone_administrative__code'
1056 def _nom(self
, obj
):
1058 _nom
.short_description
= u
"Implantation"
1059 _nom
.admin_order_field
= 'nom'
1061 def _responsable(self
, obj
):
1063 employe
= obj
.responsable
.employe
1064 dossiers
= employe
.dossiers_encours()
1065 if len(dossiers
) == 0:
1066 return u
"<span style='color: red;'>%s %s </span>" % (
1067 employe
, u
"sans dossier actif")
1071 if obj
.statut
in (1, 2): # ouverte, ouverture imminente
1072 css
= "style='color: red;'"
1075 return u
"<span %s>Pas de responsable</span>" % css
1076 _responsable
.allow_tags
= True
1077 _responsable
.short_description
= u
"Responsable"
1078 _responsable
.admin_order_field
= 'responsable__employe__nom'
1080 def has_add_permission(self
, request
=None):
1083 def has_change_permission(self
, request
, obj
=None):
1084 return in_drh_or_admin(request
.user
)
1086 def has_delete_permission(self
, request
, obj
=None):
1090 class ServiceAdminBase(ArchivableAdmin
, DerniereModificationAdmin
, BaseAdmin
):
1091 list_display
= ('nom', '_archive', 'derniere_modification')
1092 list_filter
= ('archive', )
1094 (None, {'fields': ('nom', 'archive')}),
1098 class ServiceAdmin(reversion
.VersionAdmin
, ServiceAdminBase
):
1099 ignore_duplicate_revisions
= True
1102 class ServiceProxyAdmin(ServiceAdminBase
):
1103 list_display
= ('nom', '_organigramme', '_archive', )
1106 def __init__(self
, *args
, **kwargs
):
1107 super(ServiceProxyAdmin
, self
).__init__(*args
, **kwargs
)
1108 self
.list_display_links
= (None, )
1110 def queryset(self
, request
):
1111 return super(ServiceProxyAdmin
, self
).queryset(request
) \
1112 .annotate(num_postes
=Count('rh_postes')) \
1113 .filter(num_postes__gt
=0)
1115 def has_add_permission(self
, obj
):
1118 def has_change_permission(self
, request
, obj
=None):
1119 user_groups
= [g
.name
for g
in request
.user
.groups
.all()]
1120 if groups
.CORRESPONDANT_RH
in user_groups
or \
1121 groups
.ADMINISTRATEURS
in user_groups
or \
1122 groups
.DIRECTEUR_DE_BUREAU
in user_groups
or \
1123 in_drh_or_admin(request
.user
):
1127 def _organigramme(self
, obj
):
1128 return """<a href="%s"><strong>Organigramme</strong></a>""" % \
1129 (reverse('rho_service', args
=(obj
.id,)))
1130 _organigramme
.allow_tags
= True
1131 _organigramme
.short_description
= "Organigramme"
1134 class StatutAdmin(reversion
.VersionAdmin
, DerniereModificationAdmin
,
1136 ignore_duplicate_revisions
= True
1137 list_display
= ('code', 'nom', 'derniere_modification')
1140 'fields': ('code', 'nom', ),
1145 class TauxChangeAdmin(reversion
.VersionAdmin
, DerniereModificationAdmin
,
1147 ignore_duplicate_revisions
= True
1148 list_display
= ('taux', 'devise', 'annee', 'derniere_modification')
1149 list_filter
= ('devise',)
1152 'fields': ('taux', 'devise', 'annee', ),
1157 class TypeContratAdmin(reversion
.VersionAdmin
, DerniereModificationAdmin
,
1159 ignore_duplicate_revisions
= True
1160 list_display
= ('nom', 'nom_long', 'derniere_modification')
1163 'fields': ('nom', 'nom_long', ),
1168 class TypePosteAdmin(reversion
.VersionAdmin
, DerniereModificationAdmin
,
1170 ignore_duplicate_revisions
= True
1171 search_fields
= ('nom', 'nom_feminin', )
1172 list_display
= ('nom', 'categorie_emploi', 'derniere_modification')
1173 list_filter
= ('categorie_emploi', 'famille_professionnelle')
1177 'nom', 'nom_feminin', 'is_responsable', 'categorie_emploi',
1178 'famille_professionnelle',
1184 class TypeRemunerationAdmin(reversion
.VersionAdmin
, ArchivableAdmin
,
1185 DerniereModificationAdmin
, BaseAdmin
):
1186 ignore_duplicate_revisions
= True
1188 'nom', 'type_paiement', 'nature_remuneration', '_archive',
1189 'derniere_modification'
1191 list_filter
= ('archive', )
1195 'nom', 'type_paiement', 'nature_remuneration', 'archive'
1201 class TypeRevalorisationAdmin(reversion
.VersionAdmin
,
1202 DerniereModificationAdmin
, BaseAdmin
):
1203 ignore_duplicate_revisions
= True
1204 list_display
= ('nom', 'derniere_modification')
1206 (None, {'fields': ('nom',)}),
1210 class ValeurPointAdmin(reversion
.VersionAdmin
, DerniereModificationAdmin
,
1212 ignore_duplicate_revisions
= True
1214 '_devise_code', '_devise_nom', 'annee', 'implantation',
1215 'valeur', 'derniere_modification'
1217 list_filter
= ('annee', 'devise', 'implantation__zone_administrative', )
1219 (None, {'fields': ('valeur', 'devise', 'implantation', 'annee')}),
1222 def _devise_code(self
, obj
):
1223 return obj
.devise
.code
1224 _devise_code
.short_description
= "Code de la devise"
1226 def _devise_nom(self
, obj
):
1227 return obj
.devise
.nom
1228 _devise_nom
.short_description
= "Nom de la devise"
1231 class ImplantationProxyAdmin(BaseAdmin
):
1232 list_display
= ('nom', '_organigramme')
1235 def __init__(self
, *args
, **kwargs
):
1236 super(ImplantationProxyAdmin
, self
).__init__(*args
, **kwargs
)
1237 self
.list_display_links
= (None, )
1239 def has_add_permission(self
, obj
):
1242 def has_change_permission(self
, request
, obj
=None):
1243 user_groups
= [g
.name
for g
in request
.user
.groups
.all()]
1244 if groups
.CORRESPONDANT_RH
in user_groups
or \
1245 groups
.ADMINISTRATEURS
in user_groups
or \
1246 groups
.DIRECTEUR_DE_BUREAU
in user_groups
or \
1247 in_drh_or_admin(request
.user
):
1251 def _organigramme(self
, obj
):
1252 return '<a href="%s"><strong>Organigramme</strong></a>' % (
1253 reverse('rho_implantation', args
=(obj
.id,))
1255 _organigramme
.allow_tags
= True
1256 _organigramme
.short_description
= "Organigramme"
1259 class RegionProxyAdmin(BaseAdmin
):
1260 list_display
= ('nom', '_organigramme')
1263 def __init__(self
, *args
, **kwargs
):
1264 super(RegionProxyAdmin
, self
).__init__(*args
, **kwargs
)
1265 self
.list_display_links
= (None, )
1267 def has_add_permission(self
, obj
):
1270 def has_change_permission(self
, request
, obj
=None):
1271 user_groups
= [g
.name
for g
in request
.user
.groups
.all()]
1272 if groups
.CORRESPONDANT_RH
in user_groups
or \
1273 groups
.ADMINISTRATEURS
in user_groups
or \
1274 groups
.DIRECTEUR_DE_BUREAU
in user_groups
or \
1275 in_drh_or_admin(request
.user
):
1279 def _organigramme(self
, obj
):
1280 return """<a href="%s"><strong>Organigramme</strong></a>""" % (
1281 reverse('rho_region', args
=(obj
.id,))
1283 _organigramme
.allow_tags
= True
1284 _organigramme
.short_description
= "Organigramme"
1287 admin
.site
.register(rh
.Classement
, ClassementAdmin
)
1288 admin
.site
.register(rh
.Devise
, DeviseAdmin
)
1289 admin
.site
.register(rh
.Dossier
, DossierAdmin
)
1290 admin
.site
.register(EmployeProxy
, EmployeProxyAdmin
)
1291 admin
.site
.register(ServiceProxy
, ServiceProxyAdmin
)
1292 admin
.site
.register(rh
.Employe
, EmployeAdmin
)
1293 admin
.site
.register(rh
.CategorieEmploi
, CategorieEmploiAdmin
)
1294 admin
.site
.register(rh
.FamilleProfessionnelle
)
1295 admin
.site
.register(rh
.OrganismeBstg
, OrganismeBstgAdmin
)
1296 admin
.site
.register(rh
.Poste
, PosteAdmin
)
1297 admin
.site
.register(
1298 rh
.ResponsableImplantationProxy
, ResponsableImplantationAdmin
1300 admin
.site
.register(rh
.Service
, ServiceAdmin
)
1301 admin
.site
.register(rh
.Statut
, StatutAdmin
)
1302 admin
.site
.register(rh
.TauxChange
, TauxChangeAdmin
)
1303 admin
.site
.register(rh
.TypeContrat
, TypeContratAdmin
)
1304 admin
.site
.register(rh
.TypePoste
, TypePosteAdmin
)
1305 admin
.site
.register(rh
.TypeRemuneration
, TypeRemunerationAdmin
)
1306 admin
.site
.register(rh
.TypeRevalorisation
, TypeRevalorisationAdmin
)
1307 admin
.site
.register(rh
.ValeurPoint
, ValeurPointAdmin
)
1308 admin
.site
.register(ImplantationProxy
, ImplantationProxyAdmin
)
1309 admin
.site
.register(RegionProxy
, RegionProxyAdmin
)