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
.groups
import grp_correspondants_rh
20 from project
.groups
import get_employe_from_user
21 from project
.rh
import models
as rh
22 from project
.permissions
import get_region_user
, \
23 user_gere_obj_de_sa_region
, \
25 user_can_change_obj
, \
28 import project
.rh
.models
as rh
29 from project
.rh
.forms
import \
30 ContratForm
, AyantDroitForm
, EmployeAdminForm
, AjaxSelect
, DossierForm
31 from project
.rh
.change_list
import ChangeList
32 from project
.rh
.forms
import ContratForm
, AyantDroitForm
, EmployeAdminForm
, \
33 AjaxSelect
, DossierForm
, ResponsableInlineForm
36 class BaseAdmin(admin
.ModelAdmin
):
40 'css/admin_custom.css',
41 'jquery-autocomplete/jquery.autocomplete.css',
44 'https://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js',
45 'jquery-autocomplete/jquery.autocomplete.min.js',
48 # Admin pour reversion
50 class ArchivableAdmin(admin
.ModelAdmin
):
52 Admin pour les modèles archivables
54 list_filter
= ('archive', )
56 def queryset(self
, request
):
57 return self
.model
.avec_archives
.all()
59 def _archive(self
, obj
):
64 _archive
.short_description
= u
'Archivé'
65 _archive
.admin_order_field
= 'archive'
68 class RegionProxy(ref
.Region
):
69 """ Proxy utilisé pour les organigrammes par région """
73 verbose_name
= u
"Organigramme par région"
74 verbose_name_plural
= u
"Organigramme par région"
77 class ImplantationProxy(ref
.Implantation
):
78 """ Proxy utilisé pour les organigrammes par implantation """
82 verbose_name
= u
"Organigramme par implantations"
83 verbose_name_plural
= u
"Organigramme par implantations"
86 class ServiceProxy(rh
.Service
):
87 """ Proxy utilisé pour les organigrammes par service """
92 verbose_name
= u
"Organigramme par services"
93 verbose_name_plural
= u
"Organigramme par services"
96 class EmployeProxy(rh
.Employe
):
97 """ Proxy utilisé pour les organigrammes des employés """
101 verbose_name
= u
"Organigramme des employés"
102 verbose_name_plural
= u
"Organigramme des employés"
105 class DateRangeMixin(object):
106 prefixe_recherche_temporelle
= ""
108 def get_changelist(self
, request
, **kwargs
):
109 if 'HTTP_REFERER' in request
.META
.keys():
110 referer
= request
.META
['HTTP_REFERER']
111 referer
= "/".join(referer
.split('/')[3:])
112 referer
= "/%s" % referer
.split('?')[0]
113 change_list_view
= 'admin:%s_%s_changelist' % (
114 self
.model
._meta
.app_label
,
115 self
.model
.__name__
.lower(),)
116 if referer
!= reverse(change_list_view
):
117 params
= request
.GET
.copy()
118 params
.update({'statut': 'Actif'})
123 # Override of the InlineModelAdmin to support the link in the tabular inline
124 class LinkedInline(admin
.options
.InlineModelAdmin
):
125 template
= "admin/linked.html"
126 admin_model_path
= None
128 def __init__(self
, *args
):
129 super(LinkedInline
, self
).__init__(*args
)
130 if self
.admin_model_path
is None:
131 self
.admin_model_path
= self
.model
.__name__
.lower()
134 class ProtectRegionMixin(object):
136 def queryset(self
, request
):
137 qs
= super(ProtectRegionMixin
, self
).queryset(request
)
139 if in_drh_or_admin(request
.user
):
142 if user_gere_obj_de_sa_region(request
.user
):
143 region_user
= get_region_user(request
.user
)
144 q
= Q(**{self
.model
.prefix_implantation
: \
146 qs
= qs
.filter(q
).distinct()
150 def has_add_permission(self
, request
):
151 return user_can_add_obj(request
.user
)
153 def has_change_permission(self
, request
, obj
=None):
154 return user_can_change_obj(request
.user
, obj
) if obj
else True
156 def has_delete_permission(self
, request
, obj
=None):
157 return user_can_delete_obj(request
.user
, obj
) if obj
else True
160 class DerniereModificationAdmin(admin
.ModelAdmin
):
162 def queryset(self
, request
):
163 qs
= super(DerniereModificationAdmin
, self
).queryset(request
)
164 ct
= ContentType
.objects
.get_for_model(self
.model
)
165 db_table
= self
.model
._meta
.db_table
166 pk
= self
.model
._meta
.pk
.column
167 return qs
.extra(select
={
169 "SELECT action_time FROM django_admin_log "
170 "WHERE content_type_id = %d AND object_id = %s.%s "
171 "ORDER BY action_time DESC "
172 "LIMIT 1" % (ct
.id, db_table
, pk
),
176 "INNER JOIN django_admin_log l ON l.user_id = u.id "
177 "WHERE l.content_type_id = %d AND object_id = %s.%s "
178 "ORDER BY action_time DESC "
179 "LIMIT 1" % (ct
.id, db_table
, pk
),
182 def derniere_modification(self
, obj
):
184 if obj
.date_modification
:
185 text
+= obj
.date_modification
.strftime('%d-%m-%Y %H:%M')
186 if obj
.user_modification
:
187 text
+= ' par ' + obj
.user_modification
189 derniere_modification
.short_description
= u
'dernière modification'
190 derniere_modification
.admin_order_field
= 'date_modification'
195 class CommentaireInlineForm(forms
.ModelForm
):
197 def save(self
, commit
=True):
199 # Hack: reversion.VersionAdmin ne sauvegarde pas les champs qui ne
200 # sont pas explicitement dans le formulaire. Il plante cependant
201 # leur valeur dans `self.initial`. Ceci est un peu fragile. Si
202 # c'est possible, il serait plus approprié que Reversion se rende
203 # compte qu'il manque des champs.
204 instance
= super(CommentaireInlineForm
, self
).save(commit
=False)
205 if instance
.owner_id
is None and 'owner' in self
.initial
:
206 instance
.owner_id
= self
.initial
['owner']
207 if instance
.date_creation
is None and 'date_creation' in self
.initial
:
208 instance
.date_creation
= self
.initial
['date_creation']
215 class ReadOnlyInlineMixin(object):
217 def get_readonly_fields(self
, request
, obj
=None):
218 return [f
.name
for f
in self
.model
._meta
.fields
]
221 class AyantDroitInline(admin
.StackedInline
):
222 model
= rh
.AyantDroit
223 form
= AyantDroitForm
230 ('nom_affichage', 'genre'),
238 class AyantDroitCommentaireInline(admin
.TabularInline
):
239 readonly_fields
= ('owner',)
240 model
= rh
.AyantDroitCommentaire
242 form
= CommentaireInlineForm
245 class ContratInline(admin
.TabularInline
):
251 class DossierROInline(ReadOnlyInlineMixin
, LinkedInline
):
252 template
= "admin/rh/dossier/linked.html"
257 def has_add_permission(self
, request
=None):
260 def has_change_permission(self
, request
, obj
=None):
263 def has_delete_permission(self
, request
, obj
=None):
267 class DossierCommentaireInline(admin
.TabularInline
):
268 readonly_fields
= ('owner',)
269 model
= rh
.DossierCommentaire
271 form
= CommentaireInlineForm
274 class DossierPieceInline(admin
.TabularInline
):
275 model
= rh
.DossierPiece
279 class EmployeInline(admin
.TabularInline
):
283 class EmployeCommentaireInline(admin
.TabularInline
):
284 readonly_fields
= ('owner',)
285 model
= rh
.EmployeCommentaire
287 form
= CommentaireInlineForm
290 class EmployePieceInline(admin
.TabularInline
):
291 model
= rh
.EmployePiece
295 class PosteCommentaireInline(admin
.TabularInline
):
296 readonly_fields
= ('owner',)
297 model
= rh
.PosteCommentaire
299 form
= CommentaireInlineForm
302 class PosteFinancementInline(admin
.TabularInline
):
303 model
= rh
.PosteFinancement
306 class PostePieceInline(admin
.TabularInline
):
307 model
= rh
.PostePiece
310 class RemunerationInline(admin
.TabularInline
):
311 model
= rh
.Remuneration
315 class RemunerationROInline(ReadOnlyInlineMixin
, RemunerationInline
):
319 class TypePosteInline(admin
.TabularInline
):
323 class PosteComparaisonInline(admin
.TabularInline
):
324 model
= rh
.PosteComparaison
327 class ClassementAdmin(reversion
.VersionAdmin
, DerniereModificationAdmin
,
329 ignore_duplicate_revisions
= True
330 list_display
= ('_classement', 'derniere_modification')
332 (None, {'fields': ('type', 'echelon', 'degre', 'coefficient',)}),
335 def _classement(self
, obj
):
337 _classement
.short_description
= u
"Classement"
340 class DeviseAdmin(reversion
.VersionAdmin
, ArchivableAdmin
,
341 DerniereModificationAdmin
, BaseAdmin
):
342 ignore_duplicate_revisions
= True
344 'code', 'nom', '_archive', 'derniere_modification',
346 list_filter
= ('archive', )
348 (None, {'fields': ('code', 'nom', 'archive', )}),
352 class DossierAdmin(DateRangeMixin
, ProtectRegionMixin
, reversion
.VersionAdmin
,
353 AjaxSelect
, DerniereModificationAdmin
, BaseAdmin
):
354 change_list_template
= "admin/rh/dossier/change_list.html"
355 ignore_duplicate_revisions
= True
356 alphabet_filter
= 'employe__nom'
364 'poste__nom_feminin',
365 'poste__implantation__nom',
377 'derniere_modification',
380 list_display_links
= ('_nom',)
382 'poste__implantation__region',
383 'poste__implantation',
384 'poste__type_poste__categorie_emploi',
386 'rh_contrats__type_contrat',
389 inlines
= (DossierPieceInline
, ContratInline
,
391 DossierCommentaireInline
,
400 'organisme_bstg',)}),
405 'remplacement_de', )}),
409 ('regime_travail', 'regime_travail_nb_heure_semaine'),)}),
410 ('Occupation du Poste par cet Employe', {
411 'fields': (('date_debut', 'date_fin'), )}
414 form
= make_ajax_form(rh
.Dossier
, {
415 'employe': 'employes',
417 'remplacement_de': 'dossiers',
418 }, superclass
=DossierForm
)
420 def lookup_allowed(self
, key
, value
):
422 'employe__nom__istartswith',
423 'poste__implantation__region__id__exact',
424 'poste__implantation__id__exact',
425 'poste__type_poste__id__exact',
426 'poste__type_poste__categorie_emploi__id__exact',
427 'rh_contrats__type_contrat__id__exact',
435 _id
.short_description
= u
"#"
436 _id
.admin_order_field
= "id"
438 def _apercu(self
, d
):
439 apercu_link
= u
"""<a title="Aperçu du dossier"
440 onclick="return showAddAnotherPopup(this);"
442 <img src="%simg/dossier-apercu.png" />
444 (reverse('dossier_apercu', args
=(d
.id,)),
448 _apercu
.allow_tags
= True
449 _apercu
.short_description
= u
""
453 _nom
.allow_tags
= True
454 _nom
.short_description
= u
"Dossier"
456 def _employe(self
, obj
):
457 employe
= obj
.employe
458 view_link
= reverse('employe_apercu', args
=(employe
.id,))
459 edit_link
= reverse('admin:rh_employe_change', args
=(employe
.id,))
461 view
= u
"""<a href="%s"
462 title="Aperçu l'employé"
463 onclick="return showAddAnotherPopup(this);">
464 <img src="%simg/employe-apercu.png" />
465 </a>""" % (view_link
, settings
.STATIC_URL
,)
466 return u
"""%s<a href='%s' style="%s;">%s</a>""" % \
467 (view
, edit_link
, style
, employe
)
468 _employe
.allow_tags
= True
469 _employe
.short_description
= u
"Employé"
470 _employe
.admin_order_field
= "employe__nom"
472 def _poste(self
, dossier
):
473 link
= u
"""<a title="Aperçu du poste"
474 onclick="return showAddAnotherPopup(this);"
475 href='%s'><img src="%simg/poste-apercu.png" />
477 <a href="%s" title="Modifier le poste">%s [%d]</a>""" % \
478 (reverse('poste_apercu', args
=(dossier
.poste
.id,)),
480 reverse('admin:rh_poste_change', args
=(dossier
.poste
.id,)),
485 _poste
.allow_tags
= True
486 _poste
.short_description
= u
'Poste'
487 _poste
.admin_order_field
= 'poste__nom'
489 def _region(self
, obj
):
490 return obj
.poste
.implantation
.region
.code
491 _region
.short_description
= u
"Région"
492 _region
.admin_order_field
= 'poste__implantation__region__code'
494 def _implantation(self
, obj
):
495 return obj
.poste
.implantation
.nom
496 _implantation
.short_description
= u
"Implantation"
497 _implantation
.admin_order_field
= 'poste__implantation__nom'
499 def _date_debut(self
, obj
):
500 return date(obj
.date_debut
)
502 _date_debut
.short_description
= u
'Début'
503 _date_debut
.admin_order_field
= 'date_debut'
505 def _date_fin(self
, obj
):
506 return date(obj
.date_fin
)
507 _date_fin
.short_description
= u
'Fin'
508 _date_fin
.admin_order_field
= 'date_fin'
510 def _date_modification(self
, obj
):
511 return date(obj
.date_modification
) \
512 if obj
.date_modification
is not None else "(aucune)"
513 _date_modification
.short_description
= u
'date modification'
514 _date_modification
.admin_order_field
= 'date_modification'
518 dossiers_dae
= d
.dossiers_dae
.all()
519 if len(dossiers_dae
) > 0:
520 dossier_dae
= dossiers_dae
[0]
521 apercu_link
= u
"""<a title="Aperçu du dossier"
522 onclick="return showAddAnotherPopup(this);"
524 <img src="%simg/loupe.png" />
526 (reverse('embauche_consulter', args
=(dossier_dae
.id,)),
530 _dae
.allow_tags
= True
531 _dae
.short_description
= u
"DAE"
533 def save_formset(self
, request
, form
, formset
, change
):
534 instances
= formset
.save(commit
=False)
535 for instance
in instances
:
536 if instance
.__class__
== rh
.DossierCommentaire
:
537 instance
.owner
= request
.user
538 instance
.date_creation
= datetime
.datetime
.now()
542 class EmployeAdminBase(DateRangeMixin
, ProtectRegionMixin
,
543 DerniereModificationAdmin
, BaseAdmin
):
544 prefixe_recherche_temporelle
= "rh_dossiers__"
545 alphabet_filter
= 'nom'
546 DEFAULT_ALPHABET
= u
'ABCDEFGHIJKLMNOPQRSTUVWXYZ'
548 'id', 'nom', 'prenom', 'nom_affichage',
549 'rh_dossiers__poste__nom',
550 'rh_dossiers__poste__nom_feminin'
553 form
= EmployeAdminForm
555 '_id', '_apercu', '_nom', '_dossiers_postes',
559 'derniere_modification'
561 list_display_links
= ('_nom',)
563 'rh_dossiers__poste__implantation__region',
564 'rh_dossiers__poste__implantation', 'nb_postes'
567 AyantDroitInline
, DossierROInline
, EmployePieceInline
,
568 EmployeCommentaireInline
574 ('nom_affichage', 'genre'),
579 ('Informations personnelles', {
580 'fields': ('situation_famille', 'date_entree', )
582 ('Coordonnées personnelles', {
584 ('tel_domicile', 'tel_cellulaire'),
585 ('adresse', 'ville'),
586 ('code_postal', 'province'),
595 _id
.short_description
= u
"#"
596 _id
.admin_order_field
= "id"
598 def _apercu(self
, obj
):
599 return u
"""<a title="Aperçu de l'employé"
600 onclick="return showAddAnotherPopup(this);"
602 <img src="%simg/employe-apercu.png" />
604 (reverse('employe_apercu', args
=(obj
.id,)), settings
.STATIC_URL
)
605 _apercu
.allow_tags
= True
606 _apercu
.short_description
= u
""
609 edit_link
= reverse('admin:rh_employe_change', args
=(obj
.id,))
610 return u
"""<a href='%s'><strong>%s</strong></a>""" % \
611 (edit_link
, "%s %s" % (obj
.nom
.upper(), obj
.prenom
))
612 _nom
.allow_tags
= True
613 _nom
.short_description
= u
"Employé"
614 _nom
.admin_order_field
= "nom"
616 def _region(self
, obj
):
618 d
= rh
.Dossier
.objects
.filter(employe
=obj
.id, principal
=True)[0]
619 region
= d
.poste
.implantation
.region
.code
623 _region
.short_description
= u
"Région"
625 def _implantation(self
, obj
):
627 d
= rh
.Dossier
.objects
.filter(employe
=obj
.id, principal
=True)[0]
628 implantation
= d
.poste
.implantation
.nom
632 _implantation
.short_description
= u
"Implantation"
634 def _dossiers_postes(self
, obj
):
636 for d
in obj
.rh_dossiers
.all().order_by('-date_debut'):
639 if d
.date_fin
is not None and d
.date_fin
< datetime
.date
.today():
640 link_style
= u
' style="color:#666;"'
641 list_style
= u
' style="color:grey;"'
643 dossier
= u
"""<a title="Aperçu du dossier"
645 onclick="return showAddAnotherPopup(this);"
646 title="Aperçu du dossier">
647 <img src="%simg/dossier-apercu.png" />
649 <a href="%s"%s>Dossier</a>
651 (reverse('dossier_apercu', args
=(d
.id,)),
653 reverse('admin:rh_dossier_change', args
=(d
.id,)),
656 poste
= u
"""<a title="Aperçu du poste"
658 onclick="return showAddAnotherPopup(this);"
659 title="Aperçu du poste">
660 <img src="%simg/poste-apercu.png" />
662 <a href="%s"%s>%s [%d]</a>
664 (reverse('poste_apercu', args
=(d
.poste
.id,)),
666 reverse('admin:rh_poste_change', args
=(d
.poste
.id,)),
671 link
= u
"""<li%s>%s %s</li>""" % \
672 (list_style
, dossier
, poste
)
675 return "<ul>%s</ul>" % "\n".join(l
)
676 _dossiers_postes
.allow_tags
= True
677 _dossiers_postes
.short_description
= u
"Dossiers et postes"
679 def _date_modification(self
, obj
):
680 return date(obj
.date_modification
) \
681 if obj
.date_modification
is not None else "(aucune)"
682 _date_modification
.short_description
= u
'date modification'
683 _date_modification
.admin_order_field
= 'date_modification'
685 def queryset(self
, request
):
686 qs
= super(EmployeAdminBase
, self
).queryset(request
)
687 return qs
.select_related(depth
=1).order_by('nom')
689 def save_formset(self
, request
, form
, formset
, change
):
690 instances
= formset
.save(commit
=False)
691 for instance
in instances
:
692 if instance
.__class__
== rh
.EmployeCommentaire
:
693 instance
.owner
= request
.user
694 instance
.date_creation
= datetime
.datetime
.now()
698 class EmployeAdmin(reversion
.VersionAdmin
, EmployeAdminBase
):
699 change_list_template
= "admin/rh/employe/change_list.html"
700 ignore_duplicate_revisions
= True
703 class EmployeProxyAdmin(EmployeAdminBase
):
704 list_display
= ('_id', '_apercu', '_nom', '_organigramme')
708 def __init__(self
, *args
, **kwargs
):
709 super(EmployeProxyAdmin
, self
).__init__(*args
, **kwargs
)
710 self
.list_display_links
= (None, )
712 def queryset(self
, request
):
713 qs
= super(ProtectRegionMixin
, self
).queryset(request
)
715 if in_drh_or_admin(request
.user
) or \
716 user_gere_obj_de_sa_region(request
.user
):
721 def has_add_permission(self
, obj
):
724 def has_change_permission(self
, request
, obj
=None):
725 user_groups
= request
.user
.groups
.all()
726 if groups
.grp_correspondants_rh
in user_groups
or \
727 groups
.grp_administrateurs
in user_groups
or \
728 groups
.grp_directeurs_bureau
in user_groups
or \
729 in_drh_or_admin(request
.user
):
733 def _organigramme(self
, obj
):
735 for d
in rh
.Dossier
.objects
.filter(
736 Q(date_fin__gt
=datetime
.date
.today()) |
Q(date_fin
=None),
737 Q(date_debut__lt
=datetime
.date
.today()) |
Q(date_debut
=None),
741 u
'Organigramme, niveau: ' \
742 u
'<input type="text" id="level_%s" ' \
743 u
'style="width:30px;height:15px;" /> ' \
744 u
'<input type="button" value="Générer" ' \
745 u
"""onclick="window.location='%s' + """ \
746 u
"""document.getElementById('level_%s').value" />""" % (
748 reverse('rho_employe_sans_niveau', args
=(d
.poste
.id,)),
751 link
= u
"""<li>%s [%s]:<br />%s</li>""" % (
757 return "<ul>%s</ul>" % "\n".join(l
)
759 _organigramme
.allow_tags
= True
760 _organigramme
.short_description
= "Organigramme"
763 class CategorieEmploiAdmin(reversion
.VersionAdmin
,
764 DerniereModificationAdmin
, BaseAdmin
):
765 ignore_duplicate_revisions
= True
766 list_display
= ('nom', 'derniere_modification')
767 inlines
= (TypePosteInline
,)
769 (None, {'fields': ('nom', )}),
773 class OrganismeBstgAdmin(reversion
.VersionAdmin
, DerniereModificationAdmin
,
775 ignore_duplicate_revisions
= True
776 search_fields
= ('nom',)
777 list_display
= ('nom', 'type', 'pays', 'derniere_modification')
778 list_filter
= ('type', )
779 inlines
= (DossierROInline
,)
781 (None, {'fields': ('nom', 'type', 'pays',)}),
785 class PosteAdmin(DateRangeMixin
, ProtectRegionMixin
, reversion
.VersionAdmin
,
786 AjaxSelect
, DerniereModificationAdmin
, BaseAdmin
):
787 change_list_template
= "admin/rh/poste/change_list.html"
788 ignore_duplicate_revisions
= True
789 form
= make_ajax_form(rh
.Poste
, {
790 'implantation': 'implantations',
791 'type_poste': 'typepostes',
792 'responsable': 'postes',
793 'valeur_point_min': 'valeurpoints',
794 'valeur_point_max': 'valeurpoints',
796 alphabet_filter
= 'nom'
801 'implantation__region__code',
802 'implantation__region__nom',
803 'rh_dossiers__employe__id',
804 'rh_dossiers__employe__nom',
805 'rh_dossiers__employe__prenom',
808 '_id', '_apercu', '_nom', '_occupe_par', 'implantation', '_service',
809 '_responsable', 'date_debut', 'date_fin', 'derniere_modification',
813 'implantation__region',
817 'type_poste__categorie_emploi',
818 'type_poste__famille_professionnelle',
821 list_display_links
= ('_nom',)
824 ('nom', 'nom_feminin'),
834 'regime_travail_nb_heure_semaine'),
838 'fields': (('local', 'expatrie', 'mise_a_disposition', 'appel'),)}
841 'fields': (('classement_min',
854 ('Comparatifs de rémunération', {
855 'fields': ('devise_comparaison',
856 ('comp_locale_min', 'comp_locale_max'),
857 ('comp_universite_min', 'comp_universite_max'),
858 ('comp_fonctionpub_min', 'comp_fonctionpub_max'),
859 ('comp_ong_min', 'comp_ong_max'),
860 ('comp_autre_min', 'comp_autre_max'))}
863 'fields': ('justification',)}
865 ('Autres Méta-données', {
866 'fields': ('date_debut', 'date_fin')}
870 inlines
= (PosteFinancementInline
,
873 PosteComparaisonInline
,
874 PosteCommentaireInline
, )
876 def lookup_allowed(self
, key
, value
):
878 'date_debut__gte', 'date_debut__isnull', 'date_fin__lte',
879 'date_fin__isnull', 'implantation__region__id__exact',
880 'implantation__id__exact', 'type_poste__id__exact',
881 'type_poste__categorie_emploi__id__exact', 'service__id__exact',
882 'service__isnull', 'vacant__exact', 'vacant__isnull',
883 ) or super(PosteAdmin
, self
).lookup_allowed(key
, value
)
887 _id
.short_description
= '#'
888 _id
.admin_order_field
= 'id'
890 def _apercu(self
, poste
):
891 view_link
= u
"""<a onclick="return showAddAnotherPopup(this);"
892 title="Aperçu du poste"
894 <img src="%simg/poste-apercu.png" />
896 (reverse('poste_apercu', args
=(poste
.id,)),
897 settings
.STATIC_URL
,)
899 _apercu
.allow_tags
= True
900 _apercu
.short_description
= ''
902 def _nom(self
, poste
):
903 return """<a href="%s">%s</a>""" % \
904 (reverse('admin:rh_poste_change', args
=(poste
.id,)),
906 _nom
.allow_tags
= True
907 _nom
.short_description
= u
'Poste'
908 _nom
.admin_order_field
= 'nom'
910 def _occupe_par(self
, obj
):
911 """Formatte la méthode Poste.occupe_par() pour l'admin"""
913 if obj
.date_fin
is not None and obj
.date_fin
< datetime
.date
.today():
915 employes
= obj
.occupe_par()
919 link
= u
"""<a href='%s'
920 title='Aperçu de l\'employé'
921 onclick='return showAddAnotherPopup(this)'>
922 <img src='%simg/employe-apercu.png' />
924 <a href='%s'>%s</a>""" % \
925 (reverse('employe_apercu', args
=(e
.id,)),
927 reverse('admin:rh_employe_change', args
=(e
.id,)),
930 output
= "\n<br />".join(l
)
932 _occupe_par
.allow_tags
= True
933 _occupe_par
.short_description
= "Occupé par"
935 def _region(self
, poste
):
936 return poste
.implantation
.region
.code
937 _region
.short_description
= 'Région'
938 _region
.admin_order_field
= 'implantation__region__code'
940 def _implantation(self
, poste
):
941 return poste
.implantation
.nom
942 _implantation
.short_description
= 'Implantation'
943 _implantation
.admin_order_field
= 'implantation'
945 def _service(self
, obj
):
947 _service
.short_description
= 'Service'
948 _service
.allow_tags
= True
950 def _responsable(self
, obj
):
952 responsable
= u
"""<a href="%s"
953 onclick="return showAddAnotherPopup(this)">
954 <img src="%simg/poste-apercu.png"
955 title="Aperçu du poste" />
957 <a href="%s">%s [%d]</a>
959 (reverse('poste_apercu', args
=(obj
.responsable
.id,)),
961 reverse('admin:rh_poste_change', args
=(obj
.responsable
.id,)),
968 dossier
= obj
.responsable
.rh_dossiers
.all() \
969 .order_by('-date_debut')[0]
970 employe_id
= dossier
.employe
.id
971 employe_html
= u
"""<br />
973 onclick="return showAddAnotherPopup(this)">
974 <img src="%simg/employe-apercu.png"
975 title="Aperçu de l'employé">
977 <a href="%s">%s</a>""" % \
978 (reverse('employe_apercu', args
=(employe_id
,)),
980 reverse('admin:rh_employe_change', args
=(employe_id
,)),
985 return "%s %s" % (responsable
, employe_html
)
986 _responsable
.short_description
= 'Responsable'
987 _responsable
.allow_tags
= True
989 def _date_debut(self
, obj
):
990 return date_format(obj
.date_debut
)
991 _date_debut
.short_description
= u
'Début'
992 _date_debut
.admin_order_field
= 'date_debut'
994 def _date_fin(self
, obj
):
995 return date_format(obj
.date_fin
)
996 _date_fin
.short_description
= u
'Fin'
997 _date_fin
.admin_order_field
= 'date_fin'
999 def _dae(self
, poste
):
1001 postes_dae
= poste
.postes_dae
.all()
1002 if len(postes_dae
) > 0:
1003 poste_dae
= postes_dae
[0]
1005 u
'<a title="Aperçu du dossier" href="%s" ' \
1006 u
'onclick="return showAddAnotherPopup(this);">' \
1007 u
'<img src="%simg/loupe.png" /></a>' % (reverse(
1008 'poste_consulter', args
=("dae-%s" % poste_dae
.id,)
1009 ), settings
.STATIC_URL
)
1011 _dae
.allow_tags
= True
1012 _dae
.short_description
= u
"DAE"
1014 def save_formset(self
, request
, form
, formset
, change
):
1015 instances
= formset
.save(commit
=False)
1016 for instance
in instances
:
1017 if instance
.__class__
== rh
.PosteCommentaire
:
1018 instance
.owner
= request
.user
1019 instance
.date_creation
= datetime
.datetime
.now()
1024 class ResponsableInline(admin
.TabularInline
):
1025 model
= rh
.ResponsableImplantation
1027 fk_name
= "implantation"
1028 form
= ResponsableInlineForm
1031 class ResponsableImplantationAdmin(BaseAdmin
):
1034 inlines
= (ResponsableInline
, )
1035 list_filter
= ('region', 'statut', )
1036 list_display
= ('_region', '_nom', 'statut', '_responsable', )
1037 list_display_links
= ('_nom',)
1039 readonly_fields
= ('nom', )
1042 'responsable__employe__id',
1043 'responsable__employe__nom',
1044 'responsable__employe__prenom',
1047 inlines
= (ResponsableInline
, )
1049 def _region(self
, obj
):
1050 return obj
.region
.code
1051 _region
.short_description
= u
"Région"
1052 _region
.admin_order_field
= 'region__code'
1054 def _nom(self
, obj
):
1056 _nom
.short_description
= u
"Implantation"
1057 _nom
.admin_order_field
= 'nom'
1059 def _responsable(self
, obj
):
1061 employe
= obj
.responsable
.employe
1062 dossiers
= employe
.dossiers_encours()
1063 if len(dossiers
) == 0:
1064 return u
"<span style='color: red;'>%s %s </span>" % (
1065 employe
, u
"sans dossier actif")
1069 if obj
.statut
in (1, 2): # ouverte, ouverture imminente
1070 css
= "style='color: red;'"
1073 return u
"<span %s>Pas de responsable</span>" % css
1074 _responsable
.allow_tags
= True
1075 _responsable
.short_description
= u
"Responsable"
1076 _responsable
.admin_order_field
= 'responsable__employe__nom'
1078 def has_add_permission(self
, request
=None):
1081 def has_change_permission(self
, request
, obj
=None):
1082 return in_drh_or_admin(request
.user
)
1084 def has_delete_permission(self
, request
, obj
=None):
1088 class ServiceAdminBase(ArchivableAdmin
, DerniereModificationAdmin
, BaseAdmin
):
1089 list_display
= ('nom', '_archive', 'derniere_modification')
1090 list_filter
= ('archive', )
1092 (None, {'fields': ('nom', 'archive')}),
1096 class ServiceAdmin(reversion
.VersionAdmin
, ServiceAdminBase
):
1097 ignore_duplicate_revisions
= True
1100 class ServiceProxyAdmin(ServiceAdminBase
):
1101 list_display
= ('nom', '_organigramme', '_archive', )
1104 def __init__(self
, *args
, **kwargs
):
1105 super(ServiceProxyAdmin
, self
).__init__(*args
, **kwargs
)
1106 self
.list_display_links
= (None, )
1108 def queryset(self
, request
):
1109 return super(ServiceProxyAdmin
, self
).queryset(request
) \
1110 .annotate(num_postes
=Count('rh_postes')) \
1111 .filter(num_postes__gt
=0)
1113 def has_add_permission(self
, obj
):
1116 def has_change_permission(self
, request
, obj
=None):
1117 user_groups
= request
.user
.groups
.all()
1118 if groups
.grp_correspondants_rh
in user_groups
or \
1119 groups
.grp_administrateurs
in user_groups
or \
1120 groups
.grp_directeurs_bureau
in user_groups
or \
1121 in_drh_or_admin(request
.user
):
1125 def _organigramme(self
, obj
):
1126 return """<a href="%s"><strong>Organigramme</strong></a>""" % \
1127 (reverse('rho_service', args
=(obj
.id,)))
1128 _organigramme
.allow_tags
= True
1129 _organigramme
.short_description
= "Organigramme"
1132 class StatutAdmin(reversion
.VersionAdmin
, DerniereModificationAdmin
,
1134 ignore_duplicate_revisions
= True
1135 list_display
= ('code', 'nom', 'derniere_modification')
1138 'fields': ('code', 'nom', ),
1143 class TauxChangeAdmin(reversion
.VersionAdmin
, DerniereModificationAdmin
,
1145 ignore_duplicate_revisions
= True
1146 list_display
= ('taux', 'devise', 'annee', 'derniere_modification')
1147 list_filter
= ('devise',)
1150 'fields': ('taux', 'devise', 'annee', ),
1155 class TypeContratAdmin(reversion
.VersionAdmin
, DerniereModificationAdmin
,
1157 ignore_duplicate_revisions
= True
1158 list_display
= ('nom', 'nom_long', 'derniere_modification')
1161 'fields': ('nom', 'nom_long', ),
1166 class TypePosteAdmin(reversion
.VersionAdmin
, DerniereModificationAdmin
,
1168 ignore_duplicate_revisions
= True
1169 search_fields
= ('nom', 'nom_feminin', )
1170 list_display
= ('nom', 'categorie_emploi', 'derniere_modification')
1171 list_filter
= ('categorie_emploi', 'famille_professionnelle')
1175 'nom', 'nom_feminin', 'is_responsable', 'categorie_emploi',
1176 'famille_professionnelle',
1182 class TypeRemunerationAdmin(reversion
.VersionAdmin
, ArchivableAdmin
,
1183 DerniereModificationAdmin
, BaseAdmin
):
1184 ignore_duplicate_revisions
= True
1186 'nom', 'type_paiement', 'nature_remuneration', '_archive',
1187 'derniere_modification'
1189 list_filter
= ('archive', )
1193 'nom', 'type_paiement', 'nature_remuneration', 'archive'
1199 class TypeRevalorisationAdmin(reversion
.VersionAdmin
,
1200 DerniereModificationAdmin
, BaseAdmin
):
1201 ignore_duplicate_revisions
= True
1202 list_display
= ('nom', 'derniere_modification')
1204 (None, {'fields': ('nom',)}),
1208 class ValeurPointAdmin(reversion
.VersionAdmin
, DerniereModificationAdmin
,
1210 ignore_duplicate_revisions
= True
1212 '_devise_code', '_devise_nom', 'annee', 'implantation',
1213 'valeur', 'derniere_modification'
1215 list_filter
= ('annee', 'devise', 'implantation__region', )
1217 (None, {'fields': ('valeur', 'devise', 'implantation', 'annee')}),
1220 def _devise_code(self
, obj
):
1221 return obj
.devise
.code
1222 _devise_code
.short_description
= "Code de la devise"
1224 def _devise_nom(self
, obj
):
1225 return obj
.devise
.nom
1226 _devise_nom
.short_description
= "Nom de la devise"
1229 class ImplantationProxyAdmin(BaseAdmin
):
1230 list_display
= ('nom', '_organigramme')
1233 def __init__(self
, *args
, **kwargs
):
1234 super(ImplantationProxyAdmin
, self
).__init__(*args
, **kwargs
)
1235 self
.list_display_links
= (None, )
1237 def has_add_permission(self
, obj
):
1240 def has_change_permission(self
, request
, obj
=None):
1241 user_groups
= request
.user
.groups
.all()
1242 if groups
.grp_correspondants_rh
in user_groups
or \
1243 groups
.grp_administrateurs
in user_groups
or \
1244 groups
.grp_directeurs_bureau
in user_groups
or \
1245 in_drh_or_admin(request
.user
):
1249 def _organigramme(self
, obj
):
1250 return '<a href="%s"><strong>Organigramme</strong></a>' % (
1251 reverse('rho_implantation', args
=(obj
.id,))
1253 _organigramme
.allow_tags
= True
1254 _organigramme
.short_description
= "Organigramme"
1257 class RegionProxyAdmin(BaseAdmin
):
1258 list_display
= ('nom', '_organigramme')
1261 def __init__(self
, *args
, **kwargs
):
1262 super(RegionProxyAdmin
, self
).__init__(*args
, **kwargs
)
1263 self
.list_display_links
= (None, )
1265 def has_add_permission(self
, obj
):
1268 def has_change_permission(self
, request
, obj
=None):
1269 user_groups
= request
.user
.groups
.all()
1270 if groups
.grp_correspondants_rh
in user_groups
or \
1271 groups
.grp_administrateurs
in user_groups
or \
1272 groups
.grp_directeurs_bureau
in user_groups
or \
1273 in_drh_or_admin(request
.user
):
1277 def _organigramme(self
, obj
):
1278 return """<a href="%s"><strong>Organigramme</strong></a>""" % (
1279 reverse('rho_region', args
=(obj
.id,))
1281 _organigramme
.allow_tags
= True
1282 _organigramme
.short_description
= "Organigramme"
1285 admin
.site
.register(rh
.Classement
, ClassementAdmin
)
1286 admin
.site
.register(rh
.Devise
, DeviseAdmin
)
1287 admin
.site
.register(rh
.Dossier
, DossierAdmin
)
1288 admin
.site
.register(EmployeProxy
, EmployeProxyAdmin
)
1289 admin
.site
.register(ServiceProxy
, ServiceProxyAdmin
)
1290 admin
.site
.register(rh
.Employe
, EmployeAdmin
)
1291 admin
.site
.register(rh
.CategorieEmploi
, CategorieEmploiAdmin
)
1292 admin
.site
.register(rh
.FamilleProfessionnelle
)
1293 admin
.site
.register(rh
.OrganismeBstg
, OrganismeBstgAdmin
)
1294 admin
.site
.register(rh
.Poste
, PosteAdmin
)
1295 admin
.site
.register(
1296 rh
.ResponsableImplantationProxy
, ResponsableImplantationAdmin
1298 admin
.site
.register(rh
.Service
, ServiceAdmin
)
1299 admin
.site
.register(rh
.Statut
, StatutAdmin
)
1300 admin
.site
.register(rh
.TauxChange
, TauxChangeAdmin
)
1301 admin
.site
.register(rh
.TypeContrat
, TypeContratAdmin
)
1302 admin
.site
.register(rh
.TypePoste
, TypePosteAdmin
)
1303 admin
.site
.register(rh
.TypeRemuneration
, TypeRemunerationAdmin
)
1304 admin
.site
.register(rh
.TypeRevalorisation
, TypeRevalorisationAdmin
)
1305 admin
.site
.register(rh
.ValeurPoint
, ValeurPointAdmin
)
1306 admin
.site
.register(ImplantationProxy
, ImplantationProxyAdmin
)
1307 admin
.site
.register(RegionProxy
, RegionProxyAdmin
)