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