fix
[auf_rh_dae.git] / project / dae / views.py
index 9a52585..7277d8b 100644 (file)
@@ -1,15 +1,16 @@
 # -*- encoding: utf-8 -*-
 
 from datetime import date, datetime
+from dateutil.relativedelta import relativedelta
 
 from auf.django.permissions.decorators import get_object
+from auf.django.references import models as ref
 from django.contrib import messages
 from django.contrib.auth.decorators import login_required, user_passes_test
 from django.contrib.contenttypes.models import ContentType
-from django.core.exceptions import MultipleObjectsReturned
 from django.core.paginator import Paginator, InvalidPage
-from django.db.models import Q
-from django.http import Http404, HttpResponse, HttpResponseGone
+from django.db.models import Q, Count
+from django.http import Http404, HttpResponse, HttpResponseNotFound
 from django.shortcuts import redirect, render, get_object_or_404
 from sendfile import sendfile
 from simplejson import dumps
@@ -24,22 +25,27 @@ from project.dae.decorators import \
         dossier_est_modifiable, \
         poste_est_modifiable, get_contrat
 from project.dae.forms import FinancementFormSet, FinancementFormSetInitial
-from project.dae.forms import PosteComparaisonFormSet, PosteComparaisonFormSetInitial
+from project.dae.forms import \
+        PosteComparaisonFormSet, PosteComparaisonFormSetInitial
 from project.dae.forms import \
         PosteWorkflowForm, PosteForm, PostePieceFormSet, \
         DossierWorkflowForm, ChoosePosteForm, \
         EmployeForm, DossierForm, DossierPieceForm, \
         DossierComparaisonFormSet, RemunForm, ContratForm, DAENumeriseeForm, \
-        label_poste_display, DAEFinaliseesSearchForm
+        label_poste_display, DAEFinaliseesSearchForm, \
+        remun_formset_factory, ReadOnlyRemunFormSet
 from project.dae.mail import send_drh_finalisation_mail
 from project.dae.workflow import \
         DOSSIER_ETAT_FINALISE, DOSSIER_ETAT_REGION_FINALISATION, \
         DOSSIER_ETAT_DRH_FINALISATION, POSTE_ETAT_FINALISE
-from project.decorators import \
-        redirect_interdiction, drh_or_admin_required, in_drh_or_admin
+from project.decorators import redirect_interdiction,\
+        drh_or_admin_required,\
+        in_drh_or_admin,\
+        in_one_of_group
 from project.rh import models as rh
+from project import groups
 
-
 # Helpers
 
 def devises():
@@ -75,6 +81,7 @@ def poste_consulter(request, key):
             request.POST, instance=poste, request=request
         )
         if validationForm.is_valid():
+            validationForm.save()
             messages.add_message(
                 request, messages.SUCCESS, "La validation a été enregistrée."
             )
@@ -85,14 +92,15 @@ def poste_consulter(request, key):
     comparaisons_internes = \
             poste.dae_comparaisons_internes.ma_region_ou_service(request.user)
     return render(request, 'dae/poste_consulter.html', {
+        'devises': devises(),
         'poste': poste,
         'validationForm': validationForm,
         'comparaisons_internes': comparaisons_internes,
-        'importer': in_drh_or_admin(request.user)
+        'importer': request.user.is_superuser,
     })
 
 
-
+@user_passes_test(lambda u: u.is_superuser)
 @drh_or_admin_required
 def poste_importer(request, id):
     poste_dae = get_object_or_404(dae.Poste, id=id)
@@ -112,6 +120,11 @@ def poste_importer(request, id):
 @dae_groupe_requis
 @poste_dans_ma_region_ou_service
 @poste_est_modifiable
+@in_one_of_group((groups.CORRESPONDANT_RH,
+    groups.ADMINISTRATEURS,
+    groups.DIRECTEUR_DE_BUREAU,
+    groups.DRH_NIVEAU_1,
+    groups.DRH_NIVEAU_2))
 def poste(request, key=None):
     """ Formulaire pour un poste.
 
@@ -119,6 +132,10 @@ def poste(request, key=None):
     il est automatiquement copié dans dae.
 
     """
