'dossier': dossier,
'validationForm': validationForm,
'comparaisons_internes': comparaisons_internes,
- 'comparaisons': comparaisons
- }
- return render(request, 'dae/embauche_consulter.html', vars)
+ 'comparaisons': comparaisons,
+ 'importer': in_drh_or_admin(request.user)
+ })
-
-@drh_or_admin_required
+@user_passes_test(lambda u: u.is_superuser)
+@dae_groupe_requis
+@dossier_dans_ma_region_ou_service
def embauche_importer(request, dossier_id=None):
dossier_dae = get_object_or_404(dae.Dossier, id=dossier_id)
if request.method == 'POST':
from django.conf import settings
from django.contrib import messages
from django.contrib.auth import REDIRECT_FIELD_NAME
-from django.contrib.auth.decorators import user_passes_test
-from django.core.urlresolvers import reverse
+from django.db.models import Q
from django.utils.http import urlquote
--from project.groups import grp_drh, grp_drh2, grp_correspondants_rh
++from project import groups
from project.groups import get_employe_from_user
"""
Teste si un user Django fait parti du groupe DRH, DRH2 ou s'il est admin
"""
-- groups = user.groups.all()
++ user_groups = user.groups.all()
if user.is_superuser or \
-- grp_drh in groups or \
-- grp_drh2 in groups:
++ groups.grp_drh in user_groups or \
++ groups.grp_drh2 in user_groups:
return True
else:
return False
if request.user.is_superuser:
return func(request, id)
user_groups = request.user.groups.all()
-- if grp_drh in user_groups:
++ if groups.grp_drh in user_groups or \
++ groups.grp_drh2 in user_groups:
return func(request, id)
-- if grp_correspondants_rh in user_groups:
++ if groups.grp_correspondants_rh in user_groups or \
++ groups.grp_administrateurs in user_groups or \
++ groups.grp_directeurs_bureau in user_groups:
employe = get_employe_from_user(request.user)
q = Q(**{
model.prefix_implantation: employe.implantation.region
from admin_tools.menu import items, Menu
from project.decorators import in_drh_or_admin
+ from project import groups
+
+
class CustomMenu(Menu):
"""
Custom Menu for project admin site.
Use this method if you need to access the request context.
"""
request = context['request']
+
+ if request.user.is_superuser:
+ self.children += [
+ items.MenuItem('DAE', reverse('admin:app_list',
+ kwargs={'app_label': 'dae'})),
+ ]
+
- if in_drh_or_admin(request.user):
+ user_groups = request.user.groups.all()
+ if in_drh_or_admin(request.user) or\
+ groups.grp_correspondants_rh in user_groups or\
+ groups.grp_administrateurs in user_groups or\
+ groups.grp_directeurs_bureau in user_groups:
self.children += [
items.MenuItem('Rapports',
- children=[
- #items.MenuItem('Rapport des postes', reverse('rhr_postes')),
- items.MenuItem('Rapport des contrats', reverse('rhr_contrats')),
- items.MenuItem(u'Rapport des employés sans contrat', reverse('rhr_employe_sans_contrat')),
- #items.MenuItem('Rapport de rémunération', reverse('rhr_remuneration')),
+ children=[
+ #items.MenuItem('Rapport des postes',
+ # reverse('rhr_postes')),
+ items.MenuItem('Rapport des contrats',
+ reverse('rhr_contrats')),
+ items.MenuItem(u'Rapport des employés sans contrat',
+ reverse('rhr_employe_sans_contrat')),
+ #items.MenuItem('Rapport de rémunération',
+ # reverse('rhr_remuneration')),
+
+ # A corriger
+ #items.MenuItem('Rapport des postes par service',
+ # reverse('rhr_postes_service')),
+ #items.MenuItem('Rapport des postes par implantation',
+ # reverse('rhr_postes_implantation')),
+
+ #items.MenuItem('Modelisation des postes',
+ # reverse('rhr_postes_modelisation')),
+ #items.MenuItem('Rapport hiérarchique des postes',
+ # reverse('rhr_postes_hierarchie')),
+ items.MenuItem('Rapport de masse salariale',
+ reverse('rhr_masse_salariale')),
+ items.MenuItem('Rapport des modifications',
+ reverse('rhr_historique_des_modifications')),
+ ]),
- # A corriger
- #items.MenuItem('Rapport des postes par service', reverse('rhr_postes_service')),
- #items.MenuItem('Rapport des postes par implantation', reverse('rhr_postes_implantation')),
-
- #items.MenuItem('Modelisation des postes', reverse('rhr_postes_modelisation')),
- #items.MenuItem('Rapport hiérarchique des postes', reverse('rhr_postes_hierarchie')),
- items.MenuItem('Rapport de masse salariale', reverse('rhr_masse_salariale')),
- ]
- ),
items.MenuItem('Organigrammes',
children=[
- items.MenuItem('Organigramme par employé', reverse('admin:rh_employeproxy_changelist')),
- items.MenuItem('Organigramme par service', reverse('admin:rh_serviceproxy_changelist')),
- items.MenuItem('Organigramme par implantation', reverse('admin:rh_implantationproxy_changelist')),
- items.MenuItem('Organigramme par bureau', reverse('admin:rh_regionproxy_changelist')),
- ]
- ),
+ items.MenuItem('Organigramme par employé',
+ reverse('admin:rh_employeproxy_changelist')),
+ items.MenuItem('Organigramme par service',
+ reverse('admin:rh_serviceproxy_changelist')),
+ items.MenuItem('Organigramme par implantation',
+ reverse('admin:rh_implantationproxy_changelist')),
+ items.MenuItem('Organigramme par bureau',
+ reverse('admin:rh_regionproxy_changelist')),
+ ]),
items.MenuItem('Requêtes',
children=[
- items.MenuItem('Requêtes sauvegardées', reverse('admin:django_qbe_savedquery_changelist')),
- items.MenuItem('Constructeur de requêtes', reverse('qbe_form')),
- ]
- ),
+ items.MenuItem('Requêtes sauvegardées',
+ reverse('admin:django_qbe_savedquery_changelist')),
+ items.MenuItem('Constructeur de requêtes',
+ reverse('qbe_form')),
+ ]),
]
super(CustomMenu, self).init_with_context(context)
-
from django.conf import settings
from django.db.models import Q, Count
from django.template.defaultfilters import date
-
-from ajax_select import make_ajax_form
-
-from auf.django.metadata.admin import \
- AUFMetadataAdminMixin, AUFMetadataInlineAdminMixin, \
- AUF_METADATA_READONLY_FIELDS
-import auf.django.references.models as ref
+from django.utils.formats import date_format
+ from project import groups
from project.decorators import in_drh_or_admin
+from project.groups import grp_correspondants_rh
+from project.groups import get_employe_from_user
+from project.rh import models as rh
+ from project.permissions import get_region_user, \
+ user_gere_obj_de_sa_region, \
+ user_can_add_obj, \
+ user_can_change_obj, \
+ user_can_delete_obj
+
+ import project.rh.models as rh
+ from project.rh.forms import \
+ ContratForm, AyantDroitForm, EmployeAdminForm, AjaxSelect, DossierForm
from project.rh.change_list import ChangeList
+from project.rh.forms import ContratForm, AyantDroitForm, EmployeAdminForm, \
+ AjaxSelect, DossierForm, ResponsableInlineForm
class BaseAdmin(admin.ModelAdmin):
'jquery-autocomplete/jquery.autocomplete.min.js',
)
-
+# Admin pour reversion
-class ArchiveMixin(object):
+class ArchivableAdmin(admin.ModelAdmin):
"""
- Archive Mixin pour gérer le queryset et le display
- NON COMPRIS : list_filter, et list_display, field à setter dans la classe.
+ Admin pour les modèles archivables
"""
+ list_filter = ('archive', )
def queryset(self, request):
- return self.model._base_manager
+ return self.model.avec_archives.all()
def _archive(self, obj):
if obj.archive:
return qs.none()
def has_add_permission(self, request):
- if not in_drh_or_admin(request.user):
- return False
- else:
- return True
+ return user_can_add_obj(request.user)
def has_change_permission(self, request, obj=None):
- user_groups = request.user.groups.all()
+ return user_can_change_obj(request.user, obj) if obj else True
- # Lock pour autoriser uniquement les DRH à utiliser RH
- if not in_drh_or_admin(request.user):
- return False
-
- if len(user_groups) == 0 and not request.user.is_superuser:
- return False
-
- if obj is None:
- return True
- ids = [o.id for o in self.queryset(request)]
- return obj.id in ids
+ def has_delete_permission(self, request, obj=None):
+ return user_can_delete_obj(request.user, obj) if obj else True
+class DerniereModificationAdmin(admin.ModelAdmin):
+
+ def queryset(self, request):
+ qs = super(DerniereModificationAdmin, self).queryset(request)
+ ct = ContentType.objects.get_for_model(self.model)
+ db_table = self.model._meta.db_table
+ pk = self.model._meta.pk.column
+ return qs.extra(select={
+ 'date_modification':
+ "SELECT action_time FROM django_admin_log "
+ "WHERE content_type_id = %d AND object_id = %s.%s "
+ "ORDER BY action_time DESC "
+ "LIMIT 1" % (ct.id, db_table, pk),
+ 'user_modification':
+ "SELECT u.username "
+ "FROM auth_user u "
+ "INNER JOIN django_admin_log l ON l.user_id = u.id "
+ "WHERE l.content_type_id = %d AND object_id = %s.%s "
+ "ORDER BY action_time DESC "
+ "LIMIT 1" % (ct.id, db_table, pk),
+ })
+
+ def derniere_modification(self, obj):
+ text = ''
+ if obj.date_modification:
+ text += obj.date_modification.strftime('%d-%m-%Y %H:%M')
+ if obj.user_modification:
+ text += ' par ' + obj.user_modification
+ return text
+ derniere_modification.short_description = u'dernière modification'
+ derniere_modification.admin_order_field = 'date_modification'
+
+
# Inlines
+class CommentaireInlineForm(forms.ModelForm):
+
+ def save(self, commit=True):
+
+ # Hack: reversion.VersionAdmin ne sauvegarde pas les champs qui ne
+ # sont pas explicitement dans le formulaire. Il plante cependant
+ # leur valeur dans `self.initial`. Ceci est un peu fragile. Si
+ # c'est possible, il serait plus approprié que Reversion se rende
+ # compte qu'il manque des champs.
+ instance = super(CommentaireInlineForm, self).save(commit=False)
+ if instance.owner_id is None and 'owner' in self.initial:
+ instance.owner_id = self.initial['owner']
+ if instance.date_creation is None and 'date_creation' in self.initial:
+ instance.date_creation = self.initial['date_creation']
+ if commit:
+ instance.save()
+ self.save_m2m()
+ return instance
+
+
class ReadOnlyInlineMixin(object):
def get_readonly_fields(self, request, obj=None):
class ResponsableImplantationAdmin(BaseAdmin):
actions = None
+ fields = ('nom', )
+ inlines = (ResponsableInline, )
list_filter = ('region', 'statut', )
list_display = ('_region', '_nom', 'statut', '_responsable', )
+ list_display_links = ('_nom',)
+ list_per_page = 500
readonly_fields = ('nom', )
- fields = ('nom', )
+ search_fields = (
+ 'nom',
+ 'responsable__employe__id',
+ 'responsable__employe__nom',
+ 'responsable__employe__prenom',
+ )
+ ordering = ('nom',)
+ inlines = (ResponsableInline, )
def _region(self, obj):
return obj.region.code
dossiers = rh.Dossier.objects.select_related('employe').filter(
(Q(date_fin__gt=date.today()) | Q(date_fin=None)) &
(Q(date_debut__lt=date.today()) | Q(date_debut=None)) &
- Q(poste=poste)
- ).exclude(supprime=True).all()
+ Q(poste__id=n)
+ ).all()
+ # affichage
if dossiers:
employes = "\\n".join(
["[%s] %s %s" %
# -*- encoding: utf-8 -*-
--import datetime
+from datetime import date
- from auf.django.metadata.managers import NoDeleteManager, NoDeleteQuerySet
from django.db import models
from django.db.models import Q
-
-from auf.django.metadata.managers import NoDeleteManager
++from django.db.models.query import QuerySet
from project.groups import get_employe_from_user
-from project.groups import grp_administrateurs, \
- grp_directeurs_bureau, \
- grp_drh, \
- grp_drh2, \
- grp_accior, \
- grp_abf, \
- grp_haute_direction, \
- grp_service_utilisateurs, \
- grp_correspondants_rh
+from project.groups import \
+ grp_drh, grp_drh2, grp_accior, grp_abf, grp_haute_direction, \
+ grp_service_utilisateurs
class SecurityManager(models.Manager):
return liste
-class PosteManager(SecurityManager, NoDeleteManager):
- """
- Chargement de tous les objets FK existants sur chaque QuerySet.
- """
++class ActifsQuerySet(QuerySet):
++
++ def _actifs(self, debut_field, fin_field, date_min=None, date_max=None,
++ annee=None):
++ qs = self
++ if annee:
++ janvier = date(annee, 1, 1)
++ decembre = date(annee, 12, 31)
++ date_min = max(janvier, date_min) if date_min else janvier
++ date_max = min(decembre, date_max) if date_max else decembre
++ if not date_min and not date_max:
++ date_min = date_max = date.today()
++ if date_min:
++ qs = qs.filter(
++ Q(**{fin_field + '__gte': date_min}) |
++ Q(**{fin_field: None})
++ )
++ if date_max:
++ qs = qs.filter(
++ Q(**{debut_field + '__lte': date_max}) |
++ Q(**{debut_field: None})
++ )
++ return qs
++
++ def actifs(self, *args, **kwargs):
++ return self._actifs('date_debut', 'date_fin', *args, **kwargs)
++
++
++class PosteQuerySet(ActifsQuerySet):
++ pass
++
++
+class PosteManager(SecurityManager):
prefixe_service = "service"
prefixe_implantation = "implantation__region"
-- def actifs(self):
- return super(PosteManager, self).get_query_set().filter(
- Q(date_fin__gt=datetime.datetime.now()) |
- Q(date_fin__isnull=True)
- )
- q_actif = Q(date_fin__gt=datetime.datetime.now()) | Q(date_fin__isnull=True)
- return super(PosteManager, self).get_query_set().filter(q_actif)
++ def get_query_set(self):
++ return PosteQuerySet(self.model).select_related('type_poste')
++
++ def actifs(self, *args, **kwargs):
++ return self.get_query_set().actifs(*args, **kwargs)
def ma_region_ou_service(self, user):
return super(PosteManager, self).ma_region_ou_service(user)
-- def get_query_set(self):
-- fkeys = (
-- #'id_rh',
-- #'responsable',
-- #'implantation',
-- #'implantation.bureau_rattachement',
-- 'type_poste',
-- #'service',
-- #'classement_min',
-- #'classement_max',
-- #'valeur_point_min',
-- #'valeur_point_max',
-- )
-- return super(PosteManager, self).get_query_set() \
-- .select_related(*fkeys).all()
-
-
-class DossierManager(SecurityManager, NoDeleteManager):
++
++class DossierQuerySet(ActifsQuerySet):
++ pass
+
+
+class DossierManager(SecurityManager):
prefixe_service = "poste__service"
prefixe_implantation = "poste__implantation__region"
def get_query_set(self):
-- fkeys = (
-- 'poste',
-- 'employe',
-- )
-- return super(DossierManager, self).get_query_set() \
-- .select_related(*fkeys).all()
++ return DossierQuerySet(self.model) \
++ .select_related('poste', 'employe')
-- def ma_region_ou_service(self, user):
-- return super(DossierManager, self).ma_region_ou_service(user)
++ def actifs(self, *args, **kwargs):
++ return self.get_query_set().actifs(*args, **kwargs)
+
+
- class EmployeQuerySet(NoDeleteQuerySet):
++class RemunerationQuerySet(ActifsQuerySet):
++
++ def actifs(self, *args, **kwargs):
++ return self \
++ ._actifs('date_debut', 'date_fin', *args, **kwargs) \
++ ._actifs(
++ 'dossier__date_debut', 'dossier__date_fin', *args, **kwargs
++ )
++
++
++class RemunerationManager(models.Manager):
++
++ def get_query_set(self):
++ return RemunerationQuerySet(self.model)
++
++ def actifs(self, *args, **kwargs):
++ return self.get_query_set().actifs(*args, **kwargs)
++
++
++class EmployeQuerySet(ActifsQuerySet):
+
+ def actifs(self, date_min=None, date_max=None, annee=None):
- qs = self
- if annee:
- janvier = date(annee, 1, 1)
- decembre = date(annee, 12, 31)
- date_min = max(janvier, date_min) if date_min else janvier
- date_max = min(decembre, date_max) if date_max else decembre
- if not date_min and not date_max:
- date_min = date_max = date.today()
- if date_min:
- qs = qs.filter(
- Q(rh_dossiers__date_fin__gte=date_min) |
- Q(rh_dossiers__date_fin=None)
- )
- if date_max:
- qs = qs.filter(
- Q(rh_dossiers__date_debut__lte=date_max) |
- Q(rh_dossiers__date_debut=None)
- )
- return qs.distinct()
++ return self \
++ ._actifs('rh_dossiers__date_debut', 'rh_dossiers__date_fin') \
++ .distinct()
++
+
++class EmployeManager(models.Manager):
+
- class EmployeManager(NoDeleteManager):
+ def get_query_set(self):
+ return EmployeQuerySet(self.model)
+
+ def actifs(self, *args, **kwargs):
+ return self.get_query_set().actifs(*args, **kwargs)
class PosteComparaisonManager(SecurityManager):
prefixe_implantation = "implantation__region"
-class DeviseManager(NoDeleteManager):
++class DeviseManager(models.Manager):
+ pass
+
-class ServiceManager(NoDeleteManager):
++
++class ServiceManager(models.Manager):
+ pass
+
-class TypeRemunerationManager(NoDeleteManager):
++
+class TypeRemunerationManager(models.Manager):
pass
from project.rh.change_list import \
RechercheTemporelle, KEY_STATUT, STATUT_ACTIF, STATUT_INACTIF, \
STATUT_FUTUR
-from project.rh.managers import \
- PosteManager, DossierManager, DossierComparaisonManager, \
- PosteComparaisonManager, DeviseManager, ServiceManager, \
- TypeRemunerationManager
+from project.rh.managers import PosteManager, DossierManager, EmployeManager, \
+ DossierComparaisonManager, \
+ PosteComparaisonManager, \
- TypeRemunerationManager
++ TypeRemunerationManager, \
++ RemunerationManager
from project.rh.validators import validate_date_passee
+# import pour relocaliser le modèle selon la convention
+from project.rh.historique import ModificationTraite
# Constantes
HELP_TEXT_DATE = "format: jj-mm-aaaa"
pour un Dossier. Si un Evenement existe, utiliser la structure de
rémunération EvenementRemuneration de cet événement.
"""
++ objects = RemunerationManager()
def montant_mois(self):
return round(self.montant / 12, 2)
class ResponsableImplantationProxy(ref.Implantation):
+ def save(self):
+ pass
+
class Meta:
+ managed = False
proxy = True
verbose_name = u"Responsable d'implantation"
verbose_name_plural = u"Responsables d'implantation"
--- /dev/null
+ # -*- coding: utf-8 -*-
+
+ import datetime
+ from django.contrib.auth.models import User
-from project.rh import groups
++from project import groups
+ from auf.django.references import models as ref
+ from django.test import TestCase
+ from project.rh import models as rh
+
+
+ class RhTest(TestCase):
+
+ def setUp(self):
+ """
+ POSTES
+ ======
+ self.poste_cnf_ngaoundere
+ self.poste_cnf_bangui
+ self.poste_bap_bureau
+ self.poste_bap_ifi
+
+ EMPLOYES
+ ========
+ 0@test.auf: self.employe_cnf_ngaoundere
+ 1@test.auf: self.employe_cnf_bangui
+ 2@test.auf: self.employe_bap_bureau
+ 3@test.auf: self.employe_bap_ifi
+
+ USERS DJANGO
+ ============
+ cf. EMPLOYES
+
+ DOSSIERS
+ ========
+ self.dossier_cnf_ngaoundere
+ self.dossier_cnf_bangui
+ self.dossier_bap_bureau
+ self.dossier_bap_ifi
+
+
+ """
+ self.password = "0000"
+ self.today = datetime.datetime.now()
+ #########################
+ # Régions / Implantations
+ #########################
+ self.REGION_ACGL = ref.Region.objects.get(id=1)
+ self.IMPLANTATION_ACGL_CNF_NGAOUNDERE = ref.Implantation.objects.get(id=90)
+ self.IMPLANTATION_ACGL_CNF_BANGUI = ref.Implantation.objects.get(id=85)
+
+ self.REGION_BAP = ref.Region.objects.get(id=4)
+ self.IMPLANTATION_BAP_BUREAU = ref.Implantation.objects.get(id=51)
+ self.IMPLANTATION_BAP_IFI = ref.Implantation.objects.get(id=55)
+
+
+ ##########
+ # Employés
+ ##########
+ self.employe_cnf_ngaoundere = rh.Employe(
+ id=1,
+ nom="Employé",
+ prenom="ngaoundere",
+ )
+ self.employe_cnf_ngaoundere.save()
+ self.employe_cnf_bangui = rh.Employe(
+ id=2,
+ nom="Employé",
+ prenom="bangui",
+ )
+ self.employe_cnf_bangui.save()
+ self.employe_bap_bureau = rh.Employe(
+ id=3,
+ nom="Employé",
+ prenom="BAP bureau",
+ )
+ self.employe_bap_bureau.save()
+ self.employe_bap_ifi = rh.Employe(
+ id=4,
+ nom="Employé",
+ prenom="BAP IFI",
+ )
+ self.employe_bap_ifi.save()
+
+ ######
+ # ACGL
+ ######
+ self.poste_cnf_ngaoundere = rh.Poste(nom="poste à NGAOUNDERE",
+ implantation=self.IMPLANTATION_ACGL_CNF_NGAOUNDERE)
+
+ self.poste_cnf_bangui = rh.Poste(nom="poste à BANGUI",
+ implantation=self.IMPLANTATION_ACGL_CNF_BANGUI)
+
+ self.poste_cnf_ngaoundere.save()
+ self.poste_cnf_bangui.save()
+
+ self.dossier_cnf_ngaoundere = rh.Dossier(poste=self.poste_cnf_ngaoundere,
+ employe=self.employe_cnf_ngaoundere, date_debut=self.today)
+ self.dossier_cnf_bangui = rh.Dossier(poste=self.poste_cnf_bangui,
+ employe=self.employe_cnf_bangui, date_debut=self.today)
+
+ self.dossier_cnf_ngaoundere.save()
+ self.dossier_cnf_bangui.save()
+
+ #####
+ # BAP
+ #####
+ self.poste_bap_bureau = rh.Poste(nom="poste au Bureau BAP",
+ implantation=self.IMPLANTATION_BAP_BUREAU)
+ self.poste_bap_ifi = rh.Poste(nom="poste à l'IFI",
+ implantation=self.IMPLANTATION_BAP_IFI)
+
+ self.poste_bap_bureau.save()
+ self.poste_bap_ifi.save()
+
+ self.dossier_bap_bureau = rh.Dossier(poste=self.poste_bap_bureau,
+ employe=self.employe_bap_bureau, date_debut=self.today)
+ self.dossier_bap_ifi = rh.Dossier(poste=self.poste_bap_ifi,
+ employe=self.employe_bap_ifi, date_debut=self.today)
+
+ self.dossier_bap_bureau.save()
+ self.dossier_bap_ifi.save()
+
+ ##############
+ # Users Django
+ ##############
+ self._clean_refs()
+ for idx, e in enumerate(rh.Employe.objects.all().order_by('id')):
+ email = u"%s@test.auf" % idx
+ u = User(first_name=e.prenom,
+ is_staff=True,
+ last_name=e.nom,
+ username=email,
+ email=email)
+ u.set_password(self.password)
+ u.save()
+
+ # on le porte dans le référentiel employé
+ ref_e = ref.Employe(id=u.id,
+ nom=e.nom, prenom=e.prenom,
+ implantation=e.poste_principal().implantation,
+ implantation_physique=e.poste_principal().implantation,
+ service=ref.Service.objects.get(id=1))
+ ref_e.save()
+
+ # on le porte dans le référentiel auth
+ ref.Authentification(id=ref_e, courriel=u.email).save()
+
+ def _clean_refs(self):
+ courriels = [u"%s@test.auf" % idx for idx, e in
+ enumerate(rh.Employe.objects.all())]
+ ref.Employe.objects.filter(courriel__in=courriels).delete()
+ ref.Authentification.objects.filter(courriel__in=courriels).delete()
+
+ def tearDown(self):
+ self._clean_refs()
+
+ def _test_acces_ok(self, url):
+ response = self.client.get(url, follow=True)
+ self.assertEqual(response.status_code, 200)
+ self.assertEqual('next' in response.context, False)
+
+ def _test_acces_ko(self, url):
+ response = self.client.get(url, follow=True)
+ is_ko = response.status_code == 403 or 'next' in response.context
+ self.assertEqual(is_ko, True)
+
+ def _test_anonyme(self):
+ pass
+
+ def _test_correspondant_rh(self, email="0@test.auf"):
+ u = User.objects.get(email=email)
+ groups.grp_correspondants_rh.user_set.add(u)
+ groups.grp_correspondants_rh.save()
+
+ credentials = {'username': email, 'password': self.password}
+ self.assertTrue(self.client.login(**credentials), "login failed")
+
+ def _test_administrateur_regional(self, email="0@test.auf"):
+ u = User.objects.get(email=email)
+ groups.grp_administrateurs.user_set.add(u)
+ groups.grp_administrateurs.save()
+
+ credentials = {'username': email, 'password': self.password}
+ self.assertTrue(self.client.login(**credentials), "login failed")
+
+ def _test_directeur_bureau(self, email="0@test.auf"):
+ u = User.objects.get(email=email)
+ groups.grp_directeurs_bureau.user_set.add(u)
+ groups.grp_directeurs_bureau.save()
+
+ credentials = {'username': email, 'password': self.password}
+ self.assertTrue(self.client.login(**credentials), "login failed")
+
+ def _test_drh(self):
+ email = "0@test.auf"
+
+ u = User.objects.get(email=email)
+ groups.grp_drh.user_set.add(u)
+ groups.grp_drh.save()
+
+ credentials = {'username': email, 'password': self.password}
+ self.assertTrue(self.client.login(**credentials), "login failed")
+
+ def _test_drh2(self):
+ email = "0@test.auf"
+
+ u = User.objects.get(email=email)
+ groups.grp_drh2.user_set.add(u)
+ groups.grp_drh2.save()
+
+ credentials = {'username': email, 'password': self.password}
+ self.assertTrue(self.client.login(**credentials), "login failed")
+
+ def _test_grp_accior(self):
+ email = "0@test.auf"
+
+ u = User.objects.get(email=email)
+ groups.grp_accior.user_set.add(u)
+ groups.grp_accior.save()
+
+ credentials = {'username': email, 'password': self.password}
+ self.assertTrue(self.client.login(**credentials), "login failed")
+
+ def _test_grp_abf(self):
+ email = "0@test.auf"
+
+ u = User.objects.get(email=email)
+ groups.grp_abf.user_set.add(u)
+ groups.grp_abf.save()
+
+ credentials = {'username': email, 'password': self.password}
+ self.assertTrue(self.client.login(**credentials), "login failed")
+
+ def _test_grp_haute_direction(self):
+ email = "0@test.auf"
+
+ u = User.objects.get(email=email)
+ groups.grp_haute_direction.user_set.add(u)
+ groups.grp_haute_direction.save()
+
+ credentials = {'username': email, 'password': self.password}
+ self.assertTrue(self.client.login(**credentials), "login failed")
+
+ def _test_grp_service_utilisateurs(self):
+ email = "0@test.auf"
+
+ u = User.objects.get(email=email)
+ groups.grp_service_utilisateurs.user_set.add(u)
+ groups.grp_service_utilisateurs.save()
+
+ credentials = {'username': email, 'password': self.password}
+ self.assertTrue(self.client.login(**credentials), "login failed")
from django.core.urlresolvers import reverse
from django.db.models import Q
from django.http import HttpResponse
-from django.shortcuts import render, get_object_or_404
-
-from auf.django.references import models as ref
+from django.shortcuts import render, get_object_or_404, redirect
-from project import groups
-from project.decorators import drh_or_admin_required, in_one_of_group, \
- in_drh_or_admin
-from project.decorators import redirect_interdiction
+from project.decorators import drh_or_admin_required
from project.decorators import region_protected
- from project.groups import \
- get_employe_from_user, grp_drh, grp_correspondants_rh
+ from project.groups import get_employe_from_user
++from project import groups
++from project.decorators import in_one_of_group, in_drh_or_admin
+
-from project.rh import models as rh
+from project.rh import ods
from project.rh import graph as rh_graph
+from project.rh import models as rh
from project.rh.change_list import RechercheTemporelle
-from project.rh.lib import calc_remun, get_lookup_params
-from project.rh.masse_salariale import MasseSalariale
+from project.rh.forms import MasseSalarialeForm
+from project.rh.lib import get_lookup_params
from project.rh.templatetags.rapports import SortHeaders
+from project.rh.historique import get_active_revisions, TodoForm
+
+TWOPLACES = Decimal('0.01')
@login_required
+ @drh_or_admin_required
def profil(request):
"""Profil personnel de l'employé - éditable"""
- employe = get_employe_from_user(user)
+ employe = get_employe_from_user(request.user)
c = {
'user': request.user,
'employe': employe,
@login_required
- @drh_or_admin_required
+ @in_one_of_group((groups.grp_correspondants_rh,
+ groups.grp_administrateurs,
+ groups.grp_directeurs_bureau,
+ groups.grp_drh,
+ groups.grp_drh2))
def rapports_contrat(request):
+ # statut default = actif?
if 'HTTP_REFERER' in request.META.keys():
referer = request.META['HTTP_REFERER']
referer = "/".join(referer.split('/')[3:])
lookup_params = cl.purge_params(lookup_params)
q_temporel = cl.get_q_temporel(contrats)
q = Q(**lookup_params) & q_temporel
+ contrats = contrats.filter(q)
+ user_groups = request.user.groups.all()
+ if groups.grp_correspondants_rh in user_groups or\
+ groups.grp_administrateurs in user_groups or\
+ groups.grp_directeurs_bureau in user_groups:
+ employe = get_employe_from_user(request.user)
+ q = q & Q(dossier__poste__implantation__region=employe.implantation.region)
+
- contrats = contrats.filter(q).exclude(dossier__employe__supprime=1)
++ contrats = contrats.filter(q)
+ # tri
if 'o' in request.GET:
contrats = contrats.order_by(
('-' if request.GET.get('ot') == "desc" else '') + request.GET['o']
@login_required
- @drh_or_admin_required
+ @in_one_of_group((groups.grp_correspondants_rh,
+ groups.grp_administrateurs,
+ groups.grp_directeurs_bureau,
+ groups.grp_drh,
+ groups.grp_drh2))
-def rapports_masse_salariale(request):
-
- class RechercheTemporelle(forms.Form):
- remunerations = rh.Remuneration.objects.exclude(date_debut=None)
- if len(remunerations) > 0:
- annee_debut = remunerations.order_by('date_debut')[0].date_debut.year
- else:
- annee_debut = 1982
- CHOICE_ANNEES = range(annee_debut, date.today().year + 1)
-
- annee = forms.CharField(
- initial=date.today().year,
- widget=forms.Select(
- choices=((a, a) for a in reversed(CHOICE_ANNEES))
- )
- )
-
- user_groups = request.user.groups.all()
- if groups.grp_correspondants_rh in user_groups or\
- groups.grp_administrateurs in user_groups or\
- groups.grp_directeurs_bureau in user_groups:
- employe = get_employe_from_user(request.user)
- regions = ref.Region.objects.filter(id=employe.implantation.region.id)
- implantations = ref.Implantation.objects.filter(region=employe.implantation.region)
- else:
- regions = ref.Region.objects.all()
- implantations = ref.Implantation.objects.all()
-
- region = forms.CharField(
- widget=forms.Select(choices=[('', '')] +
- [(i.id, i) for i in regions]
- )
- )
-
- implantation = forms.CharField(
- widget=forms.Select(choices=[('', '')] +
- [(i.id, i) for i in implantations]
- )
- )
-
- #date_debut = forms.DateField(widget=adminwidgets.AdminDateWidget)
- #date_fin = forms.DateField(widget=adminwidgets.AdminDateWidget)
-
- form = RechercheTemporelle(request.GET)
- get_filtre = [
- (k, v) for k, v in request.GET.items()
- if k not in ('date_debut', 'date_fin', 'implantation')
- ]
- query_string = urllib.urlencode(get_filtre)
-
- date_debut = None
- date_fin = None
- if request.GET.get('annee', None):
- date_debut = "01-01-%s" % request.GET.get('annee', None)
- date_fin = "31-12-%s" % request.GET.get('annee', None)
-
- implantation = request.GET.get('implantation')
- region = request.GET.get('region')
-
- custom_filter = {}
- if implantation:
- custom_filter['dossier__poste__implantation'] = implantation
- if region:
- custom_filter['dossier__poste__implantation__region'] = region
-
- # on force la région dans tous les cas pour les membres de ce groupe
- user_groups = request.user.groups.all()
- if groups.grp_correspondants_rh in user_groups or\
- groups.grp_administrateurs in user_groups or\
- groups.grp_directeurs_bureau in user_groups:
- employe = get_employe_from_user(request.user)
- custom_filter['dossier__poste__implantation__region'] = employe.implantation.region.id
-
-
- c = {
- 'title': 'Rapport de masse salariale',
- 'form': form,
- 'headers': [],
- 'query_string': query_string,
- }
- if date_debut or date_fin:
- masse = MasseSalariale(date_debut, date_fin, custom_filter,
- request.GET.get('ne_pas_grouper', False))
- if masse.rapport:
- if request.GET.get('ods'):
- for h in (
- h for h in masse.headers if 'background-color' in h[2]
- ):
- del h[2]['background-color']
- masse.ods()
- output = StringIO.StringIO()
- masse.doc.save(output)
- output.seek(0)
-
- response = HttpResponse(
- FileWrapper(output),
- content_type=(
- 'application/vnd.oasis.opendocument.spreadsheet'
- )
- )
- response['Content-Disposition'] = \
- 'attachment; filename=Masse Salariale %s.ods' % \
- masse.annee
- return response
- else:
- c['rapport'] = masse.rapport
- c['header_keys'] = [h[0] for h in masse.headers]
- #on enleve le background pour le header
- for h in (
- h for h in masse.headers if 'background-color' in h[2]
- ):
- h[2]['background'] = 'none'
- h = SortHeaders(request, masse.headers, order_field_type="ot",
- not_sortable=c['header_keys'], order_field="o")
- c['headers'] = list(h.headers())
- for key, nom, opts in masse.headers:
- c['headers']
- c['total'] = masse.grand_totaux[0]
- c['total_euro'] = masse.grand_totaux[1]
- c['colspan'] = len(c['header_keys']) - 1
- get_filtre.append(('ods', True))
- query_string = urllib.urlencode(get_filtre)
- c['url_ods'] = "%s?%s" % (
- reverse('rhr_masse_salariale'), query_string)
-
- return render(request, 'rh/rapports/masse_salariale.html', c)
-
-
-@login_required
-@in_one_of_group((groups.grp_correspondants_rh,
- groups.grp_administrateurs,
- groups.grp_directeurs_bureau,
- groups.grp_drh,
- groups.grp_drh2))
def rapports_employes_sans_contrat(request):
+ """
+ Employé sans contrat = a un Dossier qui n'a pas de Contrat associé
+ Employé avec contrat échu = a un Dossier avec un Contrat se terminant hier
+ au plus tard... (aujourd'hui = ok, pas date de fin = illimité donc ok)
+ """
lookup_params = get_lookup_params(request)
+ # régionalisation
+ user_groups = request.user.groups.all()
+ q_region = Q()
+ if groups.grp_correspondants_rh in user_groups or\
+ groups.grp_administrateurs in user_groups or\
+ groups.grp_directeurs_bureau in user_groups:
+ employe = get_employe_from_user(request.user)
+ q_region = Q(poste__implantation__region=employe.implantation.region)
+
# contrats échus
contrats_echus = rh.Contrat.objects.filter(
date_fin__lt=date.today()
**lookup_params
)
- # dossiers en cours sans contrat ou contrats échus
- dossiers = rh.Dossier.objects.filter(
- Q(date_debut=None) | Q(date_debut__lte=date.today()),
- ).filter(
- Q(date_fin=None) | Q(date_fin__gte=date.today()),
+ # dossiers en cours sans contrat
- dossiers_sans_contrat = rh.Dossier.objects.filter(q_region & (
++ dossiers = rh.Dossier.objects.filter(q_region & (
+ Q(date_fin=None) | Q(date_fin__gt=date.today())),
).exclude(
date_debut__gt=date.today()
).filter(
@login_required
- @drh_or_admin_required
++@in_one_of_group((groups.grp_correspondants_rh,
++ groups.grp_administrateurs,
++ groups.grp_directeurs_bureau,
++ groups.grp_drh,
++ groups.grp_drh2))
+def rapports_masse_salariale(request):
+ form = MasseSalarialeForm(request.user, request.GET)
+ if 'annee' in request.GET and form.is_valid():
+ region = form.cleaned_data['region']
+ implantation = form.cleaned_data['implantation']
+ annee = form.cleaned_data['annee']
+ debut_annee = date(annee, 1, 1)
+ fin_annee = date(annee, 12, 31)
+ jours_annee = (fin_annee - debut_annee).days + 1
+ today = date.today()
+
+ # Récupérer les dossiers actifs
+ dossiers = rh.Dossier.objects \
+ .actifs(annee=annee) \
+ .select_related(
+ 'poste', 'poste__implantation',
+ 'poste__implantation__region',
+ 'poste__implantation__adresse_physique_pays',
+ 'employe', 'poste__type_poste', 'classement',
+ 'statut', 'organisme_bstg'
+ ) \
+ .extra(
+ select={
+ 'valeur_point': (
+ 'SELECT valeur FROM rh_valeurpoint '
+ 'WHERE annee = %d '
+ 'AND implantation = ref_implantation.id' % annee
+ ),
+ 'valeur_point_devise': (
+ 'SELECT d.code '
+ 'FROM rh_valeurpoint vp '
+ 'INNER JOIN rh_devise d ON d.id = vp.devise '
+ 'WHERE annee = %d '
+ 'AND implantation = ref_implantation.id' % annee
+ )
+ }
+ )
+ if region:
+ dossiers = dossiers.filter(poste__implantation__region=region)
+ if implantation:
+ dossiers = dossiers.filter(poste__implantation=implantation)
+
+ # Récupérer les rémunérations actives
+ remuns = rh.Remuneration.objects \
+ .actifs(annee=annee) \
+ .select_related('devise', 'type') \
+ .extra(
+ tables=['rh_tauxchange'],
+ where=[
+ 'rh_tauxchange.annee = %s',
+ 'rh_tauxchange.devise = rh_devise.id'
+ ],
+ params=[annee],
+ select={
+ 'taux_change': 'rh_tauxchange.taux'
+ }
+ )
+ if region:
+ remuns = remuns.filter(dossier__poste__implantation__region=region)
+ if implantation:
+ remuns = remuns.filter(dossier__poste__implantation=implantation)
+ remuns_par_dossier = defaultdict(list)
+ types_remun = set()
+ for remun in remuns:
+ types_remun.add(remun.type_id)
+ remuns_par_dossier[remun.dossier_id].append(remun)
+
+ # Récupérer les types de rémunération par nature
+ types_remun_par_nature = defaultdict(list)
+ for type in rh.TypeRemuneration.objects.all():
+ if type.id in types_remun:
+ types_remun_par_nature[type.nature_remuneration].append(type)
+ titres_traitements = [
+ t.nom for t in types_remun_par_nature[u'Traitement']
+ ]
+ titres_indemnites = [
+ t.nom for t in types_remun_par_nature[u'Indemnité']
+ ]
+ titres_primes = [
+ t.nom for t in types_remun_par_nature[u'Accessoire']
+ ]
+ titres_charges = [
+ t.nom for t in types_remun_par_nature[u'Charges']
+ ]
+
+ # Boucler sur les dossiers et préprarer les lignes du rapport
+ lignes = []
+ masse_salariale_totale = 0
+ for dossier in dossiers:
+ debut_cette_annee = \
+ max(dossier.date_debut or debut_annee, debut_annee)
+ fin_cette_annee = \
+ min(dossier.date_fin or fin_annee, fin_annee)
+ jours = (fin_cette_annee - debut_cette_annee).days + 1
+
+ remuns = remuns_par_dossier[dossier.id]
+ devises = set(remun.devise.code for remun in remuns)
+ if len(devises) == 1:
+ devise = remuns[0].devise.code
+ montant_remun = lambda r: r.montant
+ taux_change = Decimal(str(remuns[0].taux_change))
+ else:
+ devise = 'EUR'
+ montant_remun = lambda r: (
+ r.montant * Decimal(str(r.taux_change))
+ )
+ taux_change = Decimal(1)
+
+ remuns_par_type = defaultdict(lambda: 0)
+ for remun in remuns:
+ if remun.type.nature_remuneration == u'Accessoire':
+ remuns_par_type[remun.type_id] += montant_remun(remun)
+ else:
+ remuns_par_type[remun.type_id] += (
+ montant_remun(remun) * ((
+ min(remun.date_fin or fin_annee, fin_annee) -
+ max(remun.date_debut or debut_annee, debut_annee)
+ ).days + 1) / jours_annee *
+ dossier.regime_travail / 100
+ ).quantize(TWOPLACES)
+ traitements = [
+ remuns_par_type[type.id]
+ for type in types_remun_par_nature[u'Traitement']
+ ]
+ indemnites = [
+ remuns_par_type[type.id]
+ for type in types_remun_par_nature[u'Indemnité']
+ ]
+ primes = [
+ remuns_par_type[type.id]
+ for type in types_remun_par_nature[u'Accessoire']
+ ]
+ charges = [
+ remuns_par_type[type.id]
+ for type in types_remun_par_nature[u'Charges']
+ ]
+ masse_salariale = sum(remuns_par_type.values())
+ masse_salariale_eur = (
+ masse_salariale * taux_change
+ ).quantize(TWOPLACES)
+ masse_salariale_totale += masse_salariale_eur
+
+ if dossier.valeur_point and dossier.classement \
+ and dossier.classement.coefficient and dossier.regime_travail:
+ salaire_theorique = (Decimal(str(
+ dossier.valeur_point * dossier.classement.coefficient
+ )) * dossier.regime_travail / 100).quantize(TWOPLACES)
+ else:
+ salaire_theorique = None
+
+ lignes.append({
+ 'dossier': dossier,
+ 'poste': dossier.poste,
+ 'date_debut': (
+ dossier.date_debut
+ if dossier.date_debut and dossier.date_debut.year == annee
+ else None
+ ),
+ 'date_fin': (
+ dossier.date_fin
+ if dossier.date_fin and dossier.date_fin.year == annee
+ else None
+ ),
+ 'jours': jours,
+ 'devise': devise,
+ 'valeur_point': dossier.valeur_point,
+ 'valeur_point_devise': dossier.valeur_point_devise,
+ 'regime_travail': dossier.regime_travail,
+ 'local_expatrie': {
+ 'local': 'L', 'expat': 'E'
+ }.get(dossier.statut_residence),
+ 'salaire_bstg': remuns_par_type[2],
+ 'salaire_bstg_eur': (
+ (remuns_par_type[2] * taux_change).quantize(TWOPLACES)
+ ),
+ 'salaire_theorique': salaire_theorique,
+ 'traitements': traitements,
+ 'total_traitements': sum(traitements),
+ 'indemnites': indemnites,
+ 'total_indemnites': sum(indemnites),
+ 'primes': primes,
+ 'total_primes': sum(primes),
+ 'charges': charges,
+ 'total_charges': sum(charges),
+ 'masse_salariale': masse_salariale,
+ 'masse_salariale_eur': masse_salariale_eur,
+ })
+
+ # Récupérer les postes actifs pour déterminer le nombre de jours
+ # vacants.
+ postes = rh.Poste.objects.actifs(annee=annee) \
+ .select_related(
+ 'devise_max', 'valeur_point_max', 'classement_max'
+ ) \
+ .extra(
+ tables=['rh_tauxchange'],
+ where=[
+ 'rh_tauxchange.annee = %s',
+ 'rh_tauxchange.devise = rh_devise.id'
+ ],
+ params=[annee],
+ select={
+ 'taux_change': 'rh_tauxchange.taux'
+ }
+ )
+ if region:
+ postes = postes.filter(implantation__region=region)
+ if implantation:
+ postes = postes.filter(implantation=implantation)
+ postes = list(postes)
+ postes_par_id = dict((poste.id, poste) for poste in postes)
+ jours_vacants_date = dict(
+ (poste.id, max(today, poste.date_debut or today))
+ for poste in postes
+ )
+ jours_vacants = defaultdict(lambda: 0)
+ for dossier in rh.Dossier.objects.actifs(annee=annee) \
+ .order_by('date_debut'):
+ if dossier.poste_id not in jours_vacants_date:
+ continue
+ derniere_date = jours_vacants_date[dossier.poste_id]
+ if dossier.date_debut is not None:
+ jours_vacants[dossier.poste_id] += max((
+ dossier.date_debut - derniere_date
+ ).days - 1, 0)
+ jours_vacants_date[dossier.poste_id] = max(
+ min(dossier.date_fin or fin_annee, fin_annee),
+ derniere_date
+ )
+ for poste_id, derniere_date in jours_vacants_date.iteritems():
+ jours_vacants[poste_id] += max((
+ min(postes_par_id[poste_id].date_fin or fin_annee, fin_annee) -
+ derniere_date
+ ).days, 0)
+
+ # Ajouter les lignes des postes vacants au rapport
+ for poste_id, jours in jours_vacants.iteritems():
+ if jours == 0:
+ continue
+ poste = postes_par_id[poste_id]
+ if poste.valeur_point_max and poste.classement_max \
+ and poste.classement_max.coefficient and poste.regime_travail:
+ salaire_theorique = (Decimal(str(
+ poste.valeur_point_max.valeur *
+ poste.classement_max.coefficient
+ )) * poste.regime_travail / 100).quantize(TWOPLACES)
+ else:
+ salaire_theorique = None
+
+ local_expatrie = '/'.join(
+ (['L'] if poste.local else []) +
+ (['E'] if poste.expatrie else [])
+ )
+
+ salaire = (
+ poste.salaire_max * jours / jours_annee *
+ poste.regime_travail / 100
+ ).quantize(TWOPLACES)
+ indemnites = (
+ poste.indemn_max * jours / jours_annee *
+ poste.regime_travail / 100
+ ).quantize(TWOPLACES)
+ charges = (
+ poste.autre_max * jours / jours_annee *
+ poste.regime_travail / 100
+ ).quantize(TWOPLACES)
+ masse_salariale = salaire + indemnites + charges
+ masse_salariale_eur = (
+ masse_salariale * Decimal(str(poste.taux_change))
+ ).quantize(TWOPLACES)
+ masse_salariale_totale += masse_salariale_eur
+
+ lignes.append({
+ 'poste': poste,
+ 'regime_travail': poste.regime_travail,
+ 'local_expatrie': local_expatrie,
+ 'jours': jours,
+ 'devise': poste.devise_max and poste.devise_max.code,
+ 'valeur_point': (
+ poste.valeur_point_max and poste.valeur_point_max.valeur
+ ),
+ 'valeur_point_devise': (
+ poste.valeur_point_max and \
+ poste.valeur_point_max.devise.code
+ ),
+ 'salaire_theorique': salaire_theorique,
+ 'traitements': [0] * len(titres_traitements),
+ 'total_traitements': salaire,
+ 'indemnites': [0] * len(titres_indemnites),
+ 'total_indemnites': indemnites,
+ 'primes': [0] * len(titres_primes),
+ 'total_primes': 0,
+ 'charges': [0] * len(titres_charges),
+ 'total_charges': charges,
+ 'masse_salariale': masse_salariale,
+ 'masse_salariale_eur': masse_salariale_eur
+ })
+ if 'ods' in request.GET:
+ doc = ods.masse_salariale(
+ lignes=lignes,
+ annee=annee,
+ titres_traitements=titres_traitements,
+ titres_indemnites=titres_indemnites,
+ titres_primes=titres_primes,
+ titres_charges=titres_charges,
+ masse_salariale_totale=masse_salariale_totale
+ )
+ response = HttpResponse(
+ mimetype='vnd.oasis.opendocument.spreadsheet'
+ )
+ response['Content-Disposition'] = 'filename=masse-salariale.ods'
+ doc.write(response)
+ return response
+ else:
+ return render(request, 'rh/rapports/masse_salariale.html', {
+ 'form': form,
+ 'titres_traitements': titres_traitements,
+ 'titres_indemnites': titres_indemnites,
+ 'titres_primes': titres_primes,
+ 'titres_charges': titres_charges,
+ 'masse_salariale_totale': masse_salariale_totale,
+ 'lignes': lignes,
+ 'annee': annee
+ })
+ return render(request, 'rh/rapports/masse_salariale.html', {
+ 'form': form
+ })
+
+
+@login_required
@drh_or_admin_required
def rapports_postes_modelisation(request):
c = {}
}
return render(request, 'admin/rh/poste/apercu.html', c)
-
-@region_protected(rh.Employe)
++@in_one_of_group((groups.grp_correspondants_rh,
++ groups.grp_administrateurs,
++ groups.grp_directeurs_bureau,
++ groups.grp_drh,
++ groups.grp_drh2))
def employe_apercu(request, employe_id):
employe = get_object_or_404(rh.Employe, pk=employe_id)
user_groups = request.user.groups.all()
@login_required
- @drh_or_admin_required
+ @in_one_of_group((groups.grp_correspondants_rh,
+ groups.grp_administrateurs,
+ groups.grp_directeurs_bureau,
+ groups.grp_drh,
+ groups.grp_drh2))
def organigrammes_employe(request, id, level="all"):
-
poste = get_object_or_404(rh.Poste, pk=id)
dossiers_by_poste = dict(
(d.poste_id, d)
Q(date_fin__gt=date.today()) | Q(date_fin=None),
Q(date_debut__lt=date.today()) | Q(date_debut=None),
responsable__in=postes_handle
-- ).exclude(supprime=True).exclude(responsable=None).all()
++ ).exclude(responsable=None).all()
for p in postes_handle:
if p.responsable_id != p.id:
@login_required
- @drh_or_admin_required
+ @in_one_of_group((groups.grp_correspondants_rh,
+ groups.grp_administrateurs,
+ groups.grp_directeurs_bureau,
+ groups.grp_drh,
+ groups.grp_drh2))
def organigrammes_service(request, id):
-
service = get_object_or_404(rh.Service, pk=id)
svg = rh_graph.organigramme_postes_cluster( \
+ request.user, \
cluster_filter={"service": service}, \
titre=u"Organigramme du service %s" % service.nom,
cluster_titre=service.nom)
@login_required
- @drh_or_admin_required
+ @in_one_of_group((groups.grp_correspondants_rh,
+ groups.grp_administrateurs,
+ groups.grp_directeurs_bureau,
+ groups.grp_drh,
+ groups.grp_drh2))
def organigrammes_implantation(request, id):
-
implantation = get_object_or_404(ref.Implantation, pk=id)
svg = rh_graph.organigramme_postes_cluster( \
+ request.user, \
cluster_filter={"implantation": implantation}, \
titre=u"Organigramme de l'implantation %s" % implantation.nom,
cluster_titre=implantation.nom)
@login_required
- @drh_or_admin_required
+ @in_one_of_group((groups.grp_correspondants_rh,
+ groups.grp_administrateurs,
+ groups.grp_directeurs_bureau,
+ groups.grp_drh,
+ groups.grp_drh2))
def organigrammes_region(request, id):
-
region = get_object_or_404(ref.Region, pk=id)
svg = rh_graph.organigramme_postes_cluster( \
+ request.user, \
cluster_filter={"implantation__region": region}, \
titre=u"Organigramme du bureau de %s" % region.nom,
cluster_titre=region.nom)
</li>
{% endif %}
<li class="{% menu_actif request '^embauches$' %}">
- <a href="{% url dae_embauches_liste %}">Embauches : voir et valider</a>
+ <a href="{% url dae_embauches_liste %}">Personnel : voir et valider</a>
</li>
<li class="{% menu_actif request '^embauches_finalisees$' %}">
- <a href="{% url embauches_finalisees %}">Embauches finalisées</a>
+ <a href="{% url embauches_finalisees %}">DAE finalisées</a>
</li>
- </ul>
+ </ul>
- </li>
- {% endif %}
+ </li>
+ {% endif %}
-
+
- {% if perms.rh %}
- <li>
- <a href="{% url admin:app_list app_label="rh" %}">Gestion des personnels</a>
- </li>
- {% endif %}
+ {% if perms.rh %}
+ <li>
+ <a href="{% url admin:app_list app_label="rh" %}">Gestion des personnels</a>
+ </li>
{% endif %}
-
</ul>
+++ /dev/null
--# -*- encoding: utf-8 -*-
--
--from django.db import models
--
--
--class NoDeleteQuerySet(models.query.QuerySet):
-- """
-- Pas de delete, flag à supprimer sur les entrées.
-- """
-- def delete(self):
-- self.update(supprime=True)
--
--
--class NoDeleteManager(models.Manager):
-- """
-- Les entrées supprimées sont exclues des querysets.
-- """
-- def get_query_set(self):
-- return NoDeleteQuerySet(self.model, using=self._db).filter(supprime=False)