X-Git-Url: http://git.auf.org/?p=auf_rh_dae.git;a=blobdiff_plain;f=project%2Fdae%2Fviews.py;h=7277d8b3c98435ccbcaf119010f0d20b6075e4f4;hp=ff1df56099d0d7b87ab5b518d04bffaf4aebf2a0;hb=7e4113d91edc99778bf8bb281b58889563704362;hpb=9e91202fcb27dbd253c3638783e45b6d3ff6500f;ds=sidebyside diff --git a/project/dae/views.py b/project/dae/views.py index ff1df56..7277d8b 100644 --- a/project/dae/views.py +++ b/project/dae/views.py @@ -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(): @@ -86,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) @@ -113,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. @@ -120,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): """ @@ -145,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 @@ -179,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, @@ -202,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: @@ -212,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: @@ -230,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, @@ -240,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) @@ -260,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') @@ -292,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 @@ -318,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 @@ -346,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) @@ -405,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 \ @@ -420,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 @@ -472,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(), @@ -539,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) | @@ -562,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,21 +944,34 @@ def pre_filled_dossier(dossier_rh, employe_source, poste_rh): return dossier -def _get_salaire_traitement(dossier): + +def _filter_remunerations(remun_qs, only_traitement=True): """ Type de remun traitement derniers commencant a la meme date """ - data = {} # Toutes les rémunérations d'un dossier - remunerations = [r for r in dossier.remunerations().order_by('-date_debut') if \ - r.type.nature_remuneration == "Traitement"] + 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 - remunerations = [r for r in remunerations if r.date_debut == 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 @@ -840,14 +987,15 @@ def _get_salaire_traitement(dossier): 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) if dossier.classement is not None: @@ -856,6 +1004,7 @@ def dossier_resume(request, dossier_id=None): data['statut'] = dossier.statut.id data['implantation'] = dossier.poste.implantation.id data['poste'] = dossier.poste.nom + data['d_id'] = dossier.id data.update(_get_salaire_traitement(dossier)) return HttpResponse(dumps(data)) @@ -870,15 +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 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)) @@ -954,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) ) @@ -965,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)) @@ -983,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)) @@ -1011,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: @@ -1023,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))