Debut de refactoring
[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
443 remunForm = RemunForm(request.POST, instance=dossier)
444
445 if employe_form.is_valid() and \
446 dossier_form.is_valid() and \
447 piecesForm.is_valid() and \
448 comparaisons_formset.is_valid() and \
449 remunForm.is_valid():
450 employe.save()
451 dossier_form.save()
452 piecesForm.save()
453 remunForm.save()
454
455 # Ne remplacer que les comparaisons de ma région
456 comparaisons = comparaisons_formset.save(commit=False)
457 for comparaison in comparaisons:
458 comparaison.dossier = dossier
459 comparaison.save()
460
461 messages.success(
462 request, "Le dossier %s a été sauvegardé." % dossier
463 )
464 if 'save' in request.POST:
465 return redirect('embauche_consulter', dossier_id=dossier.id)
466 else:
467 return redirect(
468 'embauche', key=dossier.poste.key, dossier_id=dossier.id
469 )
470
471 else:
472 messages.add_message(
473 request, messages.ERROR,
474 'Il y a des erreurs dans le formulaire.'
475 )
476
477 else:
478 # Initialisation d'un formulaire vide
479 if dossier_id:
480 dossier = get_object_or_404(dae.Dossier, pk=dossier_id)
481 employe = dossier.employe
482 data = dict(employe='dae-%s' % employe.id)
483 employe_form = EmployeForm(
484 initial=data, instance=employe, request=request
485 )
486 else:
487 dossier_rh = rh.Dossier()
488 poste_rh = poste.id_rh
489 dossier = pre_filled_dossier(dossier_rh, 'new', poste_rh)
490 employe_form = EmployeForm(request=request)
491
492 dossier_form = DossierForm(instance=dossier)
493 piecesForm = DossierPieceForm(instance=dossier)
494 comparaisons_formset = DossierComparaisonFormSet(
495 queryset=dossier.dae_comparaisons.ma_region_ou_service(
496 request.user
497 )
498 )
499 remunForm = RemunForm(instance=dossier)
500
501 try:
502 comparaisons_internes = \
503 dossier.poste.dae_comparaisons_internes.ma_region_ou_service(
504 request.user
505 )
506 except dae.Poste.DoesNotExist:
507 comparaisons_internes = []
508 c = {
509 'type_remun': filtered_type_remun(),
510 'devises': devises(),
511 'poste': poste,
512 'dossier': dossier,
513 'piecesForm': piecesForm,
514 'remunForm': remunForm,
515 'comparaisons_formset': comparaisons_formset,
516 'forms': dict(employe=employe_form, dossier=dossier_form, ),
517 'comparaisons_internes': comparaisons_internes,
518 }
519 return render(request, 'dae/embauche.html', c)
520
521
522 @dae_groupe_requis
523 @dossier_dans_ma_region_ou_service
524 def embauches_liste(request):
525 """ Liste des embauches. """
526 content_type = ContentType.objects.get_for_model(dae.Dossier)
527 extra_select = {'derniere_validation': (
528 "SELECT MAX(date) FROM workflow_workflowcommentaire "
529 "WHERE content_type_id = '%s' AND object_id = dae_dossier.id" %
530 content_type.id
531 )}
532 embauches_a_traiter = dae.Dossier.objects \
533 .mes_choses_a_faire(request.user) \
534 .extra(select=extra_select).order_by('-id')
535 embauches_en_cours = dae.Dossier.objects \
536 .ma_region_ou_service(request.user) \
537 .extra(select=extra_select) \
538 .order_by('-id') \
539 .exclude(etat=DOSSIER_ETAT_FINALISE)
540 c = {
541 'embauches_a_traiter': embauches_a_traiter,
542 'embauches_en_cours': embauches_en_cours,
543 }
544 return render(request, 'dae/embauches_liste.html', c)
545
546
547 @dae_groupe_requis
548 def embauches_finalisees(request):
549 """Liste des embauches finalisées."""
550
551 ### POST
552
553 if request.method == 'POST':
554 if 'supprimer' in request.POST:
555 ids = request.POST.getlist('ids')
556 dossiers = dae.Dossier.objects.filter(id__in=ids)
557 count = dossiers.count()
558 if count > 0:
559 dossiers.delete()
560 messages.success(request, u'%d dossiers supprimés' % count)
561 return redirect(request.get_full_path())
562
563 ### GET
564
565 embauches = dae.Dossier.objects.ma_region_ou_service(request.user) \
566 .filter(etat=DOSSIER_ETAT_FINALISE)
567
568 # Recherche
569 search_form = DAEFinaliseesSearchForm(request.GET)
570 if search_form.is_valid():
571 q = search_form.cleaned_data.get('q').strip()
572 importees = search_form.cleaned_data.get('importees')
573 if q:
574 criteria = [
575 Q(**{
576 'poste__implantation__zone_administrative__nom__icontains':
577 word
578 }) |
579 Q(poste__implantation__zone_administrative__code=word) |
580 Q(poste__implantation__nom__icontains=word) |
581 Q(poste__nom__icontains=word) |
582 Q(employe__nom__icontains=word) |
583 Q(employe__prenom__icontains=word)
584 for word in q.split()
585 ]
586 embauches = embauches.filter(*criteria)
587 if importees == 'oui':
588 embauches = embauches.exclude(dossier_rh=None)
589 elif importees == 'non':
590 embauches = embauches.filter(dossier_rh=None)
591
592 # Tri
593 tri = request.GET.get('tri', None)
594 if tri and tri.startswith('-'):
595 dir = '-'
596 tri = tri[1:]
597 else:
598 dir = ''
599 if tri == 'region':
600 embauches = embauches.order_by(
601 dir + 'poste__implantation__zone_administrative__nom'
602 )
603 elif tri == 'implantation':
604 embauches = embauches.order_by(dir + 'poste__implantation__nom')
605 elif tri == 'poste':
606 embauches = embauches.order_by(dir + 'poste__nom')
607 elif tri == 'personne':
608 embauches = embauches.order_by(dir + 'employe__nom',
609 dir + 'employe__prenom')
610 elif tri == 'date_debut':
611 embauches = embauches.order_by(dir + 'debut_contrat')
612 elif tri == 'date_fin':
613 embauches = embauches.order_by(dir + 'fin_contrat')
614
615 # Pagination
616 paginator = Paginator(embauches, 20)
617 try:
618 page = paginator.page(request.GET.get('page', 1))
619 except InvalidPage:
620 page = paginator.page(1)
621
622 return render(request, 'dae/embauches_finalisees.html', {
623 'embauches': page,
624 'search_form': search_form,
625 'importer': in_drh_or_admin(request.user)
626 })
627
628
629 def employe(request, key):
630 """ Récupération AJAX de l'employé pour la page d'embauche. """
631 data = dict(employe=key)
632
633 if key == '':
634 # Nouvel employé
635 employe = dae.Employe()
636 else:
637 # Employé existant
638 source, id = key.split('-')
639
640 if source == 'dae':
641 employe = get_object_or_404(dae.Employe, pk=id)
642 elif source == 'rh':
643 e = get_object_or_404(rh.Employe, id=id)
644 # Initialisation avec les valeurs de l'employé de rh_v1
645 employe = dae.Employe(id_rh=e)
646 for field in ('prenom', 'nom', 'genre'):
647 setattr(employe, field, getattr(e, field))
648
649 return HttpResponse(
650 EmployeForm(initial=data, instance=employe, request=request).as_table()
651 )
652
653
654 ### CONTRATS
655
656 @dae_groupe_requis
657 @get_contrat
658 def contrat(request, contrat, filename):
659 return sendfile(request, contrat.fichier.path)
660
661
662 @dae_groupe_requis
663 @get_contrat
664 def contrat_supprimer(request, contrat):
665 if request.method == 'POST':
666 if 'oui' in request.POST:
667 contrat.delete()
668 return redirect('embauche_consulter', dossier_id=contrat.dossier.id)
669 c = {
670 'contrat': contrat,
671 }
672 return render(request, 'dae/contrat-supprimer.html', c)
673
674
675 @dae_groupe_requis
676 @dossier_dans_ma_region_ou_service
677 def embauche_ajouter_contrat(request, dossier_id=None):
678 dossier = get_object_or_404(dae.Dossier, pk=dossier_id)
679 if request.method == 'POST':
680 form = ContratForm(request.POST, request.FILES)
681 if form.is_valid():
682 contrat = form.save(commit=False)
683 contrat.dossier = dossier
684 contrat.date_debut = dossier.contrat_date_debut
685 contrat.date_fin = dossier.contrat_date_fin
686 contrat.save()
687 return redirect('embauche_consulter', dossier_id=dossier.id)
688 else:
689 form = ContratForm()
690
691 c = {
692 'form': form,
693 }
694 return render(request, 'dae/embauche-ajouter-contrat.html', c)
695
696
697 ### DAE NUMERISEE
698
699 @get_object(dae.Dossier, 'consulter')
700 def dae_numerisee(request, dossier):
701 return sendfile(request, dossier.dae_numerisee.path)
702
703
704 @get_object(dae.Dossier, 'modifier_dae_numerisee')
705 def dae_numerisee_modifier(request, dossier):
706 if request.method == 'POST':
707 form = DAENumeriseeForm(request.POST, request.FILES, instance=dossier)
708 if form.is_valid():
709 form.save()
710 return redirect('embauche_consulter', dossier_id=dossier.id)
711 else:
712 form = DAENumeriseeForm(instance=dossier)
713
714 c = {
715 'form': form,
716 }
717 return render(request, 'dae/dae_numerisee_modifier.html', c)
718
719
720 @get_object(dae.Dossier, 'modifier_dae_numerisee')
721 def dae_numerisee_supprimer(request, dossier):
722 if request.method == 'POST':
723 if 'oui' in request.POST:
724 dossier.dae_numerisee = None
725 dossier.save()
726 return redirect('embauche_consulter', dossier_id=dossier.id)
727 return render(request, 'dae/dae_numerisee_supprimer.html', {})
728
729
730 # AJAX SECURISE
731
732 @dae_groupe_requis
733 @employe_dans_ma_region_ou_service
734 def dossier(request, poste_key, employe_key):
735 """ Récupération AJAX du dossier pour la page d'embauche. """
736 data = dict()
737
738 poste_source, poste_id = poste_key.split('-')
739 poste = get_object_or_404(dae.Poste, pk=poste_id)
740
741 # Récupérer la devise de l'implantation lié au poste
742 implantation_devise = poste.get_default_devise()
743 data.update({'devise': implantation_devise})
744
745 if poste.id_rh_id is not None:
746 poste_rh = get_object_or_404(rh.Poste, pk=poste.id_rh_id)
747 else:
748 poste_rh = None
749
750 # NOUVEL EMPLOYE
751 if employe_key == '':
752 employe_source = 'new'
753 employe = None
754 dossier_rh = rh.Dossier()
755 dossier = pre_filled_dossier(dossier_rh, employe_source, poste_rh)
756
757 # EMPLOYE DAE
758 if employe_key.startswith('dae'):
759 employe_source, employe_id = employe_key.split('-')
760 employe_dae = get_object_or_404(dae.Employe, pk=employe_id)
761
762 # récupération de l'ancien dossier rh v1 pour l'employe DAE
763 try:
764 dossier_rh = rh.Dossier.objects.get(
765 employe=employe_dae.id_rh_id, date_fin=None
766 )
767 except (rh.Dossier.DoesNotExist):
768 dossier_rh = rh.Dossier()
769
770 # on tente de récupérer le dossier DAE, au pire on le contruit en le
771 # prépoluant avec son dossier rh v1.
772 try:
773 dossier = dae.Dossier.objects.get(employe=employe_dae, poste=poste)
774 except (dae.Dossier.DoesNotExist):
775 dossier = pre_filled_dossier(dossier_rh, employe_source, poste_rh)
776 employe = employe_dae.id_rh
777
778 # EMPLOYE RH v1
779 if employe_key.startswith('rh'):
780 employe_source, employe_id = employe_key.split('-')
781 employe_rh = get_object_or_404(rh.Employe, pk=employe_id)
782
783 # récupération de l'ancien dossier rh v1 pour l'employe rh v1, s'il
784 # n'en a pas, on en fournit un nouveau qui servira uniquement un
785 # créer un nouveau dossier DAE.
786 try:
787 dossier_rh = rh.Dossier.objects.get(
788 employe=employe_rh, date_fin=None
789 )
790 except (rh.Dossier.DoesNotExist):
791 dossier_rh = rh.Dossier()
792 dossier = pre_filled_dossier(dossier_rh, employe_source, poste_rh)
793 employe = employe_rh
794
795 dossier_form = DossierForm(initial=data, instance=dossier)
796 vars = dict(form=dossier_form, poste=poste, employe=employe)
797 return render(request, 'dae/embauche-dossier.html', vars)
798
799
800 # Cette fonction est appelée à partir de fonctions déjà sécurisée
801 def pre_filled_dossier(dossier_rh, employe_source, poste_rh):
802 dossier = dae.Dossier()
803
804 if employe_source != 'new' and dossier_rh.id:
805 dossier.statut_anterieur = dossier_rh.statut
806
807 # Certains dossiers ont un classement à zéro
808 if dossier_rh.classement_id > 0:
809 dossier.classement_anterieur = dossier_rh.classement
810
811 # Récupération du salaire de base
812 remun = dossier_rh.remunerations() \
813 .filter(type=1).order_by('-date_debut')
814 if remun:
815 dossier.salaire_anterieur = remun[0].montant
816 dossier.devise_anterieur = remun[0].devise
817
818 # Récupération du titulaire précédent
819 try:
820 dossiers = rh.Dossier.objects.order_by('-date_debut')
821 if poste_rh:
822 dossiers = dossiers.filter(poste=poste_rh)
823 else:
824 dossiers = rh.Dossier.objects.none()
825 if len(dossiers):
826 # Ce bloc ignore toutes les erreurs, car les données de rh
827 # manquantes peuvent en générer
828 d = dossiers[0]
829 try:
830 titulaire = d.employe
831 dossier.employe_anterieur = titulaire
832 dossier.classement_titulaire_anterieur = d.classement
833 dossier.statut_titulaire_anterieur = d.statut
834 remun = d.remunerations().filter(type=1) \
835 .order_by('-date_debut')[0]
836 dossier.salaire_titulaire_anterieur = remun.montant
837 dossier.devise_titulaire_anterieur = remun.devise
838 except:
839 pass
840 # TODO: afficher l'info, les champs ne sont pas dans le
841 # modèle dae.Dossier: nom, prenom, classement, salaire
842 pass
843
844 except (rh.Dossier.DoesNotExist):
845 dossier_rh = rh.Dossier()
846
847 return dossier
848
849
850 def _get_salaire_traitement(dossier):
851 """
852 Type de remun traitement derniers commencant a la meme date
853 """
854 data = {}
855 # Toutes les rémunérations d'un dossier
856 remunerations = [
857 r for r in dossier.remunerations().order_by('-date_debut')
858 if r.type.nature_remuneration == "Traitement"
859 ]
860
861 # On prend les dernières avec le postulat que les rémun à la même date
862 # constituent le dernier salaire
863 if len(remunerations) > 0:
864 date_debut = remunerations[0].date_debut
865 remunerations = [r for r in remunerations if r.date_debut == date_debut]
866
867 montant = 0.0
868 montant_euros = 0.0
869 devise = None
870
871 # Les remun sont sensées être dans la même devise
872 for r in remunerations:
873 montant += float(r.montant)
874 montant_euros += r.montant_euros()
875 devise = r.devise.id
876
877 data['devise'] = devise
878 data['montant'] = montant
879 data['montant_euros'] = montant_euros
880 return data
881
882
883 @dae_groupe_requis
884 @vieux_dossier_dans_ma_region_ou_service
885 def dossier_resume(request, dossier_id=None):
886 try:
887 dossier = rh.Dossier.objects.get(id=dossier_id)
888 except:
889 return HttpResponseNotFound("Ce dossier n'est pas accessible")
890
891 data = {}
892 data['personne'] = unicode(dossier.employe)
893 if dossier.classement is not None:
894 data['classement'] = dossier.classement.id
895 if dossier.statut is not None:
896 data['statut'] = dossier.statut.id
897 data['implantation'] = dossier.poste.implantation.id
898 data['poste'] = dossier.poste.nom
899 data.update(_get_salaire_traitement(dossier))
900 return HttpResponse(dumps(data))
901
902
903 @dae_groupe_requis
904 @vieux_dossier_dans_ma_region_ou_service
905 def poste_resume(request, dossier_id=None):
906 """
907 On travaille, en réalité sur le dossier mais on cache
908 l'identité de la personne.
909 """
910 try:
911 dossier = rh.Dossier.objects.get(id=dossier_id)
912 except:
913 return HttpResponseNotFound("Ce dossier n'est pas accessible")
914
915 data = {}
916 data['implantation'] = dossier.poste.implantation.id
917 data['poste'] = dossier.poste.nom
918 data['statut'] = dossier.statut_id
919 data['classement'] = dossier.classement_id
920 data.update(_get_salaire_traitement(dossier))
921 return HttpResponse(dumps(data))
922
923
924 def liste_postes(request):
925 """ Appel AJAX :
926 input : implantation_id
927 output : JSON liste de valeur point
928 """
929 method = request.method
930 params = getattr(request, method, [])
931 data = []
932
933 if 'implantation_id' in params \
934 and params.get('implantation_id') is not u"":
935 implantation_id = params.get('implantation_id')
936 q = Q(implantation__id=implantation_id)
937 else:
938 q = Q()
939
940 postes_rh = rh.Poste.objects.ma_region_ou_service(request.user).filter(q)
941 postes_rh = postes_rh.select_related(depth=1)
942
943 data = [('', 'Nouveau poste')] + \
944 sorted([('rh-%s' % p.id, label_poste_display(p)) for p in
945 postes_rh],
946 key=lambda t: t[1])
947 return HttpResponse(dumps(data))
948
949
950 @login_required
951 def dossier_piece(request, id, filename):
952 """Téléchargement d'une pièce jointe à un poste."""
953 piece = get_object_or_404(dae.DossierPiece, pk=id)
954 if dae.Dossier.objects.ma_region_ou_service(request.user) \
955 .filter(id=piece.dossier_id).exists():
956 return sendfile(request, piece.fichier.path)
957 else:
958 return redirect_interdiction(request)
959
960
961 # AJAX SECURITE non nécessaire
962
963 def coefficient(request):
964 """ Appel AJAX :
965 input : classement
966 output : coefficient
967 """
968 method = request.method
969 params = getattr(request, method, [])
970 data = dict()
971 if 'classement' in params and params.get('classement') is not u"":
972 classement = params.get('classement')
973 classement = rh.Classement.objects.get(pk=classement)
974 data['coefficient'] = classement.coefficient
975 else:
976 data['coefficient'] = 0
977 return HttpResponse(dumps(data))
978
979
980 def devise(request):
981 """ Appel AJAX :
982 input : valeur_point
983 output : devise, devise_code, taux_euro
984 """
985 method = request.method
986 params = getattr(request, method, [])
987 data = dict()
988 if 'valeur_point' in params and params.get('valeur_point') is not u"":
989 valeur_point = params.get('valeur_point')
990 valeur_point = rh.ValeurPoint.objects.get(pk=valeur_point)
991 annee = valeur_point.annee
992 try:
993 taux = rh.TauxChange.objects.get(
994 annee=annee, devise=valeur_point.devise
995 )
996 except rh.TauxChange.DoesNotExist:
997 return HttpResponseNotFound(
998 u"Taux de change introuvable pour la devise %s "
999 u"pour l'année %d" % (valeur_point.devise.code, annee)
1000 )
1001 except rh.TauxChange.MultipleObjectsReturned:
1002 return HttpResponseNotFound(
1003 u"Il existe plusieurs taux pour la devise %s "
1004 u"cette année-là : %s" % (valeur_point.devise.code, annee)
1005 )
1006
1007 data['devise'] = taux.devise.id
1008 data['valeur'] = valeur_point.valeur
1009 data['devise_code'] = taux.devise.code
1010 data['taux_euro'] = taux.taux
1011 else:
1012 return HttpResponseNotFound("Vous devez choisir une valeur de point")
1013 return HttpResponse(dumps(data))
1014
1015
1016 def devise_code(request):
1017 """ Appel AJAX :
1018 input : devise
1019 output : devise_code, taux_euro
1020 """
1021 method = request.method
1022 params = getattr(request, method, [])
1023 data = dict()
1024 if 'devise' in params:
1025 devise = params.get('devise')
1026 devise = rh.Devise.objects.get(pk=devise)
1027 annee = date.today().year
1028 taux = rh.TauxChange.objects.filter(annee=annee, devise=devise)
1029 if len(taux) == 0:
1030 return HttpResponseNotFound("Le taux n'est pas disponible")
1031 data['devise_code'] = devise.code
1032 data['taux_euro'] = taux[0].taux
1033 return HttpResponse(dumps(data))
1034
1035
1036 def add_remun(request, dossier, type_remun):
1037 dossier = get_object_or_404(dae.Dossier, pk=dossier)
1038 type_remun = get_object_or_404(rh.TypeRemuneration, pk=type_remun)
1039 dae.Remuneration(dossier=dossier, devise=dossier.devise,
1040 type=type_remun).save()
1041
1042 c = {
1043 'dossier': dossier,
1044 }
1045 return render(request, 'dae/embauche-remun.html', c)
1046
1047
1048 def salaire(request, implantation, devise, classement):
1049 if not devise or not classement:
1050 raise Http404
1051
1052 taux = rh.TauxChange.objects.filter(devise=devise).order_by('-annee')
1053 vp = rh.ValeurPoint.objects \
1054 .filter(implantation=implantation, devise=devise) \
1055 .order_by('-annee')
1056
1057 if vp.count() == 0:
1058 status = u"pas de valeur de point pour le couple \
1059 implantation/devise (%s/%s)" % (implantation, devise)
1060 return HttpResponse(dumps(dict(status=status)))
1061
1062 if taux.count() == 0:
1063 status = u"Pas de taux pour la devise %s" % devise
1064 return HttpResponse(dumps(dict(status=status)))
1065
1066 classement = get_object_or_404(rh.Classement, pk=classement)
1067 if classement.coefficient is None:
1068 raise Http404
1069 taux, vp = taux[0].taux, vp[0].valeur
1070
1071 salaire_euro = round(vp * classement.coefficient * taux, 2)
1072 data = dict(status='OK',
1073 salaire_euro=salaire_euro, taux=taux,
1074 salaire_devise=round(salaire_euro / taux, 2))
1075
1076 return HttpResponse(dumps(data))
1077
1078
1079 def liste_valeurs_point(request):
1080 """ Appel AJAX :
1081 input : implantation_id
1082 output : JSON liste de valeur point
1083 """
1084 method = request.method
1085 params = getattr(request, method, [])
1086 data = []
1087 annee_courante = datetime.now().year
1088 if 'implantation_id' in params \
1089 and params.get('implantation_id') is not u"":
1090 implantation_id = params.get('implantation_id')
1091 preselectionne = rh.ValeurPoint.objects \
1092 .filter(implantation=implantation_id, annee=annee_courante) \
1093 .order_by("-annee")
1094 for o in preselectionne:
1095 data.append({
1096 'id': o.id,
1097 'label': o.__unicode__(),
1098 'devise': o.devise_id,
1099 'suggestion': True
1100 })
1101 else:
1102 preselectionne = rh.ValeurPoint.objects.none()
1103
1104 liste_complete = rh.ValeurPoint.objects \
1105 .filter(annee__in=(annee_courante,)) \
1106 .order_by("-annee")
1107 for o in liste_complete.exclude(id__in=[p.id for p in preselectionne]):
1108 data.append({
1109 'id': o.id,
1110 'label': o.__unicode__(),
1111 'devise': o.devise_id,
1112 'suggestion': False
1113 })
1114 return HttpResponse(dumps(data, indent=4))