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