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