+    if 'creer_dossier_dae' in request.GET:
+        creer_dossier_dae = True
+    else:
+        creer_dossier_dae = False
 
     def _dupliquer_poste(poste_dae, poste_rh):
         """
@@ -144,6 +161,8 @@ def poste(request, key=None):
     # Type intervention
     if 'type_intervention' in request.GET:
         data['type_intervention'] = request.GET['type_intervention']
+    if creer_dossier_dae:
+        data['type_intervention'] = request.GET['creer_dossier_dae']
 
     # Poste existant
     poste_rh = None
@@ -178,12 +197,13 @@ def poste(request, key=None):
         financements = []
         comparaisons = []
 
-
     if request.POST:
         data.update(dict(request.POST.items()))
         form = PosteForm(data, instance=poste, request=request)
         financementForm = FinancementForm(request.POST, instance=poste, )
-        piecesForm = PostePieceFormSet(request.POST, request.FILES, instance=poste, )
+        piecesForm = PostePieceFormSet(
+            request.POST, request.FILES, instance=poste
+        )
         comparaisons_formset = PosteComparaisonForm(
                 request.POST,
                 instance=poste,
@@ -201,6 +221,39 @@ def poste(request, key=None):
             for comparaison in comparaisons:
                 comparaison.poste = poste
                 comparaison.save()
+            saved_cmps = [x.id for x in comparaisons]
+
+            for cmp_f in comparaisons_formset.forms:
+                comparaison = (cmp_f.instance, cmp_f)
+
+                cmp_dossier_id = comparaison[1].cleaned_data.get(
+                    'cmp_poste', None)
+                if (not cmp_dossier_id or
+                    comparaison[0].id not in saved_cmps):
+                    continue
+                cmp_dossier_qs = rh.Dossier.objects.filter(id=cmp_dossier_id)
+                if not cmp_dossier_qs.count() > 0:
+                    continue
+                dossier = rh.Dossier.objects.get(id=cmp_dossier_qs.get().id)
+
+                # Get all remunerations for a period of 1 year,
+                # going back from either: today (if dossier has not
+                # yet ended), or from dossier's date_fin.
+                cmp_date = min(dossier.date_fin or date.today(), date.today())
+                for remuneration in _filter_remunerations(
+                    dossier.remunerations().order_by('-date_debut'),
+                    only_traitement=False,
+                    ):
+                    dae.PosteComparaisonRemuneration.objects.create(
+                        poste_comparaison = comparaison[0],
+                        type=remuneration.type,
+                        type_revalorisation=remuneration.type_revalorisation,
+                        montant=remuneration.montant,
+                        devise=remuneration.devise,
+                        commentaire=remuneration.commentaire,
+                        date_debut=remuneration.date_debut,
+                        date_fin=remuneration.date_fin,
+                        )
 
             # dans le cas d'une modification de poste de RH, on recopie les PJ
             if poste_rh is not None:
@@ -211,6 +264,9 @@ def poste(request, key=None):
                 request, messages.SUCCESS,
                 "Le poste %s a été sauvegardé." % poste
             )
+            if creer_dossier_dae:
+                return redirect('embauche', key='dae-%s' % poste.id)
+
             if 'save' in request.POST:
                 return redirect('poste_consulter', key='dae-%s' % poste.id)
             else:
@@ -229,7 +285,9 @@ def poste(request, key=None):
         piecesForm = PostePieceFormSet(instance=poste)
 
         if poste_rh is not None:
-            financementForm = FinancementForm(initial=financements, instance=poste)
+            financementForm = FinancementForm(
+                initial=financements, instance=poste
+            )
             comparaisons_formset = PosteComparaisonForm(
                 initial=comparaisons,
                 instance=poste,
@@ -239,11 +297,20 @@ def poste(request, key=None):
             financementForm = FinancementForm(instance=poste)
             comparaisons_formset = PosteComparaisonForm(instance=poste)
 
+
+    # Modify queryset so that it is limited to users' rights:
+    imp_qs = dae.ProxyImplantation.dae_manager.ma_region_ou_service(
+        request.user)
+        
+    for cmp_form in comparaisons_formset.forms:
+        cmp_form.fields['implantation'].queryset = imp_qs
+
     vars.update(dict(
         form=form, poste=poste, poste_key=key, piecesForm=piecesForm,
         financementForm=financementForm,
         comparaisons_formset=comparaisons_formset,
         poste_rh=poste_rh,
+        creer_dossier_dae=creer_dossier_dae,
     ))
 
     return render(request, 'dae/poste.html', vars)
@@ -259,8 +326,12 @@ def postes_liste(request):
         content_type.id
     )}
     postes_a_traiter = dae.Poste.objects.mes_choses_a_faire(request.user) \
+            .annotate(num_dae=Count('dae_dossiers')) \
+            .filter(num_dae=0) \
             .extra(select=extra_select).order_by('-id')
     postes_en_cours = dae.Poste.objects.ma_region_ou_service(request.user) \
+            .annotate(num_dae=Count('dae_dossiers')) \
+            .filter(num_dae=0) \
             .extra(select=extra_select) \
             .filter(~Q(etat=POSTE_ETAT_FINALISE)) \
             .order_by('-id')
@@ -291,7 +362,7 @@ def filtered_type_remun():
 
 @dae_groupe_requis
 @dossier_dans_ma_region_ou_service
-def embauche_consulter(request, dossier_id):
+def embauche_consulter(request, dossier_id):    
     dossier = get_object_or_404(dae.Dossier, pk=dossier_id)
     etat_precedent = dossier.etat
 
@@ -317,14 +388,17 @@ def embauche_consulter(request, dossier_id):
                 request.user
             )
     comparaisons = dossier.dae_comparaisons.ma_region_ou_service(request.user)
+
     return render(request, 'dae/embauche_consulter.html', {
         'dossier': dossier,
+        'devises': devises(),
         'validationForm': validationForm,
         'comparaisons_internes': comparaisons_internes,
         'comparaisons': comparaisons,
-        'importer': in_drh_or_admin(request.user)
+        'importer': request.user.is_superuser,
     })
 
+
 @user_passes_test(lambda u: u.is_superuser)
 @dae_groupe_requis
 @dossier_dans_ma_region_ou_service
@@ -345,8 +419,14 @@ def embauche_importer(request, dossier_id=None):
 
 @dae_groupe_requis
 def embauche_choisir_poste(request):
+    if request.POST:
+        form = ChoosePosteForm(data=request.POST, request=request)
+        if form.is_valid():
+            return form.redirect()
+    else:
+        form = ChoosePosteForm(request=request)
     c = {
-        'form': ChoosePosteForm(request=request),
+        'form': form,
     }
     return render(request, 'dae/embauche-choisir-poste.html', c)
 
@@ -404,8 +484,9 @@ def embauche(request, key=None, dossier_id=None):
             request.POST,
             queryset=dossier.dae_comparaisons.ma_region_ou_service(
                 request.user
-            )
+            ),
         )
+        
         remunForm = RemunForm(request.POST, instance=dossier)
 
         if employe_form.is_valid() and \
@@ -419,10 +500,45 @@ def embauche(request, key=None, dossier_id=None):
             remunForm.save()
 
             # Ne remplacer que les comparaisons de ma région
+            
             comparaisons = comparaisons_formset.save(commit=False)
             for comparaison in comparaisons:
                 comparaison.dossier = dossier
                 comparaison.save()
+            saved_cmps = [x.id for x in comparaisons]
+
+            for cmp_f in comparaisons_formset.forms:
+                comparaison = (cmp_f.instance, cmp_f)
+
+                cmp_dossier_id = comparaison[1].cleaned_data.get(
+                    'cmp_dossier', None)
+                if (not cmp_dossier_id or
+                    comparaison[0].id not in saved_cmps):
+                    continue
+                cmp_dossier_qs = rh.Dossier.objects.filter(id=cmp_dossier_id)
+                if not cmp_dossier_qs.count() > 0:
+                    continue
+                rhdossier = rh.Dossier.objects.get(id=cmp_dossier_qs.get().id)
+
+
+                # Get all remunerations for a period of 1 year,
+                # going back from either: today (if cdossier has not
+                # yet ended), or from cdossier's date_fin.
+                cmp_date = min(rhdossier.date_fin or date.today(), date.today())
+                for remuneration in _filter_remunerations(
+                    rhdossier.remunerations().order_by('-date_debut'),
+                    only_traitement=False,
+                    ):
+                    dae.DossierComparaisonRemuneration.objects.create(
+                        dossier_comparaison = comparaison[0],
+                        type=remuneration.type,
+                        type_revalorisation=remuneration.type_revalorisation,
+                        montant=remuneration.montant,
+                        devise=remuneration.devise,
+                        commentaire=remuneration.commentaire,
+                        date_debut=remuneration.date_debut,
+                        date_fin=remuneration.date_fin,
+                        )
 
             messages.success(
                 request, "Le dossier %s a été sauvegardé." % dossier
@@ -471,6 +587,22 @@ def embauche(request, key=None, dossier_id=None):
                 )
     except dae.Poste.DoesNotExist:
         comparaisons_internes = []
+
+    # Modify queryset so that it is limited to users' rights:
+    imp_qs = dae.ProxyImplantation.dae_manager.ma_region_ou_service(
+        request.user)
+        
+    for cmp_form in comparaisons_formset.forms:
+        cmp_form.fields['implantation'].queryset = imp_qs
+
+    # Comment out for now.
+    # if dossier and dossier.poste:
+    #     dossier_form.fields['employe_anterieur'].queryset = (
+    #         dossier_form.fields['employe_anterieur'].queryset.filter(
+    #             rh_dossiers__poste=dossier.poste,
+    #             ).distinct()
+    #         )
+
     c = {
         'type_remun': filtered_type_remun(),
         'devises': devises(),
@@ -538,8 +670,11 @@ def embauches_finalisees(request):
         importees = search_form.cleaned_data.get('importees')
         if q:
             criteria = [
-                Q(poste__implantation__region__nom__icontains=word) |
-                Q(poste__implantation__region__code=word) |
+                Q(**{
+                    'poste__implantation__zone_administrative__nom__icontains':
+                    word
+                }) |
+                Q(poste__implantation__zone_administrative__code=word) |
                 Q(poste__implantation__nom__icontains=word) |
                 Q(poste__nom__icontains=word) |
                 Q(employe__nom__icontains=word) |
@@ -561,7 +696,7 @@ def embauches_finalisees(request):
         dir = ''
     if tri == 'region':
         embauches = embauches.order_by(
-            dir + 'poste__implantation__region__nom'
+            dir + 'poste__implantation__zone_administrative__nom'
         )
     elif tri == 'implantation':
         embauches = embauches.order_by(dir + 'poste__implantation__nom')
@@ -810,32 +945,67 @@ def pre_filled_dossier(dossier_rh, employe_source, poste_rh):
     return dossier
 
 
+def _filter_remunerations(remun_qs, only_traitement=True):
+    """
+    Type de remun traitement derniers commencant a la meme date
+    """
+    # Toutes les rémunérations d'un dossier
+    remunerations = remun_qs
+
+    if only_traitement:
+        remunerations = [
+            r for r in remun_qs
+            if r.type.nature_remuneration == "Traitement"
+            ]
+    
+    # On prend les dernières avec le postulat que les rémun à la même date
+    # constituent le dernier salaire
+    if len(remunerations) > 0:
+        date_debut = remunerations[0].date_debut
+
+    return [r for r in remunerations if r.date_debut == date_debut]
+    
+
+
+def _get_salaire_traitement(dossier):
+    data = {}
+
+    remunerations = _filter_remunerations(dossier.remunerations().order_by('-date_debut'))
+    
+    montant = 0.0
+    montant_euros = 0.0
+    devise = None
+
+    # Les remun sont sensées être dans la même devise
+    for r in remunerations:
+        montant += float(r.montant)
+        montant_euros += r.montant_euros()
+        devise = r.devise.id
+
+    data['devise'] = devise
+    data['montant'] = montant
+    data['montant_euros'] = montant_euros
+    return data
+
+
 @dae_groupe_requis
 @vieux_dossier_dans_ma_region_ou_service
 def dossier_resume(request, dossier_id=None):
     try:
         dossier = rh.Dossier.objects.get(id=dossier_id)
     except:
-        return HttpResponseGone("Ce dossier n'est pas accessible")
+        return HttpResponseNotFound("Ce dossier n'est pas accessible")
 
     data = {}
     data['personne'] = unicode(dossier.employe)
-    data['classement'] = dossier.classement.id
+    if dossier.classement is not None:
+        data['classement'] = dossier.classement.id
     if dossier.statut is not None:
         data['statut'] = dossier.statut.id
     data['implantation'] = dossier.poste.implantation.id
     data['poste'] = dossier.poste.nom
-    salaire = dossier.get_salaire()
-    if salaire is not None:
-        data['montant'] = float(salaire.montant)
-    else:
-        data['montant'] = None
-    if salaire is not None and salaire.devise is not None:
-        data['devise'] = salaire.devise.id
-        data['montant_euros'] = salaire.montant_euros()
-    else:
-        data['devise'] = None
-        data['montant_euros'] = 0
+    data['d_id'] = dossier.id
+    data.update(_get_salaire_traitement(dossier))
     return HttpResponse(dumps(data))
 
 
@@ -849,22 +1019,16 @@ def poste_resume(request, dossier_id=None):
     try:
         dossier = rh.Dossier.objects.get(id=dossier_id)
     except:
-        return HttpResponseGone("Ce dossier n'est pas accessible")
+        return HttpResponseNotFound("Ce dossier n'est pas accessible")
 
-    salaire = dossier.get_salaire()
     data = {}
     data['implantation'] = dossier.poste.implantation.id
     data['poste'] = dossier.poste.nom
-    if salaire is not None:
-        data['devise'] = salaire.devise.id
-        data['montant'] = float(salaire.montant)
-        data['montant_euros'] = salaire.montant_euros()
-    else:
-        data['devise'] = None
-        data['montant'] = ""
-        data['montant_euros'] = ""
     data['statut'] = dossier.statut_id
     data['classement'] = dossier.classement_id
+    data['d_id'] = dossier.id
+    data.update(_get_salaire_traitement(dossier))
+
     return HttpResponse(dumps(data))
 
 
@@ -940,8 +1104,13 @@ def devise(request):
             taux = rh.TauxChange.objects.get(
                 annee=annee, devise=valeur_point.devise
             )
-        except MultipleObjectsReturned:
-            return HttpResponseGone(
+        except rh.TauxChange.DoesNotExist:
+            return HttpResponseNotFound(
+                u"Taux de change introuvable pour la devise %s "
+                u"pour l'année %d" % (valeur_point.devise.code, annee)
+            )
+        except rh.TauxChange.MultipleObjectsReturned:
+            return HttpResponseNotFound(
                 u"Il existe plusieurs taux pour la devise %s "
                 u"cette année-là : %s" % (valeur_point.devise.code, annee)
             )
@@ -951,7 +1120,7 @@ def devise(request):
         data['devise_code'] = taux.devise.code
         data['taux_euro'] = taux.taux
     else:
-        return HttpResponseGone("Vous devez choisir une valeur de point")
+        return HttpResponseNotFound("Vous devez choisir une valeur de point")
     return HttpResponse(dumps(data))
 
 
@@ -969,7 +1138,7 @@ def devise_code(request):
         annee = date.today().year
         taux = rh.TauxChange.objects.filter(annee=annee, devise=devise)
         if len(taux) == 0:
-            return HttpResponseGone("Le taux n'est pas disponible")
+            return HttpResponseNotFound("Le taux n'est pas disponible")
         data['devise_code'] = devise.code
         data['taux_euro'] = taux[0].taux
     return HttpResponse(dumps(data))
@@ -997,11 +1166,13 @@ def salaire(request, implantation, devise, classement):
             .order_by('-annee')
 
     if vp.count() == 0:
-        raise Exception(u"pas de valeur de point pour le couple\
-                implantation/devise (%s/%s)" % (implantation, devise))
+        status = u"pas de valeur de point pour le couple \
+implantation/devise (%s/%s)" % (implantation, devise)
+        return HttpResponse(dumps(dict(status=status)))
 
     if taux.count() == 0:
-        raise Exception(u"Pas de taux pour la devise %s" % devise)
+        status = u"Pas de taux pour la devise %s" % devise
+        return HttpResponse(dumps(dict(status=status)))
 
     classement = get_object_or_404(rh.Classement, pk=classement)
     if classement.coefficient is None:
@@ -1009,7 +1180,8 @@ def salaire(request, implantation, devise, classement):
     taux, vp = taux[0].taux, vp[0].valeur
 
     salaire_euro = round(vp * classement.coefficient * taux, 2)
-    data = dict(salaire_euro=salaire_euro, taux=taux,
+    data = dict(status='OK',
+                salaire_euro=salaire_euro, taux=taux,
                 salaire_devise=round(salaire_euro / taux, 2))
 
     return HttpResponse(dumps(data))