fix synchro vp
[auf_rh_dae.git] / project / dae / views.py
CommitLineData
5d680e84 1# -*- encoding: utf-8 -*-
f87fe1a1
OL
2
3import datetime
cb1d62b5 4from collections import defaultdict
8e30e17f 5from datetime import date
3feae3c6 6from simplejson import dumps
768d7e1b 7import warnings
139686f2 8
a05cc82d 9from django.core.urlresolvers import reverse
86f1e48d 10from django.http import Http404, HttpResponse, HttpResponseGone
5d680e84
NC
11from django.shortcuts import redirect, render_to_response, get_object_or_404
12from django.template import RequestContext
9cb4de55 13from django.contrib import messages
5d680e84 14
ad86bbb3
OL
15from reversion.models import Version
16
139686f2 17from project.dae.forms import (ChoosePosteForm, DossierForm, EmployeForm,
d766bf2c
OL
18 PosteForm, PosteFinancementForm, PostePieceForm,
19 DossierPieceForm)
5d680e84
NC
20from project.dae import models as dae
21from project.rh_v1 import models as rh
22
e993f3dc 23from project.decorators import admin_required
a05cc82d 24from forms import PosteValidationForm
ed1982f3 25
e57fb3d8 26@admin_required
5d680e84
NC
27def index(request):
28 return render_to_response('dae/index.html', {}, RequestContext(request))
29
e57fb3d8 30@admin_required
3ed49093 31def poste(request, key=None):
5d680e84
NC
32 """ Formulaire pour un poste.
33
34 Permet de créer ou modifier un poste. Si le poste n'existe que dans rh_v1
35 il est automatiquement copié dans dae.
36
37 """
38 poste, data, vars = None, dict(), dict()
39
3ed49093 40 if key:
5d680e84 41 # Poste existant
3ed49093 42 data['poste'] = key
139686f2 43 source, id = key.split('-')
5d680e84 44
139686f2 45 if source == 'dae':
5d680e84 46 poste = get_object_or_404(dae.Poste, pk=id)
139686f2
NC
47 elif source == 'rh':
48 p = get_object_or_404(rh.Poste, pk=id)
5d680e84
NC
49 # Initialisation avec les valeurs du poste de rh_v1
50 poste = dae.Poste(id_rh=p, nom=p.type_poste.nom)
51 for field in ('implantation', 'type_poste', 'actif'):
52 setattr(poste, field, getattr(p, field))
3ed49093
NC
53 else:
54 # Nouveau poste
55 vars['new'] = True
5d680e84
NC
56
57 if request.POST:
3ed49093 58 data.update(dict(request.POST.items()))
5d680e84 59 form = PosteForm(data, instance=poste)
36341125 60 piecesForm = PostePieceForm(request.POST, request.FILES, instance=poste)
9cb4de55 61 if 'save' in data and form.is_valid() and piecesForm.is_valid():
5d680e84 62 poste = form.save()
eb8c3edb
OL
63 piecesForm.instance = poste
64 piecesForm.save()
9cb4de55 65 messages.add_message(request, messages.SUCCESS, "Le poste %s a été sauvegardé." % poste)
24d44b1b 66 return redirect('poste', key='dae-%s' % poste.id)
9cb4de55
OL
67 else:
68 messages.add_message(request, messages.ERROR, 'Il y a des erreurs dans le formulaire.')
69
5d680e84
NC
70 else:
71 # 'initial' évite la validation prémature lors d'une copie de poste de
72 # rh_v1 vers dae.
73 form = PosteForm(initial=data, instance=poste)
36341125 74 piecesForm = PostePieceForm(instance=poste)
5d680e84 75
36341125 76 vars.update(dict(form=form, poste=poste, poste_key=key, piecesForm=piecesForm))
5d680e84
NC
77
78 return render_to_response('dae/poste.html', vars, RequestContext(request))
3ed49093 79
e57fb3d8 80@admin_required
498881f4 81def postes_liste(request):
0f23302a 82 """ Liste des postes. """
498881f4 83 vars = dict()
ad86bbb3 84 vars['postes'] = []
a05cc82d 85
ad86bbb3 86 for p in dae.Poste.objects.all().order_by('-date_creation'):
26072a75 87 versions = Version.objects.get_for_object(p)
f5e9346c
OL
88 if len(versions) > 0:
89 premiere_revision = versions[0].revision
90 else:
91 premiere_revision = None
92
a05cc82d
OL
93 if request.POST:
94 validationForm = PosteValidationForm(request.POST, instance=p, prefix=p.id)
95 if validationForm.is_valid():
96 p = validationForm.save()
97 else:
98 validationForm = PosteValidationForm(instance=p, prefix=p.id)
99
100 vars['postes'].append((p, premiere_revision, validationForm))
101
102 if request.POST:
103 return redirect(reverse('dae_postes_liste'))
104
98d51b59
NC
105 return render_to_response('dae/postes_liste.html', vars,
106 RequestContext(request))
107
3ed49093
NC
108def financement(request, key=None, id=None):
109 """ Formulaire pour une source de financement pour un poste. """
110 poste, financement, data, vars = None, None, dict(), dict()
111
112 if request.POST:
113 data.update(dict(request.POST.items()))
114
115 if key:
139686f2 116 source, poste_id = key.split('-')
703e5cfb 117 vars['poste_key'] = key
139686f2 118 if source == 'dae':
3ed49093
NC
119 poste = get_object_or_404(dae.Poste, pk=poste_id)
120 if id:
121 # Financement existant
122 financement = get_object_or_404(dae.PosteFinancement, pk=id)
703e5cfb 123 vars['financement_id'] = id
3ed49093
NC
124 else:
125 # Nouveau financement
126 financement = dae.PosteFinancement(poste_id=poste_id)
127 vars['new'] = True
128
129 if not financement:
130 return Http404
131
132 if request.POST:
133 form = PosteFinancementForm(data, instance=financement)
134 if 'delete' in data:
135 financement.delete()
136 elif 'save' in data and form.is_valid():
137 financement = form.save()
138 return redirect('poste', key='dae-%s' % poste.id)
139 else:
140 form = PosteFinancementForm(initial=data, instance=financement)
141
142 vars.update(dict(form=form, financement=financement))
143
703e5cfb
NC
144 if 'ajax' in request.GET:
145 template = 'dae/financement.html'
146 else:
147 template = 'dae/financement-full.html'
148 return render_to_response(template, vars, RequestContext(request))
139686f2 149
cb1d62b5
NC
150def filtered_type_remun():
151 # Exclusion de "Indemnité de fonction" des types de rémun utilisés
152 return rh.TypeRemuneration.objects.exclude(pk=7)
153
e57fb3d8 154@admin_required
ed1982f3 155def embauche(request, key=None, dossier=None):
139686f2
NC
156 """ Formulaire d'autorisation d'embauche. """
157 if not key:
158 vars = dict(step='poste', form=ChoosePosteForm())
159 else:
cb1d62b5
NC
160 type_remun = filtered_type_remun()
161 vars = dict(type_remun=type_remun)
139686f2
NC
162 source, id = key.split('-')
163 if source != 'dae':
164 return Http404
165 poste = get_object_or_404(dae.Poste, pk=id)
cb1d62b5
NC
166 if not dossier:
167 vars['new'] = True
139686f2
NC
168
169 if request.POST:
768d7e1b
NC
170 if request.POST['employe'] == '':
171 # Nouvel employé
172 employe = dae.Employe()
139686f2 173 else:
768d7e1b
NC
174 employe_source, id = request.POST['employe'].split('-')
175 if employe_source == 'dae':
176 # Employé DAE
177 employe = get_object_or_404(dae.Employe, pk=id)
178 elif employe_source == 'rh':
179 # Employé RH, on le copie dans DAE
180 e = get_object_or_404(rh.Employe, pk=id)
181 employe = dae.Employe(id_rh=e, prenom=e.prenom, nom=e.nom,
182 genre=e.genre)
183 else:
184 raise Http404
185
139686f2 186 employe_form = EmployeForm(request.POST, instance=employe)
768d7e1b
NC
187
188 if 'save' in request.POST:
189 if employe_form.is_valid():
190 data = dict(request.POST.items())
3feae3c6
OL
191 #with warnings.catch_warnings():
192 # warnings.simplefilter('ignore')
193 employe = employe_form.save()
768d7e1b
NC
194 data['employe'] = 'dae-%s' % employe.id
195 employe_form = EmployeForm(data, instance=employe)
cb1d62b5 196
ed1982f3
NC
197 if not dossier:
198 dossier = dae.Dossier(poste=poste, employe=employe)
199 else:
200 dossier = get_object_or_404(dae.Dossier, pk=dossier)
201 dossier_form = DossierForm(request.POST, instance=dossier)
d766bf2c
OL
202 piecesForm = DossierPieceForm(request.POST, request.FILES, instance=dossier)
203
9cb4de55 204 if dossier_form.is_valid() and piecesForm.is_valid():
768d7e1b 205 dossier = dossier_form.save()
eb8c3edb
OL
206 piecesForm.instance = dossier
207 piecesForm.save()
cb1d62b5
NC
208 if not dossier.remuneration_set.all():
209 # Pré-peuplement des entrées de la section "coût
210 # global", à l'exclusion de "Indemnité de fonction"
211 for type in type_remun.all():
212 dae.Remuneration(dossier=dossier, type=type,
213 devise=dossier.devise).save()
214
215 else:
216 # Sauvegarde du coût global
217 cg_lines = defaultdict(dict)
218 for k, v in request.POST.items():
219 if k.startswith('cg-'):
220 prefix, field_name, cg_id = k.split('-')
221 cg_lines[int(cg_id)][unicode(field_name)] = v
222
223 for r in dossier.remuneration_set.all():
224 print 'trying %r' % r
225 if r.id in cg_lines:
226 if cg_lines[r.id]['montant'] == '':
227 r.delete()
228 else:
229 for k, v in cg_lines[r.id].items():
230 setattr(r, k, v)
231 r.save()
9cb4de55
OL
232
233 messages.add_message(request, messages.SUCCESS, "Le dossier %s a été sauvegardé." % dossier)
768d7e1b
NC
234 return redirect('embauche', key='dae-%s' % poste.id,
235 dossier=dossier.id)
9cb4de55
OL
236 else:
237 messages.add_message(request, messages.ERROR, 'Il y a des erreurs dans le formulaire.')
238
768d7e1b
NC
239 else:
240 dossier_form = DossierForm(instance=dossier)
d766bf2c 241 piecesForm = DossierPieceForm(instance=dossier)
ed1982f3 242 else:
768d7e1b 243 # Initialisation d'un formulaire vide
ed1982f3
NC
244 dossier_rh = rh.Dossier()
245 poste_rh = poste.id_rh
768d7e1b
NC
246 if dossier:
247 dossier = get_object_or_404(dae.Dossier, pk=dossier)
248 employe = dossier.employe
249 data = dict(employe='dae-%s' % employe.id)
250 employe_form = EmployeForm(initial=data, instance=employe)
251 else:
252 dossier = pre_filled_dossier(dossier_rh, 'new', poste_rh)
253 employe_form = EmployeForm()
d766bf2c 254
ed1982f3 255 dossier_form = DossierForm(instance=dossier)
d766bf2c 256 piecesForm = DossierPieceForm(instance=dossier)
ed1982f3 257
d766bf2c
OL
258 vars = dict(step='employe', poste=poste, dossier=dossier, piecesForm=piecesForm,
259 forms=dict(employe=employe_form, dossier=dossier_form, ))
139686f2 260
139686f2
NC
261 return render_to_response('dae/embauche.html', vars,
262 RequestContext(request))
e57fb3d8 263@admin_required
0140cbd2 264def embauches_liste(request):
265 """ Liste des embauches. """
266 vars = dict()
267 vars['embauches'] = []
268 for d in dae.Dossier.objects.all().order_by('-date_creation'):
f5e9346c
OL
269 versions = Version.objects.get_for_object(d)
270 if len(versions) > 0:
271 premiere_revision = versions[0].revision
272 else:
273 premiere_revision = None
0140cbd2 274 vars['embauches'].append((d, premiere_revision))
275 return render_to_response('dae/embauches_liste.html', vars,
276 RequestContext(request))
355c80c8 277
139686f2
NC
278def employe(request, key):
279 """ Récupération AJAX de l'employé pour la page d'embauche. """
280 data = dict(employe=key)
281
282 if key == '':
283 # Nouvel employé
284 employe = dae.Employe()
285 else:
286 # Employé existant
287 source, id = key.split('-')
288
289 if source == 'dae':
290 employe = get_object_or_404(dae.Employe, pk=id)
291 elif source == 'rh':
292 e = get_object_or_404(rh.Employe, id=id)
293 # Initialisation avec les valeurs de l'employé de rh_v1
294 employe = dae.Employe(id_rh=e)
295 for field in ('prenom', 'nom', 'genre'):
296 setattr(employe, field, getattr(e, field))
297
298 return HttpResponse(EmployeForm(initial=data, instance=employe).as_table())
299
139686f2
NC
300def dossier(request, poste_key, employe_key):
301 """ Récupération AJAX du dossier pour la page d'embauche. """
302 data = dict()
303
304 poste_source, poste_id = poste_key.split('-')
305 poste = get_object_or_404(dae.Poste, pk=poste_id)
179f6b49
OL
306
307 # Récupérer la devise de l'implantation lié au poste
308 implantation_devise = poste.get_default_devise()
309 data.update({'devise' : implantation_devise.id})
310
e27db04c
OL
311 if poste.id_rh_id is not None:
312 poste_rh = get_object_or_404(rh.Poste, pk=poste.id_rh_id)
313 else:
314 poste_rh = None
139686f2
NC
315
316 if employe_key == '':
317 employe_source = 'new'
318 dossier_rh = rh.Dossier()
319 else:
320 # Récupération des données de RH v1
321 employe_source, employe_id = employe_key.split('-')
322 if employe_source == 'dae':
323 employe = get_object_or_404(dae.Employe, pk=employe_id)
324 employe_source, employe_id = 'rh', employe.id_rh_id
325 if employe_source == 'rh':
326 employe_rh = get_object_or_404(rh.Employe, pk=employe_id)
327 try:
328 dossier_rh = rh.Dossier.objects.get(employe=employe_rh,
329 mandat_date_fin=None)
330 except (rh.Dossier.DoesNotExist):
331 dossier_rh = rh.Dossier()
332
139686f2
NC
333 # Récupération du dossier dae existant ou pré-remplissage
334 # des valeurs par défaut
335 if employe_source == 'dae':
336 try:
337 dossier = dae.Dossier.objects.get(employe=employe, poste=poste)
338 except (dae.Dossier.DoesNotExist):
ed1982f3 339 dossier = pre_filled_dossier(dossier_rh, employe_source, poste_rh)
139686f2 340 else:
ed1982f3 341 dossier = pre_filled_dossier(dossier_rh, employe_source, poste_rh)
139686f2 342
da3ca955 343 dossier_form = DossierForm(initial=data, instance=dossier)
b4583ec5 344 vars = dict(form=dossier_form, poste=poste)
da3ca955 345
346 return render_to_response('dae/embauche-dossier.html', vars,
347 RequestContext(request))
139686f2 348
139686f2
NC
349def salaire(request, implantation, devise, classement):
350 if not devise or not classement:
351 raise Http404
352
353 taux_impl = rh.TauxChange.objects.filter(implantation=implantation) \
354 .order_by('-annee')
355 taux = rh.TauxChange.objects.filter(devise=devise).order_by('-annee')
356 vp = rh.ValeurPoint.objects.filter(implantation=implantation) \
357 .order_by('-annee')
358 if vp.count() * taux.count() * taux_impl.count() == 0:
359 raise Http404
360
361 classement = get_object_or_404(rh.Classement, pk=classement)
362 taux, taux_impl, vp = taux[0].taux, taux_impl[0].taux, vp[0].valeur
363
364 salaire_euro = round(vp * classement.coefficient * taux_impl, 2)
365 data = dict(salaire_euro=salaire_euro, taux=taux,
366 salaire_devise=round(salaire_euro / taux, 2))
367
368 return HttpResponse(dumps(data))
ed1982f3 369
ed1982f3
NC
370def pre_filled_dossier(dossier_rh, employe_source, poste_rh):
371 dossier = dae.Dossier()
372
373 if employe_source != 'new' and dossier_rh.id:
374 dossier.statut_anterieur = dossier_rh.statut
375
376 # Certains dossiers ont un classement à zéro
377 if dossier_rh.classement_id > 0:
378 dossier.classement_anterieur = dossier_rh.classement
379
380 # Récupération du salaire de base
381 remun = dossier_rh.remuneration_set.filter(type=1)
382 if remun:
383 dossier.salaire_anterieur = remun[0].montant
384
385 # Récupération du titulaire précédent
386 try:
387 dossiers = rh.Dossier.objects.order_by('-mandat_date_fin')
e27db04c 388 dossiers = dossiers.filter(poste1=poste_rh) | dossiers.filter(poste2=poste_rh)
ed1982f3
NC
389 if len(dossiers):
390 # Ce bloc ignore toutes les erreurs, car les données de rh
391 # manquantes peuvent en générer
392 d = dossiers[0]
393 try:
394 titulaire = d.employe
395 dossier.employe_anterieur = titulaire
396 dossier.classement_titulaire_anterieur = d.classement
397 dossier.statut_titulaire_anterieur = d.statut
398 dossier.salaire_titulaire_anterieur = \
399 d.remuneration_set.all()[0].montant
400 except:
401 pass
402 # TODO: afficher l'info, les champs ne sont pas dans le
403 # modèle dae.Dossier: nom, prenom, classement, salaire
404 pass
405
406 except (rh.Dossier.DoesNotExist):
407 dossier_rh = rh.Dossier()
408
409 return dossier
410
b50b0cd3 411def coefficient(request):
3d627bfd 412 """ Appel AJAX :
413 input : classement
414 output : coefficient
415 """
f87fe1a1
OL
416 method = request.method
417 params = getattr(request, method, [])
b50b0cd3 418 data = dict()
be3c51e9 419 if 'classement' in params and params.get('classement') is not u"":
f87fe1a1 420 classement = params.get('classement')
b50b0cd3 421 classement = rh.Classement.objects.get(pk=classement)
422 data['coefficient'] = classement.coefficient
be3c51e9
OL
423 else:
424 data['coefficient'] = 0
b50b0cd3 425 return HttpResponse(dumps(data))
426
f87fe1a1
OL
427
428def liste_valeurs_point(request):
3d627bfd 429 """ Appel AJAX :
f87fe1a1
OL
430 input : implantation_id
431 output : JSON liste de valeur point
3d627bfd 432 """
f87fe1a1
OL
433 method = request.method
434 params = getattr(request, method, [])
435 data = []
436 annee_courante = datetime.datetime.now().year
437 if 'implantation_id' in params and params.get('implantation_id') is not u"":
438 implantation_id = params.get('implantation_id')
439 objects = rh.ValeurPoint.objects.filter(implantation=implantation_id, annee__in=(annee_courante-1, annee_courante)).order_by("-annee")
440 else:
441 objects = rh.ValeurPoint.objects.filter(annee__in=(annee_courante-1, annee_courante)).order_by("-annee")
442 for o in objects:
443 data.append({'id' : o.id, 'label' : o.__unicode__(), })
85668061 444 return HttpResponse(dumps(data))
f87fe1a1 445
3d627bfd 446def devise(request):
447 """ Appel AJAX :
448 input : valeur_point
8e30e17f 449 output : devise, devise_code, taux_euro
3d627bfd 450 """
f87fe1a1
OL
451 method = request.method
452 params = getattr(request, method, [])
3d627bfd 453 data = dict()
f87fe1a1
OL
454 if 'valeur_point' in params and params.get('valeur_point') is not u"":
455 valeur_point = params.get('valeur_point')
3d627bfd 456 valeur_point = rh.ValeurPoint.objects.get(pk=valeur_point)
457 annee = valeur_point.annee
458 implantation = valeur_point.implantation
459 taux = rh.TauxChange.objects.get(annee=annee,
460 implantation=implantation)
461 data['devise'] = taux.devise.id
f87fe1a1 462 data['valeur'] = valeur_point.valeur
3d627bfd 463 data['devise_code'] = taux.devise.code
8e30e17f 464 data['taux_euro'] = taux.taux
be3c51e9
OL
465 else:
466 return HttpResponseGone("Vous devez choisir une valeur de point")
3d627bfd 467 return HttpResponse(dumps(data))
468
469def devise_code(request):
470 """ Appel AJAX :
471 input : devise
8e30e17f 472 output : devise_code, taux_euro
3d627bfd 473 """
f87fe1a1
OL
474 method = request.method
475 params = getattr(request, method, [])
3d627bfd 476 data = dict()
f87fe1a1
OL
477 if 'devise' in params:
478 devise = params.get('devise')
3d627bfd 479 devise = rh.Devise.objects.get(pk=devise)
8e30e17f 480 annee = date.today().year
481 taux = rh.TauxChange.objects.filter(annee=annee, devise=devise)
86f1e48d
OL
482 if len(taux) == 0:
483 return HttpResponseGone("Le taux n'est pas disponible")
3d627bfd 484 data['devise_code'] = devise.code
8e30e17f 485 data['taux_euro'] = taux[0].taux
3d627bfd 486 return HttpResponse(dumps(data))
85668061 487
cb1d62b5
NC
488def add_remun(request, dossier, type_remun):
489 dossier = get_object_or_404(dae.Dossier, pk=dossier)
490 type_remun = get_object_or_404(rh.TypeRemuneration, pk=type_remun)
491 dae.Remuneration(dossier=dossier, devise=dossier.devise,
492 type=type_remun).save()
493
494 return render_to_response('dae/embauche-remun.html', dict(dossier=dossier),
495 RequestContext(request))