Merge branch 'master' into test
[auf_rh_dae.git] / project / dae / views.py
1 # -*- encoding: utf-8 -*-
2
3 from datetime import date, datetime
4
5 from auf.django.permissions.decorators import get_object
6 from django.contrib import messages
7 from django.contrib.auth.decorators import login_required, user_passes_test
8 from django.contrib.contenttypes.models import ContentType
9 from django.core.paginator import Paginator, InvalidPage
10 from django.db.models import Q, Count
11 from django.http import Http404, HttpResponse, HttpResponseNotFound
12 from django.shortcuts import redirect, render, get_object_or_404
13 from sendfile import sendfile
14 from simplejson import dumps
15
16 from project.dae import models as dae
17 from project.dae.decorators import \
18 dae_groupe_requis, \
19 poste_dans_ma_region_ou_service, \
20 dossier_dans_ma_region_ou_service, \
21 vieux_dossier_dans_ma_region_ou_service, \
22 employe_dans_ma_region_ou_service, \
23 dossier_est_modifiable, \
24 poste_est_modifiable, get_contrat
25 from project.dae.forms import FinancementFormSet, FinancementFormSetInitial
26 from project.dae.forms import \
27 PosteComparaisonFormSet, PosteComparaisonFormSetInitial
28 from project.dae.forms import \
29 PosteWorkflowForm, PosteForm, PostePieceFormSet, \
30 DossierWorkflowForm, ChoosePosteForm, \
31 EmployeForm, DossierForm, DossierPieceForm, \
32 DossierComparaisonFormSet, RemunForm, ContratForm, DAENumeriseeForm, \
33 label_poste_display, DAEFinaliseesSearchForm
34 from project.dae.mail import send_drh_finalisation_mail
35 from project.dae.workflow import \
36 DOSSIER_ETAT_FINALISE, DOSSIER_ETAT_REGION_FINALISATION, \
37 DOSSIER_ETAT_DRH_FINALISATION, POSTE_ETAT_FINALISE
38 from project.decorators import redirect_interdiction,\
39 drh_or_admin_required,\
40 in_drh_or_admin,\
41 in_one_of_group
42 from project.rh import models as rh
43 from project import groups
44
45
46 # Helpers
47
48 def devises():
49 liste = []
50 for d in rh.Devise.objects.all():
51 annee = date.today().year
52 taux = rh.TauxChange.objects.filter(annee=annee, devise=d)
53 data = {}
54 if len(taux) == 0:
55 data['taux_euro'] = 0
56 else:
57 data['taux_euro'] = taux[0].taux
58 data['devise_code'] = d.id
59 liste.append(data)
60 return liste
61
62
63 @dae_groupe_requis
64 def index(request):
65 return render(request, 'dae/index.html', {})
66
67
68 ### POSTE
69
70 @dae_groupe_requis
71 @poste_dans_ma_region_ou_service
72 def poste_consulter(request, key):
73 source, id = key.split('-')
74 poste = get_object_or_404(dae.Poste, pk=id)
75
76 if request.POST:
77 validationForm = PosteWorkflowForm(
78 request.POST, instance=poste, request=request
79 )
80 if validationForm.is_valid():
81 validationForm.save()
82 messages.add_message(
83 request, messages.SUCCESS, "La validation a été enregistrée."
84 )
85 return redirect('dae_postes_liste')
86 else:
87 validationForm = PosteWorkflowForm(instance=poste, request=request)
88
89 comparaisons_internes = \
90 poste.dae_comparaisons_internes.ma_region_ou_service(request.user)
91 return render(request, 'dae/poste_consulter.html', {
92 'poste': poste,
93 'validationForm': validationForm,
94 'comparaisons_internes': comparaisons_internes,
95 'importer': request.user.is_superuser,
96 })
97
98
99 @user_passes_test(lambda u: u.is_superuser)
100 @drh_or_admin_required
101 def poste_importer(request, id):
102 poste_dae = get_object_or_404(dae.Poste, id=id)
103 if request.method == 'POST':
104 if 'confirmer' in request.POST:
105 poste_rh = poste_dae.importer_dans_rh()
106 return redirect('admin:rh_poste_change', poste_rh.id)
107 else:
108 return redirect('poste_consulter', 'dae-' + id)
109 else:
110 c = {
111 'poste': poste_dae,
112 }
113 return render(request, 'dae/poste_importer.html', c)
114
115
116 @dae_groupe_requis
117 @poste_dans_ma_region_ou_service
118 @poste_est_modifiable
119 @in_one_of_group((groups.CORRESPONDANT_RH,
120 groups.ADMINISTRATEURS,
121 groups.DIRECTEUR_DE_BUREAU,
122 groups.DRH_NIVEAU_1,
123 groups.DRH_NIVEAU_2))
124 def poste(request, key=None):
125 """ Formulaire pour un poste.
126
127 Permet de créer ou modifier un poste. Si le poste n'existe que dans rh_v1
128 il est automatiquement copié dans dae.
129
130 """
131 if 'creer_dossier_dae' in request.GET:
132 creer_dossier_dae = True
133 else:
134 creer_dossier_dae = False
135
136 def _dupliquer_poste(poste_dae, poste_rh):
137 """
138 Recopie les fields d'un poste RH dans un poste DAE
139 avec ceux-ci précédemment crées
140 """
141 exclus = ('id', 'supprime', 'date_creation',
142 'user_creation', 'date_modification',
143 'user_modification', )
144 fields = [f for f in poste_rh._meta.fields if f.name not in exclus]
145 for field in fields:
146 setattr(poste_dae, field.name, getattr(poste_rh, field.name))
147 return poste_dae
148
149 poste, data, vars = None, dict(), dict()
150
151 # Sans key, c'est un nouveau poste
152 if key is None:
153 new = True
154 else:
155 new = False
156
157 # Type intervention
158 if 'type_intervention' in request.GET:
159 data['type_intervention'] = request.GET['type_intervention']
160 if creer_dossier_dae:
161 data['type_intervention'] = request.GET['creer_dossier_dae']
162
163 # Poste existant
164 poste_rh = None
165 if not new:
166 source, id = key.split('-')
167
168 if source == 'dae':
169 poste = get_object_or_404(dae.Poste, pk=id)
170 data['poste'] = key
171 elif source == 'rh':
172 poste_rh = get_object_or_404(rh.Poste, pk=id)
173 poste = dae.Poste(id_rh=poste_rh)
174 # Initialisation avec les valeurs du poste de rh_v1
175 poste = _dupliquer_poste(poste, poste_rh)
176 data['poste'] = 'rh-' + str(poste.id_rh_id)
177
178 # prépopuler pour la modification de poste
179 if poste_rh is not None:
180 FinancementForm = FinancementFormSetInitial
181 PosteComparaisonForm = PosteComparaisonFormSetInitial
182
183 qs_financements = poste_rh.rh_financements.all()
184 qs_comparaisons = poste_rh.rh_comparaisons_internes.all()
185 financements = [{'type': f.type, 'pourcentage': f.pourcentage,
186 'commentaire': f.commentaire} for f in qs_financements]
187 comparaisons = [{'implantation': c.implantation, 'nom': c.nom,
188 'montant': c.montant, 'devise': c.devise} for c in qs_comparaisons]
189 # formulaires normaux, avec modifications des objects FK
190 else:
191 FinancementForm = FinancementFormSet
192 PosteComparaisonForm = PosteComparaisonFormSet
193 financements = []
194 comparaisons = []
195
196 if request.POST:
197 data.update(dict(request.POST.items()))
198 form = PosteForm(data, instance=poste, request=request)
199 financementForm = FinancementForm(request.POST, instance=poste, )
200 piecesForm = PostePieceFormSet(
201 request.POST, request.FILES, instance=poste
202 )
203 comparaisons_formset = PosteComparaisonForm(
204 request.POST,
205 instance=poste,
206 )
207 if form.is_valid() and piecesForm.is_valid() and \
208 financementForm.is_valid() and comparaisons_formset.is_valid():
209 poste = form.save()
210 piecesForm.instance = poste
211 piecesForm.save()
212 financementForm.instance = poste
213 financementForm.save()
214
215 # Ne remplacer que les comparaisons de ma région
216 comparaisons = comparaisons_formset.save(commit=False)
217 for comparaison in comparaisons:
218 comparaison.poste = poste
219 comparaison.save()
220
221 # dans le cas d'une modification de poste de RH, on recopie les PJ
222 if poste_rh is not None:
223 for piece in poste_rh.rh_pieces.all():
224 dae.PostePiece(poste=poste, nom=piece.nom,
225 fichier=piece.fichier).save()
226 messages.add_message(
227 request, messages.SUCCESS,
228 "Le poste %s a été sauvegardé." % poste
229 )
230 if creer_dossier_dae:
231 return redirect('embauche', key='dae-%s' % poste.id)
232
233 if 'save' in request.POST:
234 return redirect('poste_consulter', key='dae-%s' % poste.id)
235 else:
236 return redirect('poste', key='dae-%s' % poste.id)
237
238 else:
239 messages.add_message(
240 request, messages.ERROR,
241 'Il y a des erreurs dans le formulaire.'
242 )
243
244 else:
245 # 'initial' évite la validation prémature lors d'une copie de poste de
246 # rh_v1 vers dae.
247 form = PosteForm(initial=data, instance=poste, request=request)
248 piecesForm = PostePieceFormSet(instance=poste)
249
250 if poste_rh is not None:
251 financementForm = FinancementForm(
252 initial=financements, instance=poste
253 )
254 comparaisons_formset = PosteComparaisonForm(
255 initial=comparaisons,
256 instance=poste,
257 )
258 # cas de la création d'un nouveau poste
259 else:
260 financementForm = FinancementForm(instance=poste)
261 comparaisons_formset = PosteComparaisonForm(instance=poste)
262
263 vars.update(dict(
264 form=form, poste=poste, poste_key=key, piecesForm=piecesForm,
265 financementForm=financementForm,
266 comparaisons_formset=comparaisons_formset,
267 poste_rh=poste_rh,
268 creer_dossier_dae=creer_dossier_dae,
269 ))
270
271 return render(request, 'dae/poste.html', vars)
272
273
274 @dae_groupe_requis
275 def postes_liste(request):
276 """ Liste des postes. """
277 content_type = ContentType.objects.get_for_model(dae.Poste)
278 extra_select = {'derniere_validation': (
279 "SELECT MAX(date) FROM workflow_workflowcommentaire "
280 "WHERE content_type_id = '%s' AND object_id = dae_poste.id" %
281 content_type.id
282 )}
283 postes_a_traiter = dae.Poste.objects.mes_choses_a_faire(request.user) \
284 .annotate(num_dae=Count('dae_dossiers')) \
285 .filter(num_dae=0) \
286 .extra(select=extra_select).order_by('-id')
287 postes_en_cours = dae.Poste.objects.ma_region_ou_service(request.user) \
288 .annotate(num_dae=Count('dae_dossiers')) \
289 .filter(num_dae=0) \
290 .extra(select=extra_select) \
291 .filter(~Q(etat=POSTE_ETAT_FINALISE)) \
292 .order_by('-id')
293 return render(request, 'dae/postes_liste.html', {
294 'postes_a_traiter': postes_a_traiter,
295 'postes_en_cours': postes_en_cours,
296 })
297
298
299 @login_required
300 def poste_piece(request, id, filename):
301 """Téléchargement d'une pièce jointe à un poste."""
302 piece = get_object_or_404(dae.PostePiece, pk=id)
303 if dae.Poste.objects.ma_region_ou_service(request.user) \
304 .filter(id=piece.poste_id).exists():
305 return sendfile(request, piece.fichier.path)
306 else:
307 return redirect_interdiction(request)
308
309
310 ### DOSSIER
311
312 def filtered_type_remun():
313 defaut = (2, 3, 8, 17) # salaire de base, indemnité de fonction,
314 # charges patronales
315 return rh.TypeRemuneration.objects.filter(pk__in=defaut)
316
317
318 @dae_groupe_requis
319 @dossier_dans_ma_region_ou_service
320 def embauche_consulter(request, dossier_id):
321 dossier = get_object_or_404(dae.Dossier, pk=dossier_id)
322 etat_precedent = dossier.etat
323
324 if request.POST:
325 validationForm = DossierWorkflowForm(
326 request.POST, instance=dossier, request=request
327 )
328 if validationForm.is_valid():
329 if etat_precedent == DOSSIER_ETAT_REGION_FINALISATION and \
330 validationForm.cleaned_data['etat'] == \
331 DOSSIER_ETAT_DRH_FINALISATION:
332 send_drh_finalisation_mail(request, dossier)
333 validationForm.save()
334 messages.add_message(
335 request, messages.SUCCESS, "La validation a été enregistrée."
336 )
337 return redirect('dae_embauches_liste')
338 else:
339 validationForm = DossierWorkflowForm(instance=dossier, request=request)
340
341 comparaisons_internes = \
342 dossier.poste.dae_comparaisons_internes.ma_region_ou_service(
343 request.user
344 )
345 comparaisons = dossier.dae_comparaisons.ma_region_ou_service(request.user)
346 return render(request, 'dae/embauche_consulter.html', {
347 'dossier': dossier,
348 'validationForm': validationForm,
349 'comparaisons_internes': comparaisons_internes,
350 'comparaisons': comparaisons,
351 'importer': request.user.is_superuser,
352 })
353
354
355 @user_passes_test(lambda u: u.is_superuser)
356 @dae_groupe_requis
357 @dossier_dans_ma_region_ou_service
358 def embauche_importer(request, dossier_id=None):
359 dossier_dae = get_object_or_404(dae.Dossier, id=dossier_id)
360 if request.method == 'POST':
361 if 'confirmer' in request.POST:
362 dossier_rh = dossier_dae.importer_dans_rh()
363 return redirect('admin:rh_dossier_change', dossier_rh.id)
364 else:
365 return redirect('embauches_finalisees')
366 else:
367 c = {
368 'dossier': dossier_dae,
369 }
370 return render(request, 'dae/embauche_importer.html', c)
371
372
373 @dae_groupe_requis
374 def embauche_choisir_poste(request):
375 if request.POST:
376 form = ChoosePosteForm(data=request.POST, request=request)
377 if form.is_valid():
378 return form.redirect()
379 else:
380 form = ChoosePosteForm(request=request)
381 c = {
382 'form': form,
383 }
384 return render(request, 'dae/embauche-choisir-poste.html', c)
385
386
387 @dae_groupe_requis
388 @dossier_dans_ma_region_ou_service
389 @dossier_est_modifiable
390 def embauche(request, key=None, dossier_id=None):
391 """ Formulaire d'autorisation d'embauche. """
392
393 # Récupérer ou créer un poste et un dossier
394 source, id = key.split('-')
395 if source != 'dae':
396 return Http404
397 poste = get_object_or_404(dae.Poste, pk=id)
398
399 if request.POST:
400 if request.POST['employe'] == '':
401 # Nouvel employé
402 employe = dae.Employe()
403 else:
404 employe_source, id = request.POST['employe'].split('-')
405 if employe_source == 'dae':
406 # Employé DAE
407 employe = get_object_or_404(dae.Employe, pk=id)
408 elif employe_source == 'rh':
409 # Employé RH, on le copie dans DAE
410 e = get_object_or_404(rh.Employe, pk=id)
411 employe = dae.Employe(id_rh=e, prenom=e.prenom, nom=e.nom,
412 genre=e.genre)
413 else:
414 raise Http404
415
416 employe_form = EmployeForm(
417 request.POST, instance=employe, request=request
418 )
419
420 if employe_form.is_valid():
421 data = dict(request.POST.items())
422 employe = employe_form.save()
423 data['employe'] = 'dae-%s' % employe.id
424 employe_form = EmployeForm(data, instance=employe, request=request)
425
426 if not dossier_id:
427 dossier = dae.Dossier(poste=poste, employe=employe)
428 else:
429 dossier = get_object_or_404(dae.Dossier, pk=dossier_id)
430 dossier.employe = employe_form.instance
431
432 dossier_form = DossierForm(request.POST, instance=dossier)
433 piecesForm = DossierPieceForm(
434 request.POST, request.FILES, instance=dossier
435 )
436 comparaisons_formset = DossierComparaisonFormSet(
437 request.POST,
438 queryset=dossier.dae_comparaisons.ma_region_ou_service(
439 request.user
440 )
441 )
442 remunForm = RemunForm(request.POST, instance=dossier)
443
444 if employe_form.is_valid() and \
445 dossier_form.is_valid() and \
446 piecesForm.is_valid() and \
447 comparaisons_formset.is_valid() and \
448 remunForm.is_valid():
449 employe.save()
450 dossier_form.save()
451 piecesForm.save()
452 remunForm.save()
453
454 # Ne remplacer que les comparaisons de ma région
455 comparaisons = comparaisons_formset.save(commit=False)
456 for comparaison in comparaisons:
457 comparaison.dossier = dossier
458 comparaison.save()
459
460 messages.success(
461 request, "Le dossier %s a été sauvegardé." % dossier
462 )
463 if 'save' in request.POST:
464 return redirect('embauche_consulter', dossier_id=dossier.id)
465 else:
466 return redirect(
467 'embauche', key=dossier.poste.key, dossier_id=dossier.id
468 )
469
470 else:
471 messages.add_message(
472 request, messages.ERROR,
473 'Il y a des erreurs dans le formulaire.'
474 )
475
476 else:
477 # Initialisation d'un formulaire vide
478 if dossier_id:
479 dossier = get_object_or_404(dae.Dossier, pk=dossier_id)
480 employe = dossier.employe
481 data = dict(employe='dae-%s' % employe.id)
482 employe_form = EmployeForm(
483 initial=data, instance=employe, request=request
484 )
485 else:
486 dossier_rh = rh.Dossier()
487 poste_rh = poste.id_rh
488 dossier = pre_filled_dossier(dossier_rh, 'new', poste_rh)
489 employe_form = EmployeForm(request=request)
490
491 dossier_form = DossierForm(instance=dossier)
492 piecesForm = DossierPieceForm(instance=dossier)
493 comparaisons_formset = DossierComparaisonFormSet(
494 queryset=dossier.dae_comparaisons.ma_region_ou_service(
495 request.user
496 )
497 )
498 remunForm = RemunForm(instance=dossier)
499
500 try:
501 comparaisons_internes = \
502 dossier.poste.dae_comparaisons_internes.ma_region_ou_service(
503 request.user
504 )
505 except dae.Poste.DoesNotExist:
506 comparaisons_internes = []
507 c = {
508 'type_remun': filtered_type_remun(),
509 'devises': devises(),
510 'poste': poste,
511 'dossier': dossier,
512 'piecesForm': piecesForm,
513 'remunForm': remunForm,
514 'comparaisons_formset': comparaisons_formset,
515 'forms': dict(employe=employe_form, dossier=dossier_form, ),
516 'comparaisons_internes': comparaisons_internes,
517 }
518 return render(request, 'dae/embauche.html', c)
519
520
521 @dae_groupe_requis
522 @dossier_dans_ma_region_ou_service
523 def embauches_liste(request):
524 """ Liste des embauches. """
525 content_type = ContentType.objects.get_for_model(dae.Dossier)
526 extra_select = {'derniere_validation': (
527 "SELECT MAX(date) FROM workflow_workflowcommentaire "
528 "WHERE content_type_id = '%s' AND object_id = dae_dossier.id" %
529 content_type.id
530 )}
531 embauches_a_traiter = dae.Dossier.objects \
532 .mes_choses_a_faire(request.user) \
533 .extra(select=extra_select).order_by('-id')
534 embauches_en_cours = dae.Dossier.objects \
535 .ma_region_ou_service(request.user) \
536 .extra(select=extra_select) \
537 .order_by('-id') \
538 .exclude(etat=DOSSIER_ETAT_FINALISE)
539 c = {
540 'embauches_a_traiter': embauches_a_traiter,
541 'embauches_en_cours': embauches_en_cours,
542 }
543 return render(request, 'dae/embauches_liste.html', c)
544
545
546 @dae_groupe_requis
547 def embauches_finalisees(request):
548 """Liste des embauches finalisées."""
549
550 ### POST
551
552 if request.method == 'POST':
553 if 'supprimer' in request.POST:
554 ids = request.POST.getlist('ids')
555 dossiers = dae.Dossier.objects.filter(id__in=ids)
556 count = dossiers.count()
557 if count > 0:
558 dossiers.delete()
559 messages.success(request, u'%d dossiers supprimés' % count)
560 return redirect(request.get_full_path())
561
562 ### GET
563
564 embauches = dae.Dossier.objects.ma_region_ou_service(request.user) \
565 .filter(etat=DOSSIER_ETAT_FINALISE)
566
567 # Recherche
568 search_form = DAEFinaliseesSearchForm(request.GET)
569 if search_form.is_valid():
570 q = search_form.cleaned_data.get('q').strip()
571 importees = search_form.cleaned_data.get('importees')
572 if q:
573 criteria = [
574 Q(**{
575 'poste__implantation__zone_administrative__nom__icontains':
576 word
577 }) |
578 Q(poste__implantation__zone_administrative__code=word) |
579 Q(poste__implantation__nom__icontains=word) |
580 Q(poste__nom__icontains=word) |
581 Q(employe__nom__icontains=word) |
582 Q(employe__prenom__icontains=word)
583 for word in q.split()
584 ]
585 embauches = embauches.filter(*criteria)
586 if importees == 'oui':
587 embauches = embauches.exclude(dossier_rh=None)
588 elif importees == 'non':
589 embauches = embauches.filter(dossier_rh=None)
590
591 # Tri
592 tri = request.GET.get('tri', None)
593 if tri and tri.startswith('-'):
594 dir = '-'
595 tri = tri[1:]
596 else:
597 dir = ''
598 if tri == 'region':
599 embauches = embauches.order_by(
600 dir + 'poste__implantation__zone_administrative__nom'
601 )
602 elif tri == 'implantation':
603 embauches = embauches.order_by(dir + 'poste__implantation__nom')
604 elif tri == 'poste':
605 embauches = embauches.order_by(dir + 'poste__nom')
606 elif tri == 'personne':
607 embauches = embauches.order_by(dir + 'employe__nom',
608 dir + 'employe__prenom')
609 elif tri == 'date_debut':
610 embauches = embauches.order_by(dir + 'debut_contrat')
611 elif tri == 'date_fin':
612 embauches = embauches.order_by(dir + 'fin_contrat')
613
614 # Pagination
615 paginator = Paginator(embauches, 20)
616 try:
617 page = paginator.page(request.GET.get('page', 1))
618 except InvalidPage:
619 page = paginator.page(1)
620
621 return render(request, 'dae/embauches_finalisees.html', {
622 'embauches': page,
623 'search_form': search_form,
624 'importer': in_drh_or_admin(request.user)
625 })
626
627
628 def employe(request, key):
629 """ Récupération AJAX de l'employé pour la page d'embauche. """
630 data = dict(employe=key)
631
632 if key == '':
633 # Nouvel employé
634 employe = dae.Employe()
635 else:
636 # Employé existant
637 source, id = key.split('-')
638
639 if source == 'dae':
640 employe = get_object_or_404(dae.Employe, pk=id)
641 elif source == 'rh':
642 e = get_object_or_404(rh.Employe, id=id)
643 # Initialisation avec les valeurs de l'employé de rh_v1
644 employe = dae.Employe(id_rh=e)
645 for field in ('prenom', 'nom', 'genre'):
646 setattr(employe, field, getattr(e, field))
647
648 return HttpResponse(
649 EmployeForm(initial=data, instance=employe, request=request).as_table()
650 )
651
652
653 ### CONTRATS
654
655 @dae_groupe_requis
656 @get_contrat
657 def contrat(request, contrat, filename):
658 return sendfile(request, contrat.fichier.path)
659
660
661 @dae_groupe_requis
662 @get_contrat
663 def contrat_supprimer(request, contrat):
664 if request.method == 'POST':
665 if 'oui' in request.POST:
666 contrat.delete()
667 return redirect('embauche_consulter', dossier_id=contrat.dossier.id)
668 c = {
669 'contrat': contrat,
670 }
671 return render(request, 'dae/contrat-supprimer.html', c)
672
673
674 @dae_groupe_requis
675 @dossier_dans_ma_region_ou_service
676 def embauche_ajouter_contrat(request, dossier_id=None):
677 dossier = get_object_or_404(dae.Dossier, pk=dossier_id)
678 if request.method == 'POST':
679 form = ContratForm(request.POST, request.FILES)
680 if form.is_valid():
681 contrat = form.save(commit=False)
682 contrat.dossier = dossier
683 contrat.date_debut = dossier.contrat_date_debut
684 contrat.date_fin = dossier.contrat_date_fin
685 contrat.save()
686 return redirect('embauche_consulter', dossier_id=dossier.id)
687 else:
688 form = ContratForm()
689
690 c = {
691 'form': form,
692 }
693 return render(request, 'dae/embauche-ajouter-contrat.html', c)
694
695
696 ### DAE NUMERISEE
697
698 @get_object(dae.Dossier, 'consulter')
699 def dae_numerisee(request, dossier):
700 return sendfile(request, dossier.dae_numerisee.path)
701
702
703 @get_object(dae.Dossier, 'modifier_dae_numerisee')
704 def dae_numerisee_modifier(request, dossier):
705 if request.method == 'POST':
706 form = DAENumeriseeForm(request.POST, request.FILES, instance=dossier)
707 if form.is_valid():
708 form.save()
709 return redirect('embauche_consulter', dossier_id=dossier.id)
710 else:
711 form = DAENumeriseeForm(instance=dossier)
712
713 c = {
714 'form': form,
715 }
716 return render(request, 'dae/dae_numerisee_modifier.html', c)
717
718
719 @get_object(dae.Dossier, 'modifier_dae_numerisee')
720 def dae_numerisee_supprimer(request, dossier):
721 if request.method == 'POST':
722 if 'oui' in request.POST:
723 dossier.dae_numerisee = None
724 dossier.save()
725 return redirect('embauche_consulter', dossier_id=dossier.id)
726 return render(request, 'dae/dae_numerisee_supprimer.html', {})
727
728
729 # AJAX SECURISE
730
731 @dae_groupe_requis
732 @employe_dans_ma_region_ou_service
733 def dossier(request, poste_key, employe_key):
734 """ Récupération AJAX du dossier pour la page d'embauche. """
735 data = dict()
736
737 poste_source, poste_id = poste_key.split('-')
738 poste = get_object_or_404(dae.Poste, pk=poste_id)
739
740 # Récupérer la devise de l'implantation lié au poste
741 implantation_devise = poste.get_default_devise()
742 data.update({'devise': implantation_devise})
743
744 if poste.id_rh_id is not None:
745 poste_rh = get_object_or_404(rh.Poste, pk=poste.id_rh_id)
746 else:
747 poste_rh = None
748
749 # NOUVEL EMPLOYE
750 if employe_key == '':
751 employe_source = 'new'
752 employe = None
753 dossier_rh = rh.Dossier()
754 dossier = pre_filled_dossier(dossier_rh, employe_source, poste_rh)
755
756 # EMPLOYE DAE
757 if employe_key.startswith('dae'):
758 employe_source, employe_id = employe_key.split('-')
759 employe_dae = get_object_or_404(dae.Employe, pk=employe_id)
760
761 # récupération de l'ancien dossier rh v1 pour l'employe DAE
762 try:
763 dossier_rh = rh.Dossier.objects.get(
764 employe=employe_dae.id_rh_id, date_fin=None
765 )
766 except (rh.Dossier.DoesNotExist):
767 dossier_rh = rh.Dossier()
768
769 # on tente de récupérer le dossier DAE, au pire on le contruit en le
770 # prépoluant avec son dossier rh v1.
771 try:
772 dossier = dae.Dossier.objects.get(employe=employe_dae, poste=poste)
773 except (dae.Dossier.DoesNotExist):
774 dossier = pre_filled_dossier(dossier_rh, employe_source, poste_rh)
775 employe = employe_dae.id_rh
776
777 # EMPLOYE RH v1
778 if employe_key.startswith('rh'):
779 employe_source, employe_id = employe_key.split('-')
780 employe_rh = get_object_or_404(rh.Employe, pk=employe_id)
781
782 # récupération de l'ancien dossier rh v1 pour l'employe rh v1, s'il
783 # n'en a pas, on en fournit un nouveau qui servira uniquement un
784 # créer un nouveau dossier DAE.
785 try:
786 dossier_rh = rh.Dossier.objects.get(
787 employe=employe_rh, date_fin=None
788 )
789 except (rh.Dossier.DoesNotExist):
790 dossier_rh = rh.Dossier()
791 dossier = pre_filled_dossier(dossier_rh, employe_source, poste_rh)
792 employe = employe_rh
793
794 dossier_form = DossierForm(initial=data, instance=dossier)
795 vars = dict(form=dossier_form, poste=poste, employe=employe)
796 return render(request, 'dae/embauche-dossier.html', vars)
797
798
799 # Cette fonction est appelée à partir de fonctions déjà sécurisée
800 def pre_filled_dossier(dossier_rh, employe_source, poste_rh):
801 dossier = dae.Dossier()
802
803 if employe_source != 'new' and dossier_rh.id:
804 dossier.statut_anterieur = dossier_rh.statut
805
806 # Certains dossiers ont un classement à zéro
807 if dossier_rh.classement_id > 0:
808 dossier.classement_anterieur = dossier_rh.classement
809
810 # Récupération du salaire de base
811 remun = dossier_rh.remunerations() \
812 .filter(type=1).order_by('-date_debut')
813 if remun:
814 dossier.salaire_anterieur = remun[0].montant
815 dossier.devise_anterieur = remun[0].devise
816
817 # Récupération du titulaire précédent
818 try:
819 dossiers = rh.Dossier.objects.order_by('-date_debut')
820 if poste_rh:
821 dossiers = dossiers.filter(poste=poste_rh)
822 else:
823 dossiers = rh.Dossier.objects.none()
824 if len(dossiers):
825 # Ce bloc ignore toutes les erreurs, car les données de rh
826 # manquantes peuvent en générer
827 d = dossiers[0]
828 try:
829 titulaire = d.employe
830 dossier.employe_anterieur = titulaire
831 dossier.classement_titulaire_anterieur = d.classement
832 dossier.statut_titulaire_anterieur = d.statut
833 remun = d.remunerations().filter(type=1) \
834 .order_by('-date_debut')[0]
835 dossier.salaire_titulaire_anterieur = remun.montant
836 dossier.devise_titulaire_anterieur = remun.devise
837 except:
838 pass
839 # TODO: afficher l'info, les champs ne sont pas dans le
840 # modèle dae.Dossier: nom, prenom, classement, salaire
841 pass
842
843 except (rh.Dossier.DoesNotExist):
844 dossier_rh = rh.Dossier()
845
846 return dossier
847
848
849 def _get_salaire_traitement(dossier):
850 """
851 Type de remun traitement derniers commencant a la meme date
852 """
853 data = {}
854 # Toutes les rémunérations d'un dossier
855 remunerations = [
856 r for r in dossier.remunerations().order_by('-date_debut')
857 if r.type.nature_remuneration == "Traitement"
858 ]
859
860 # On prend les dernières avec le postulat que les rémun à la même date
861 # constituent le dernier salaire
862 if len(remunerations) > 0:
863 date_debut = remunerations[0].date_debut
864 remunerations = [r for r in remunerations if r.date_debut == date_debut]
865
866 montant = 0.0
867 montant_euros = 0.0
868 devise = None
869
870 # Les remun sont sensées être dans la même devise
871 for r in remunerations:
872 montant += float(r.montant)
873 montant_euros += r.montant_euros()
874 devise = r.devise.id
875
876 data['devise'] = devise
877 data['montant'] = montant
878 data['montant_euros'] = montant_euros
879 return data
880
881
882 @dae_groupe_requis
883 @vieux_dossier_dans_ma_region_ou_service
884 def dossier_resume(request, dossier_id=None):
885 try:
886 dossier = rh.Dossier.objects.get(id=dossier_id)
887 except:
888 return HttpResponseNotFound("Ce dossier n'est pas accessible")
889
890 data = {}
891 data['personne'] = unicode(dossier.employe)
892 if dossier.classement is not None:
893 data['classement'] = dossier.classement.id
894 if dossier.statut is not None:
895 data['statut'] = dossier.statut.id
896 data['implantation'] = dossier.poste.implantation.id
897 data['poste'] = dossier.poste.nom
898 data.update(_get_salaire_traitement(dossier))
899 return HttpResponse(dumps(data))
900
901
902 @dae_groupe_requis
903 @vieux_dossier_dans_ma_region_ou_service
904 def poste_resume(request, dossier_id=None):
905 """
906 On travaille, en réalité sur le dossier mais on cache
907 l'identité de la personne.
908 """
909 try:
910 dossier = rh.Dossier.objects.get(id=dossier_id)
911 except:
912 return HttpResponseNotFound("Ce dossier n'est pas accessible")
913
914 data = {}
915 data['implantation'] = dossier.poste.implantation.id
916 data['poste'] = dossier.poste.nom
917 data['statut'] = dossier.statut_id
918 data['classement'] = dossier.classement_id
919 data.update(_get_salaire_traitement(dossier))
920 return HttpResponse(dumps(data))
921
922
923 def liste_postes(request):
924 """ Appel AJAX :
925 input : implantation_id
926 output : JSON liste de valeur point
927 """
928 method = request.method
929 params = getattr(request, method, [])
930 data = []
931
932 if 'implantation_id' in params \
933 and params.get('implantation_id') is not u"":
934 implantation_id = params.get('implantation_id')
935 q = Q(implantation__id=implantation_id)
936 else:
937 q = Q()
938
939 postes_rh = rh.Poste.objects.ma_region_ou_service(request.user).filter(q)
940 postes_rh = postes_rh.select_related(depth=1)
941
942 data = [('', 'Nouveau poste')] + \
943 sorted([('rh-%s' % p.id, label_poste_display(p)) for p in
944 postes_rh],
945 key=lambda t: t[1])
946 return HttpResponse(dumps(data))
947
948
949 @login_required
950 def dossier_piece(request, id, filename):
951 """Téléchargement d'une pièce jointe à un poste."""
952 piece = get_object_or_404(dae.DossierPiece, pk=id)
953 if dae.Dossier.objects.ma_region_ou_service(request.user) \
954 .filter(id=piece.dossier_id).exists():
955 return sendfile(request, piece.fichier.path)
956 else:
957 return redirect_interdiction(request)
958
959
960 # AJAX SECURITE non nécessaire
961
962 def coefficient(request):
963 """ Appel AJAX :
964 input : classement
965 output : coefficient
966 """
967 method = request.method
968 params = getattr(request, method, [])
969 data = dict()
970 if 'classement' in params and params.get('classement') is not u"":
971 classement = params.get('classement')
972 classement = rh.Classement.objects.get(pk=classement)
973 data['coefficient'] = classement.coefficient
974 else:
975 data['coefficient'] = 0
976 return HttpResponse(dumps(data))
977
978
979 def devise(request):
980 """ Appel AJAX :
981 input : valeur_point
982 output : devise, devise_code, taux_euro
983 """
984 method = request.method
985 params = getattr(request, method, [])
986 data = dict()
987 if 'valeur_point' in params and params.get('valeur_point') is not u"":
988 valeur_point = params.get('valeur_point')
989 valeur_point = rh.ValeurPoint.objects.get(pk=valeur_point)
990 annee = valeur_point.annee
991 try:
992 taux = rh.TauxChange.objects.get(
993 annee=annee, devise=valeur_point.devise
994 )
995 except rh.TauxChange.DoesNotExist:
996 return HttpResponseNotFound(
997 u"Taux de change introuvable pour la devise %s "
998 u"pour l'année %d" % (valeur_point.devise.code, annee)
999 )
1000 except rh.TauxChange.MultipleObjectsReturned:
1001 return HttpResponseNotFound(
1002 u"Il existe plusieurs taux pour la devise %s "
1003 u"cette année-là : %s" % (valeur_point.devise.code, annee)
1004 )
1005
1006 data['devise'] = taux.devise.id
1007 data['valeur'] = valeur_point.valeur
1008 data['devise_code'] = taux.devise.code
1009 data['taux_euro'] = taux.taux
1010 else:
1011 return HttpResponseNotFound("Vous devez choisir une valeur de point")
1012 return HttpResponse(dumps(data))
1013
1014
1015 def devise_code(request):
1016 """ Appel AJAX :
1017 input : devise
1018 output : devise_code, taux_euro
1019 """
1020 method = request.method
1021 params = getattr(request, method, [])
1022 data = dict()
1023 if 'devise' in params:
1024 devise = params.get('devise')
1025 devise = rh.Devise.objects.get(pk=devise)
1026 annee = date.today().year
1027 taux = rh.TauxChange.objects.filter(annee=annee, devise=devise)
1028 if len(taux) == 0:
1029 return HttpResponseNotFound("Le taux n'est pas disponible")
1030 data['devise_code'] = devise.code
1031 data['taux_euro'] = taux[0].taux
1032 return HttpResponse(dumps(data))
1033
1034
1035 def add_remun(request, dossier, type_remun):
1036 dossier = get_object_or_404(dae.Dossier, pk=dossier)
1037 type_remun = get_object_or_404(rh.TypeRemuneration, pk=type_remun)
1038 dae.Remuneration(dossier=dossier, devise=dossier.devise,
1039 type=type_remun).save()
1040
1041 c = {
1042 'dossier': dossier,
1043 }
1044 return render(request, 'dae/embauche-remun.html', c)
1045
1046
1047 def salaire(request, implantation, devise, classement):
1048 if not devise or not classement:
1049 raise Http404
1050
1051 taux = rh.TauxChange.objects.filter(devise=devise).order_by('-annee')
1052 vp = rh.ValeurPoint.objects \
1053 .filter(implantation=implantation, devise=devise) \
1054 .order_by('-annee')
1055
1056 if vp.count() == 0:
1057 status = u"pas de valeur de point pour le couple \
1058 implantation/devise (%s/%s)" % (implantation, devise)
1059 return HttpResponse(dumps(dict(status=status)))
1060
1061 if taux.count() == 0:
1062 status = u"Pas de taux pour la devise %s" % devise
1063 return HttpResponse(dumps(dict(status=status)))
1064
1065 classement = get_object_or_404(rh.Classement, pk=classement)
1066 if classement.coefficient is None:
1067 raise Http404
1068 taux, vp = taux[0].taux, vp[0].valeur
1069
1070 salaire_euro = round(vp * classement.coefficient * taux, 2)
1071 data = dict(status='OK',
1072 salaire_euro=salaire_euro, taux=taux,
1073 salaire_devise=round(salaire_euro / taux, 2))
1074
1075 return HttpResponse(dumps(data))
1076
1077
1078 def liste_valeurs_point(request):
1079 """ Appel AJAX :
1080 input : implantation_id
1081 output : JSON liste de valeur point
1082 """
1083 method = request.method
1084 params = getattr(request, method, [])
1085 data = []
1086 annee_courante = datetime.now().year
1087 if 'implantation_id' in params \
1088 and params.get('implantation_id') is not u"":
1089 implantation_id = params.get('implantation_id')
1090 preselectionne = rh.ValeurPoint.objects \
1091 .filter(implantation=implantation_id, annee=annee_courante) \
1092 .order_by("-annee")
1093 for o in preselectionne:
1094 data.append({
1095 'id': o.id,
1096 'label': o.__unicode__(),
1097 'devise': o.devise_id,
1098 'suggestion': True
1099 })
1100 else:
1101 preselectionne = rh.ValeurPoint.objects.none()
1102
1103 liste_complete = rh.ValeurPoint.objects \
1104 .filter(annee__in=(annee_courante,)) \
1105 .order_by("-annee")
1106 for o in liste_complete.exclude(id__in=[p.id for p in preselectionne]):
1107 data.append({
1108 'id': o.id,
1109 'label': o.__unicode__(),
1110 'devise': o.devise_id,
1111 'suggestion': False
1112 })
1113 return HttpResponse(dumps(data, indent=4))