fix
[auf_rh_dae.git] / project / dae / views.py
index e5e456c..7277d8b 100644 (file)
@@ -1,21 +1,19 @@
 # -*- encoding: utf-8 -*-
 
-import datetime
-from datetime import date
-from simplejson import dumps
+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
+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 auf.django.permissions.decorators import get_object
+from simplejson import dumps
 
 from project.dae import models as dae
 from project.dae.decorators import \
@@ -26,19 +24,29 @@ from project.dae.decorators import \
         employe_dans_ma_region_ou_service, \
         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 \
-        PosteWorkflowForm, PosteForm, FinancementForm, PostePieceForm, \
-        PosteComparaisonFormSet, DossierWorkflowForm, ChoosePosteForm, \
+        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
+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():
     liste = []
@@ -83,15 +91,17 @@ def poste_consulter(request, key):
 
     comparaisons_internes = \
             poste.dae_comparaisons_internes.ma_region_ou_service(request.user)
-    vars = {
+    return render(request, 'dae/poste_consulter.html', {
+        'devises': devises(),
         'poste': poste,
         'validationForm': validationForm,
-        'comparaisons_internes': comparaisons_internes
-    }
-
-    return render(request, 'dae/poste_consulter.html', vars)
+        'comparaisons_internes': comparaisons_internes,
+        '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)
     if request.method == 'POST':
@@ -110,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.
 
@@ -117,46 +132,81 @@ 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):
+        """
+        Recopie les fields d'un poste RH dans un poste DAE
+        avec ceux-ci précédemment crées
+        """
+        exclus = ('id', 'supprime', 'date_creation',
+                'user_creation', 'date_modification',
+                'user_modification', )
+        fields = [f for f in poste_rh._meta.fields if f.name not in exclus]
+        for field in fields:
+            setattr(poste_dae, field.name, getattr(poste_rh, field.name))
+        return poste_dae
+
     poste, data, vars = None, dict(), dict()
 
-    if key:
-        # Poste existant
+    # Sans key, c'est un nouveau poste
+    if key is None:
+        new = True
+    else:
+        new = False
+
+    # 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
+    if not new:
         source, id = key.split('-')
 
         if source == 'dae':
             poste = get_object_or_404(dae.Poste, pk=id)
+            data['poste'] = key
         elif source == 'rh':
-            p = get_object_or_404(rh.Poste, pk=id)
+            poste_rh = get_object_or_404(rh.Poste, pk=id)
+            poste = dae.Poste(id_rh=poste_rh)
             # Initialisation avec les valeurs du poste de rh_v1
-            poste = dae.Poste(id_rh=p, nom=p.type_poste.nom)
-            for field in ('implantation', 'type_poste', ):
-                setattr(poste, field, getattr(p, field))
-        if poste.id_rh_id:
+            poste = _dupliquer_poste(poste, poste_rh)
             data['poste'] = 'rh-' + str(poste.id_rh_id)
-        else:
-            data['poste'] = key
+
+    # prépopuler pour la modification de poste
+    if poste_rh is not None:
+        FinancementForm = FinancementFormSetInitial
+        PosteComparaisonForm = PosteComparaisonFormSetInitial
+
+        qs_financements = poste_rh.rh_financements.all()
+        qs_comparaisons = poste_rh.rh_comparaisons_internes.all()
+        financements = [{'type': f.type, 'pourcentage': f.pourcentage,
+            'commentaire': f.commentaire} for f in qs_financements]
+        comparaisons = [{'implantation': c.implantation, 'nom': c.nom,
+            'montant': c.montant, 'devise': c.devise} for c in qs_comparaisons]
+    # formulaires normaux, avec modifications des objects FK
     else:
-        # Nouveau poste
-        vars['new'] = True
+        FinancementForm = FinancementFormSet
+        PosteComparaisonForm = PosteComparaisonFormSet
+        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 = PostePieceForm(
+        financementForm = FinancementForm(request.POST, instance=poste, )
+        piecesForm = PostePieceFormSet(
             request.POST, request.FILES, instance=poste
         )
-        if isinstance(poste, dae.Poste):
-            comparaisons_formset = PosteComparaisonFormSet(
+        comparaisons_formset = PosteComparaisonForm(
                 request.POST,
-                queryset=poste.dae_comparaisons_internes.ma_region_ou_service(
-                    request.user
-                )
-            )
-        else:
-            comparaisons_formset = PosteComparaisonFormSet(
-                request.POST,
-                queryset=dae.PosteComparaison.objects.none()
+                instance=poste,
             )
         if form.is_valid() and piecesForm.is_valid() and \
            financementForm.is_valid() and comparaisons_formset.is_valid():
@@ -171,11 +221,52 @@ 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:
+                for piece in poste_rh.rh_pieces.all():
+                    dae.PostePiece(poste=poste, nom=piece.nom,
+                            fichier=piece.fichier).save()
             messages.add_message(
                 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:
@@ -191,23 +282,35 @@ def poste(request, key=None):
         # 'initial' évite la validation prémature lors d'une copie de poste de
         # rh_v1 vers dae.
         form = PosteForm(initial=data, instance=poste, request=request)
-        piecesForm = PostePieceForm(instance=poste)
-        financementForm = FinancementForm(instance=poste)
-        if isinstance(poste, dae.Poste):
-            comparaisons_formset = PosteComparaisonFormSet(
-                queryset=poste.dae_comparaisons_internes.ma_region_ou_service(
-                    request.user
-                )
+        piecesForm = PostePieceFormSet(instance=poste)
+
+        if poste_rh is not None:
+            financementForm = FinancementForm(
+                initial=financements, instance=poste
             )
-        else:
-            comparaisons_formset = PosteComparaisonFormSet(
-                queryset=dae.PosteComparaison.objects.none()
+            comparaisons_formset = PosteComparaisonForm(
+                initial=comparaisons,
+                instance=poste,
             )
+        # cas de la création d'un nouveau poste
+        else:
+            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
+        comparaisons_formset=comparaisons_formset,
+        poste_rh=poste_rh,
+        creer_dossier_dae=creer_dossier_dae,
     ))
 
     return render(request, 'dae/poste.html', vars)
@@ -223,16 +326,19 @@ def postes_liste(request):
         content_type.id
     )}
     postes_a_traiter = dae.Poste.objects.mes_choses_a_faire(request.user) \
-            .extra(select=extra_select).order_by('-date_creation')
+            .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('-date_creation')
-    c = {
+            .order_by('-id')
+    return render(request, 'dae/postes_liste.html', {
         'postes_a_traiter': postes_a_traiter,
         'postes_en_cours': postes_en_cours,
-    }
-    return render(request, 'dae/postes_liste.html', c)
+    })
 
 
 @login_required
@@ -256,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
 
@@ -282,15 +388,18 @@ def embauche_consulter(request, dossier_id):
                 request.user
             )
     comparaisons = dossier.dae_comparaisons.ma_region_ou_service(request.user)
-    vars = {
+
+    return render(request, 'dae/embauche_consulter.html', {
         'dossier': dossier,
+        'devises': devises(),
         'validationForm': validationForm,
         'comparaisons_internes': comparaisons_internes,
-        'comparaisons': comparaisons
-    }
-    return render(request, 'dae/embauche_consulter.html', vars)
+        'comparaisons': comparaisons,
+        'importer': request.user.is_superuser,
+    })
 
 
+@user_passes_test(lambda u: u.is_superuser)
 @dae_groupe_requis
 @dossier_dans_ma_region_ou_service
 def embauche_importer(request, dossier_id=None):
@@ -310,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)
 
