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