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