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