@@ -369,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 \
@@ -384,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
@@ -436,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(),
@@ -462,11 +629,11 @@ def embauches_liste(request):
     )}
     embauches_a_traiter = dae.Dossier.objects \
             .mes_choses_a_faire(request.user) \
-            .extra(select=extra_select).order_by('-date_creation')
+            .extra(select=extra_select).order_by('-id')
     embauches_en_cours = dae.Dossier.objects \
             .ma_region_ou_service(request.user) \
             .extra(select=extra_select) \
-            .order_by('-date_creation') \
+            .order_by('-id') \
             .exclude(etat=DOSSIER_ETAT_FINALISE)
     c = {
         'embauches_a_traiter': embauches_a_traiter,
@@ -503,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) |
@@ -526,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')
@@ -547,11 +717,11 @@ def embauches_finalisees(request):
     except InvalidPage:
         page = paginator.page(1)
 
-    c = {
+    return render(request, 'dae/embauches_finalisees.html', {
         'embauches': page,
         'search_form': search_form,
-    }
-    return render(request, 'dae/embauches_finalisees.html', c)
+        'importer': in_drh_or_admin(request.user)
+    })
 
 
 def employe(request, key):
@@ -775,34 +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'] = u"%s %s" % (
-        dossier.poste.type_poste.nom, 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['poste'] = dossier.poste.nom
+    data['d_id'] = dossier.id
+    data.update(_get_salaire_traitement(dossier))
     return HttpResponse(dumps(data))
 
 
@@ -816,24 +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'] = u"%s %s" % (
-        dossier.poste.type_poste.nom, 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['poste'] = dossier.poste.nom
     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))
 
 
@@ -846,26 +1041,20 @@ def liste_postes(request):
     params = getattr(request, method, [])
     data = []
 
-    # Voir le code de _poste_choices dans forms.py
-    copies = dae.Poste.objects.exclude(id_rh__isnull=True) \
-            .filter(etat=POSTE_ETAT_FINALISE)
-    rh_postes_actifs = rh.Poste.objects.all()
-
     if 'implantation_id' in params \
        and params.get('implantation_id') is not u"":
         implantation_id = params.get('implantation_id')
-        copies = copies.filter(implantation__id=implantation_id)
-        rh_postes_actifs = rh_postes_actifs.filter(
-            implantation__id=implantation_id
-        )
+        q = Q(implantation__id=implantation_id)
+    else:
+        q = Q()
 
-    id_copies = [p.id_rh_id for p in copies.all()]
-    rhv1 = rh_postes_actifs.exclude(id__in=id_copies)
-    rhv1 = rhv1.select_related(depth=1)
+    postes_rh = rh.Poste.objects.ma_region_ou_service(request.user).filter(q)
+    postes_rh = postes_rh.select_related(depth=1)
 
     data = [('', 'Nouveau poste')] + \
-            sorted([('rh-%s' % p.id, label_poste_display(p)) for p in rhv1],
-                   key=lambda t: t[1])
+           sorted([('rh-%s' % p.id, label_poste_display(p)) for p in
+               postes_rh],
+                  key=lambda t: t[1])
     return HttpResponse(dumps(data))
 
 
@@ -915,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)
             )
@@ -926,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))
 
 
@@ -944,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))
@@ -972,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:
@@ -984,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))
@@ -998,7 +1195,7 @@ def liste_valeurs_point(request):
     method = request.method
     params = getattr(request, method, [])
     data = []
-    annee_courante = datetime.datetime.now().year
+    annee_courante = datetime.now().year
     if 'implantation_id' in params \
        and params.get('implantation_id') is not u"":
         implantation_id = params.get('implantation_id')