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