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
= employe
= obj
.responsable
.employe
1064 except Exception, e
:
1065 return u
"<span style='color: red;'>Pas de responsable</span><!-- %s -->" % e
1067 dossiers
= employe
.dossiers_encours()
1068 if len(dossiers
) == 0:
1069 return u
"<span style='color: red;'>%s %s </span>" % (
1070 employe
, u
"sans dossier actif")
1073 except Exception, e
:
1074 return u
"<!-- %s -->" % e
1075 _responsable
.allow_tags
= True
1076 _responsable
.short_description
= u
"Responsable"
1077 _responsable
.admin_order_field
= 'responsable__employe__nom'
1079 def has_add_permission(self
, request
=None):
1082 def has_change_permission(self
, request
, obj
=None):
1083 return in_drh_or_admin(request
.user
)
1085 def has_delete_permission(self
, request
, obj
=None):
1089 class ServiceAdminBase(ArchivableAdmin
, DerniereModificationAdmin
, BaseAdmin
):
1090 list_display
= ('nom', '_archive', 'derniere_modification')
1091 list_filter
= ('archive', )
1093 (None, {'fields': ('nom', 'archive')}),
1097 class ServiceAdmin(reversion
.VersionAdmin
, ServiceAdminBase
):
1098 ignore_duplicate_revisions
= True
1101 class ServiceProxyAdmin(ServiceAdminBase
):
1102 list_display
= ('nom', '_organigramme', '_archive', )
1105 def __init__(self
, *args
, **kwargs
):
1106 super(ServiceProxyAdmin
, self
).__init__(*args
, **kwargs
)
1107 self
.list_display_links
= (None, )
1109 def queryset(self
, request
):
1110 return super(ServiceProxyAdmin
, self
).queryset(request
) \
1111 .annotate(num_postes
=Count('rh_postes')) \
1112 .filter(num_postes__gt
=0)
1114 def has_add_permission(self
, obj
):
1117 def has_change_permission(self
, request
, obj
=None):
1118 user_groups
= [g
.name
for g
in request
.user
.groups
.all()]
1119 if groups
.CORRESPONDANT_RH
in user_groups
or \
1120 groups
.ADMINISTRATEURS
in user_groups
or \
1121 groups
.DIRECTEUR_DE_BUREAU
in user_groups
or \
1122 in_drh_or_admin(request
.user
):
1126 def _organigramme(self
, obj
):
1127 return """<a href="%s"><strong>Organigramme</strong></a>""" % \
1128 (reverse('rho_service', args
=(obj
.id,)))
1129 _organigramme
.allow_tags
= True
1130 _organigramme
.short_description
= "Organigramme"
1133 class StatutAdmin(reversion
.VersionAdmin
, DerniereModificationAdmin
,
1135 ignore_duplicate_revisions
= True
1136 list_display
= ('code', 'nom', 'derniere_modification')
1139 'fields': ('code', 'nom', ),
1144 class TauxChangeAdmin(reversion
.VersionAdmin
, DerniereModificationAdmin
,
1146 ignore_duplicate_revisions
= True
1147 list_display
= ('taux', 'devise', 'annee', 'derniere_modification')
1148 list_filter
= ('devise',)
1151 'fields': ('taux', 'devise', 'annee', ),
1156 class TypeContratAdmin(reversion
.VersionAdmin
, DerniereModificationAdmin
,
1158 ignore_duplicate_revisions
= True
1159 list_display
= ('nom', 'nom_long', 'derniere_modification')
1162 'fields': ('nom', 'nom_long', ),
1167 class TypePosteAdmin(reversion
.VersionAdmin
, DerniereModificationAdmin
,
1169 ignore_duplicate_revisions
= True
1170 search_fields
= ('nom', 'nom_feminin', )
1171 list_display
= ('nom', 'categorie_emploi', 'derniere_modification')
1172 list_filter
= ('categorie_emploi', 'famille_professionnelle')
1176 'nom', 'nom_feminin', 'is_responsable', 'categorie_emploi',
1177 'famille_professionnelle',
1183 class TypeRemunerationAdmin(reversion
.VersionAdmin
, ArchivableAdmin
,
1184 DerniereModificationAdmin
, BaseAdmin
):
1185 ignore_duplicate_revisions
= True
1187 'nom', 'type_paiement', 'nature_remuneration', '_archive',
1188 'derniere_modification'
1190 list_filter
= ('archive', )
1194 'nom', 'type_paiement', 'nature_remuneration', 'archive'
1200 class TypeRevalorisationAdmin(reversion
.VersionAdmin
,
1201 DerniereModificationAdmin
, BaseAdmin
):
1202 ignore_duplicate_revisions
= True
1203 list_display
= ('nom', 'derniere_modification')
1205 (None, {'fields': ('nom',)}),
1209 class ValeurPointAdmin(reversion
.VersionAdmin
, DerniereModificationAdmin
,
1211 ignore_duplicate_revisions
= True
1213 '_devise_code', '_devise_nom', 'annee', 'implantation',
1214 'valeur', 'derniere_modification'
1216 list_filter
= ('annee', 'devise', 'implantation__zone_administrative', )
1218 (None, {'fields': ('valeur', 'devise', 'implantation', 'annee')}),
1221 def _devise_code(self
, obj
):
1222 return obj
.devise
.code
1223 _devise_code
.short_description
= "Code de la devise"
1225 def _devise_nom(self
, obj
):
1226 return obj
.devise
.nom
1227 _devise_nom
.short_description
= "Nom de la devise"
1230 class ImplantationProxyAdmin(BaseAdmin
):
1231 list_display
= ('nom', '_organigramme')
1234 def __init__(self
, *args
, **kwargs
):
1235 super(ImplantationProxyAdmin
, self
).__init__(*args
, **kwargs
)
1236 self
.list_display_links
= (None, )
1238 def has_add_permission(self
, obj
):
1241 def has_change_permission(self
, request
, obj
=None):
1242 user_groups
= [g
.name
for g
in request
.user
.groups
.all()]
1243 if groups
.CORRESPONDANT_RH
in user_groups
or \
1244 groups
.ADMINISTRATEURS
in user_groups
or \
1245 groups
.DIRECTEUR_DE_BUREAU
in user_groups
or \
1246 in_drh_or_admin(request
.user
):
1250 def _organigramme(self
, obj
):
1251 return '<a href="%s"><strong>Organigramme</strong></a>' % (
1252 reverse('rho_implantation', args
=(obj
.id,))
1254 _organigramme
.allow_tags
= True
1255 _organigramme
.short_description
= "Organigramme"
1258 class RegionProxyAdmin(BaseAdmin
):
1259 list_display
= ('nom', '_organigramme')
1262 def __init__(self
, *args
, **kwargs
):
1263 super(RegionProxyAdmin
, self
).__init__(*args
, **kwargs
)
1264 self
.list_display_links
= (None, )
1266 def has_add_permission(self
, obj
):
1269 def has_change_permission(self
, request
, obj
=None):
1270 user_groups
= [g
.name
for g
in request
.user
.groups
.all()]
1271 if groups
.CORRESPONDANT_RH
in user_groups
or \
1272 groups
.ADMINISTRATEURS
in user_groups
or \
1273 groups
.DIRECTEUR_DE_BUREAU
in user_groups
or \
1274 in_drh_or_admin(request
.user
):
1278 def _organigramme(self
, obj
):
1279 return """<a href="%s"><strong>Organigramme</strong></a>""" % (
1280 reverse('rho_region', args
=(obj
.id,))
1282 _organigramme
.allow_tags
= True
1283 _organigramme
.short_description
= "Organigramme"
1286 admin
.site
.register(rh
.Classement
, ClassementAdmin
)
1287 admin
.site
.register(rh
.Devise
, DeviseAdmin
)
1288 admin
.site
.register(rh
.Dossier
, DossierAdmin
)
1289 admin
.site
.register(EmployeProxy
, EmployeProxyAdmin
)
1290 admin
.site
.register(ServiceProxy
, ServiceProxyAdmin
)
1291 admin
.site
.register(rh
.Employe
, EmployeAdmin
)
1292 admin
.site
.register(rh
.CategorieEmploi
, CategorieEmploiAdmin
)
1293 admin
.site
.register(rh
.FamilleProfessionnelle
)
1294 admin
.site
.register(rh
.OrganismeBstg
, OrganismeBstgAdmin
)
1295 admin
.site
.register(rh
.Poste
, PosteAdmin
)
1296 admin
.site
.register(
1297 rh
.ResponsableImplantationProxy
, ResponsableImplantationAdmin
1299 admin
.site
.register(rh
.Service
, ServiceAdmin
)
1300 admin
.site
.register(rh
.Statut
, StatutAdmin
)
1301 admin
.site
.register(rh
.TauxChange
, TauxChangeAdmin
)
1302 admin
.site
.register(rh
.TypeContrat
, TypeContratAdmin
)
1303 admin
.site
.register(rh
.TypePoste
, TypePosteAdmin
)
1304 admin
.site
.register(rh
.TypeRemuneration
, TypeRemunerationAdmin
)
1305 admin
.site
.register(rh
.TypeRevalorisation
, TypeRevalorisationAdmin
)
1306 admin
.site
.register(rh
.ValeurPoint
, ValeurPointAdmin
)
1307 admin
.site
.register(ImplantationProxy
, ImplantationProxyAdmin
)
1308 admin
.site
.register(RegionProxy
, RegionProxyAdmin
)