1 # -*- encoding: utf-8 -*-
4 from collections
import defaultdict
5 from datetime
import date
6 from simplejson
import dumps
9 from django
.core
.urlresolvers
import reverse
10 from django
.http
import Http404
, HttpResponse
, HttpResponseGone
11 from django
.shortcuts
import redirect
, render_to_response
, get_object_or_404
12 from django
.template
import RequestContext
13 from django
.contrib
import messages
15 from reversion
.models
import Version
17 from project
.dae
import models
as dae
18 from project
.rh_v1
import models
as rh
20 from decorators
import dae_groupe_requis
, \
21 poste_dans_ma_region_ou_service
, \
22 dossier_dans_ma_region_ou_service
, \
23 employe_dans_ma_region_ou_service
28 return render_to_response('dae/index.html', {}, RequestContext(request
))
31 @poste_dans_ma_region_ou_service
32 def poste_consulter(request
, key
):
33 source
, id = key
.split('-')
34 poste
= get_object_or_404(dae
.Poste
, pk
=id)
37 validationForm
= PosteWorkflowForm(request
.POST
, instance
=poste
, request
=request
)
38 if validationForm
.is_valid():
40 messages
.add_message(request
, messages
.SUCCESS
, "La validation a été enregistrée.")
41 return redirect('poste_consulter', key
=key
)
43 validationForm
= PosteWorkflowForm(instance
=poste
, request
=request
)
45 vars = {'poste' : poste
, 'validationForm' : validationForm
, }
46 return render_to_response('dae/poste_consulter.html', vars, RequestContext(request
))
49 @poste_dans_ma_region_ou_service
50 def poste(request
, key
=None):
51 """ Formulaire pour un poste.
53 Permet de créer ou modifier un poste. Si le poste n'existe que dans rh_v1
54 il est automatiquement copié dans dae.
57 poste
, data
, vars = None, dict(), dict()
62 source
, id = key
.split('-')
65 poste
= get_object_or_404(dae
.Poste
, pk
=id)
67 p
= get_object_or_404(rh
.Poste
, pk
=id)
68 # Initialisation avec les valeurs du poste de rh_v1
69 poste
= dae
.Poste(id_rh
=p
, nom
=p
.type_poste
.nom
)
70 for field
in ('implantation', 'type_poste', 'actif'):
71 setattr(poste
, field
, getattr(p
, field
))
77 data
.update(dict(request
.POST
.items()))
78 form
= PosteForm(data
, instance
=poste
, request
=request
)
79 financementForm
= FinancementForm(request
.POST
, instance
=poste
)
80 piecesForm
= PostePieceForm(request
.POST
, request
.FILES
, instance
=poste
)
81 if form
.is_valid() and piecesForm
.is_valid() and financementForm
.is_valid():
83 piecesForm
.instance
= poste
85 financementForm
.instance
= poste
86 financementForm
.save()
87 messages
.add_message(request
, messages
.SUCCESS
, "Le poste %s a été sauvegardé." % poste
)
88 if request
.POST
.has_key('save'):
89 return redirect('poste_consulter', key
='dae-%s' % poste
.id)
91 return redirect('poste', key
='dae-%s' % poste
.id)
94 messages
.add_message(request
, messages
.ERROR
, 'Il y a des erreurs dans le formulaire.')
97 # 'initial' évite la validation prémature lors d'une copie de poste de
99 form
= PosteForm(initial
=data
, instance
=poste
, request
=request
)
100 piecesForm
= PostePieceForm(instance
=poste
)
101 financementForm
= FinancementForm(instance
=poste
)
103 vars.update(dict(form
=form
, poste
=poste
, poste_key
=key
, piecesForm
=piecesForm
, financementForm
=financementForm
))
105 return render_to_response('dae/poste.html', vars, RequestContext(request
))
108 def postes_liste(request
):
109 """ Liste des postes. """
111 vars['postes'] = dae
.Poste
.objects
.ma_region_ou_service(request
.user
).order_by('-date_creation')
112 return render_to_response('dae/postes_liste.html', vars, RequestContext(request
))
114 def filtered_type_remun():
115 # Exclusion de "Indemnité de fonction" des types de rémun utilisés
116 return rh
.TypeRemuneration
.objects
.exclude(pk
=7)
119 @dossier_dans_ma_region_ou_service
120 def embauche_consulter(request
, dossier_id
):
121 dossier
= get_object_or_404(dae
.Dossier
, pk
=dossier_id
)
124 validationForm
= DossierWorkflowForm(request
.POST
, instance
=dossier
, request
=request
)
125 if validationForm
.is_valid():
126 validationForm
.save()
127 messages
.add_message(request
, messages
.SUCCESS
, "La validation a été enregistrée.")
128 return redirect('embauche_consulter', dossier_id
=dossier
.id)
130 validationForm
= DossierWorkflowForm(instance
=dossier
, request
=request
)
134 'validationForm' : validationForm
,
136 return render_to_response('dae/embauche_consulter.html', vars, RequestContext(request
))
139 @dossier_dans_ma_region_ou_service
140 def embauche(request
, key
=None, dossier_id
=None):
141 """ Formulaire d'autorisation d'embauche. """
143 vars = dict(step
='poste', form
=ChoosePosteForm(request
=request
))
145 type_remun
= filtered_type_remun()
146 vars = dict(type_remun
=type_remun
)
147 source
, id = key
.split('-')
150 poste
= get_object_or_404(dae
.Poste
, pk
=id)
155 if request
.POST
['employe'] == '':
157 employe
= dae
.Employe()
159 employe_source
, id = request
.POST
['employe'].split('-')
160 if employe_source
== 'dae':
162 employe
= get_object_or_404(dae
.Employe
, pk
=id)
163 elif employe_source
== 'rh':
164 # Employé RH, on le copie dans DAE
165 e
= get_object_or_404(rh
.Employe
, pk
=id)
166 employe
= dae
.Employe(id_rh
=e
, prenom
=e
.prenom
, nom
=e
.nom
,
171 employe_form
= EmployeForm(request
.POST
, instance
=employe
, request
=request
)
174 if employe_form
.is_valid():
175 data
= dict(request
.POST
.items())
176 #with warnings.catch_warnings():
177 # warnings.simplefilter('ignore')
178 employe
= employe_form
.save()
179 data
['employe'] = 'dae-%s' % employe
.id
180 employe_form
= EmployeForm(data
, instance
=employe
, request
=request
)
183 dossier
= dae
.Dossier(poste
=poste
, employe
=employe
)
185 dossier
= get_object_or_404(dae
.Dossier
, pk
=dossier_id
)
186 dossier_form
= DossierForm(request
.POST
, instance
=dossier
)
187 piecesForm
= DossierPieceForm(request
.POST
, request
.FILES
, instance
=dossier
)
188 justificationsNouveauForm
= JustificationNouvelEmployeForm(request
.POST
, instance
=dossier
)
189 justificationsAutreForm
= JustificationAutreEmployeForm(request
.POST
, instance
=dossier
)
190 dossiersComparaisonsForm
= DossierComparaisonForm(request
.POST
, instance
=dossier
)
192 if dossier_form
.is_valid() and piecesForm
.is_valid() and justificationsNouveauForm
.is_valid() and justificationsAutreForm
.is_valid() and dossiersComparaisonsForm
.is_valid():
193 dossier
= dossier_form
.save()
194 piecesForm
.instance
= dossier
196 justificationsNouveauForm
.instance
= dossier
197 justificationsNouveauForm
.save()
198 justificationsAutreForm
.instance
= dossier
199 justificationsAutreForm
.save()
200 dossiersComparaisonsForm
.instance
= dossier
201 dossiersComparaisonsForm
.save()
203 if not dossier
.remuneration_set
.all():
204 # Pré-peuplement des entrées de la section "coût
205 # global", à l'exclusion de "Indemnité de fonction"
206 for type in type_remun
.all():
207 dae
.Remuneration(dossier
=dossier
, type=type,
208 devise
=dossier
.devise
).save()
211 # Sauvegarde du coût global
212 cg_lines
= defaultdict(dict)
213 for k
, v
in request
.POST
.items():
214 if k
.startswith('cg-'):
215 prefix
, field_name
, cg_id
= k
.split('-')
216 cg_lines
[int(cg_id
)][unicode(field_name
)] = v
218 for r
in dossier
.remuneration_set
.all():
219 print 'trying %r' % r
221 if cg_lines
[r
.id]['montant'] == '':
224 for k
, v
in cg_lines
[r
.id].items():
228 messages
.add_message(request
, messages
.SUCCESS
, "Le dossier %s a été sauvegardé." % dossier
)
229 if request
.POST
.has_key('save'):
230 return redirect('embauche_consulter', dossier_id
=dossier
.id)
232 return redirect('embauche', key
=dossier
.poste
.key
, dossier_id
=dossier
.id)
235 messages
.add_message(request
, messages
.ERROR
, 'Il y a des erreurs dans le formulaire.')
238 dossier_form
= DossierForm(instance
=dossier
)
239 piecesForm
= DossierPieceForm(instance
=dossier
)
240 justificationsNouveauForm
= JustificationNouvelEmployeForm(instance
=dossier
)
241 justificationsAutreForm
= JustificationAutreEmployeForm(instance
=dossier
)
242 dossiersComparaisonsForm
= DossierComparaisonForm(instance
=dossier
)
244 # Initialisation d'un formulaire vide
245 dossier_rh
= rh
.Dossier()
246 poste_rh
= poste
.id_rh
248 dossier
= get_object_or_404(dae
.Dossier
, pk
=dossier_id
)
249 employe
= dossier
.employe
250 data
= dict(employe
='dae-%s' % employe
.id)
251 employe_form
= EmployeForm(initial
=data
, instance
=employe
, request
=request
)
253 dossier
= pre_filled_dossier(dossier_rh
, 'new', poste_rh
)
254 employe_form
= EmployeForm(request
=request
)
256 dossier_form
= DossierForm(instance
=dossier
)
257 piecesForm
= DossierPieceForm(instance
=dossier
)
258 justificationsNouveauForm
= JustificationNouvelEmployeForm(instance
=dossier
)
259 justificationsAutreForm
= JustificationAutreEmployeForm(instance
=dossier
)
260 dossiersComparaisonsForm
= DossierComparaisonForm(instance
=dossier
)
262 vars = dict(step
='employe',
263 type_remun
=type_remun
,
266 piecesForm
=piecesForm
,
267 justificationsNouveauForm
=justificationsNouveauForm
,
268 justificationsAutreForm
=justificationsAutreForm
,
269 dossiersComparaisonsForm
=dossiersComparaisonsForm
,
270 forms
=dict(employe
=employe_form
, dossier
=dossier_form
, )
274 return render_to_response('dae/embauche.html', vars,
275 RequestContext(request
))
277 @dossier_dans_ma_region_ou_service
278 def embauches_liste(request
):
279 """ Liste des embauches. """
281 vars['embauches'] = dae
.Dossier
.objects
.ma_region_ou_service(request
.user
).order_by('-date_creation')
282 return render_to_response('dae/embauches_liste.html', vars, RequestContext(request
))
284 def employe(request
, key
):
285 """ Récupération AJAX de l'employé pour la page d'embauche. """
286 data
= dict(employe
=key
)
290 employe
= dae
.Employe()
293 source
, id = key
.split('-')
296 employe
= get_object_or_404(dae
.Employe
, pk
=id)
298 e
= get_object_or_404(rh
.Employe
, id=id)
299 # Initialisation avec les valeurs de l'employé de rh_v1
300 employe
= dae
.Employe(id_rh
=e
)
301 for field
in ('prenom', 'nom', 'genre'):
302 setattr(employe
, field
, getattr(e
, field
))
304 return HttpResponse(EmployeForm(initial
=data
, instance
=employe
, request
=request
).as_table())
306 ################################################################################
308 ################################################################################
310 @employe_dans_ma_region_ou_service
311 def dossier(request
, poste_key
, employe_key
):
312 """ Récupération AJAX du dossier pour la page d'embauche. """
315 poste_source
, poste_id
= poste_key
.split('-')
316 poste
= get_object_or_404(dae
.Poste
, pk
=poste_id
)
318 # Récupérer la devise de l'implantation lié au poste
319 implantation_devise
= poste
.get_default_devise()
320 data
.update({'devise' : implantation_devise
.id})
322 if poste
.id_rh_id
is not None:
323 poste_rh
= get_object_or_404(rh
.Poste
, pk
=poste
.id_rh_id
)
327 ##########################################################################################
329 ##########################################################################################
330 if employe_key
== '':
331 employe_source
= 'new'
333 dossier_rh
= rh
.Dossier()
334 dossier
= pre_filled_dossier(dossier_rh
, employe_source
, poste_rh
)
336 ##########################################################################################
338 ##########################################################################################
339 if employe_key
.startswith('dae'):
340 employe_source
, employe_id
= employe_key
.split('-')
341 employe_dae
= get_object_or_404(dae
.Employe
, pk
=employe_id
)
343 # récupération de l'ancien dossier rh v1 pour l'employe DAE
345 dossier_rh
= rh
.Dossier
.objects
.get(employe
=employe_dae
.id_rh_id
, mandat_date_fin
=None)
346 except (rh
.Dossier
.DoesNotExist
):
347 dossier_rh
= rh
.Dossier()
349 # on tente de récupérer le dossier DAE, au pire on le contruit en le
350 # prépoluant avec son dossier rh v1.
352 dossier
= dae
.Dossier
.objects
.get(employe
=employe_dae
, poste
=poste
)
353 except (dae
.Dossier
.DoesNotExist
):
354 dossier
= pre_filled_dossier(dossier_rh
, employe_source
, poste_rh
)
355 employe
= employe_dae
.id_rh
356 ##########################################################################################
358 ##########################################################################################
359 if employe_key
.startswith('rh'):
360 employe_source
, employe_id
= employe_key
.split('-')
361 employe_rh
= get_object_or_404(rh
.Employe
, pk
=employe_id
)
363 # récupération de l'ancien dossier rh v1 pour l'employe rh v1, s'il n'en a pas,
364 # on en fournit un nouveau qui servira uniquement un créer un nouveau dossier DAE.
366 dossier_rh
= rh
.Dossier
.objects
.get(employe
=employe_rh
, mandat_date_fin
=None)
367 except (rh
.Dossier
.DoesNotExist
):
368 dossier_rh
= rh
.Dossier()
369 dossier
= pre_filled_dossier(dossier_rh
, employe_source
, poste_rh
)
372 dossier_form
= DossierForm(initial
=data
, instance
=dossier
)
373 vars = dict(form
=dossier_form
, poste
=poste
, employe
=employe
)
374 return render_to_response('dae/embauche-dossier.html', vars,
375 RequestContext(request
))
377 # @Cette fonction est appelée à partir de fonctions déjà sécurisée
378 def pre_filled_dossier(dossier_rh
, employe_source
, poste_rh
):
379 dossier
= dae
.Dossier()
381 if employe_source
!= 'new' and dossier_rh
.id:
382 dossier
.statut_anterieur
= dossier_rh
.statut
384 # Certains dossiers ont un classement à zéro
385 if dossier_rh
.classement_id
> 0:
386 dossier
.classement_anterieur
= dossier_rh
.classement
388 # Récupération du salaire de base
389 remun
= dossier_rh
.remuneration_set
.filter(type=1)
391 dossier
.salaire_anterieur
= remun
[0].montant
393 # Récupération du titulaire précédent
395 dossiers
= rh
.Dossier
.objects
.order_by('-mandat_date_fin')
396 dossiers
= dossiers
.filter(poste1
=poste_rh
) | dossiers
.filter(poste2
=poste_rh
)
398 # Ce bloc ignore toutes les erreurs, car les données de rh
399 # manquantes peuvent en générer
402 titulaire
= d
.employe
403 dossier
.employe_anterieur
= titulaire
404 dossier
.classement_titulaire_anterieur
= d
.classement
405 dossier
.statut_titulaire_anterieur
= d
.statut
406 dossier
.salaire_titulaire_anterieur
= \
407 d
.remuneration_set
.all()[0].montant
410 # TODO: afficher l'info, les champs ne sont pas dans le
411 # modèle dae.Dossier: nom, prenom, classement, salaire
414 except (rh
.Dossier
.DoesNotExist
):
415 dossier_rh
= rh
.Dossier()
420 @dossier_dans_ma_region_ou_service
421 def dossier_resume(request
, dossier_id
=None):
424 output : devise, devise_code, taux_euro
427 dossier
= rh
.Dossier
.objects
.get(id=dossier_id
)
429 return HttpResponseGone("Ce dossier n'est pas accessible")
432 data
['personne'] = unicode(dossier
.employe
)
433 data
['implantation'] = dossier
.implantation1
.id
434 data
['poste'] = u
"%s %s" % (dossier
.poste1
.type_poste
.nom
, dossier
.complement1
)
435 data
['montant'] = dossier
.get_salaire()
436 salaire
= dossier
.get_dernier_salaire_remun()
437 if salaire
is not None:
438 data
['devise'] = dossier
.get_dernier_salaire_remun().devise
.id
439 data
['montant_euros'] = dossier
.get_dernier_salaire_remun().en_euros()
441 data
['devise'] = None
442 data
['montant_euros'] = 0
443 return HttpResponse(dumps(data
))
445 def liste_postes(request
):
447 input : implantation_id
448 output : JSON liste de valeur point
450 method
= request
.method
451 params
= getattr(request
, method
, [])
454 # Voir le code de _poste_choices dans forms.py
455 dae_
= dae
.Poste
.objects
.filter(actif
=True, id_rh__isnull
=True)
456 copies
= dae
.Poste
.objects
.exclude(id_rh__isnull
=True)
457 rh_postes_actifs
= rh
.Poste
.objects
.filter(actif
=True)
459 if 'implantation_id' in params
and params
.get('implantation_id') is not u
"":
460 implantation_id
= params
.get('implantation_id')
461 dae_
= dae_
.filter(implantation__id
=implantation_id
)
462 copies
= copies
.filter(implantation__id
=implantation_id
)
463 rh_postes_actifs
= rh_postes_actifs
.filter(implantation__id
=implantation_id
)
465 id_copies
= [p
.id_rh_id
for p
in copies
.all()]
466 rhv1
= rh_postes_actifs
.exclude(id__in
=id_copies
)
467 rhv1
= rhv1
.select_related(depth
=1)
469 data
= [('', 'Nouveau poste')] + sorted([('dae-%s' % p
.id, label_poste_display(p
)) for p
in dae_ | copies
] + [('rh-%s' % p
.id, label_poste_display(p
)) for p
in rhv1
], key
=lambda t
: t
[1])
470 return HttpResponse(dumps(data
))
473 ################################################################################
474 # AJAX SECURITE non nécessaire
475 ################################################################################
476 def coefficient(request
):
481 method
= request
.method
482 params
= getattr(request
, method
, [])
484 if 'classement' in params
and params
.get('classement') is not u
"":
485 classement
= params
.get('classement')
486 classement
= rh
.Classement
.objects
.get(pk
=classement
)
487 data
['coefficient'] = classement
.coefficient
489 data
['coefficient'] = 0
490 return HttpResponse(dumps(data
))
496 output : devise, devise_code, taux_euro
498 method
= request
.method
499 params
= getattr(request
, method
, [])
501 if 'valeur_point' in params
and params
.get('valeur_point') is not u
"":
502 valeur_point
= params
.get('valeur_point')
503 valeur_point
= rh
.ValeurPoint
.objects
.get(pk
=valeur_point
)
504 annee
= valeur_point
.annee
505 implantation
= valeur_point
.implantation
506 taux
= rh
.TauxChange
.objects
.get(annee
=annee
,
507 implantation
=implantation
)
508 data
['devise'] = taux
.devise
.id
509 data
['valeur'] = valeur_point
.valeur
510 data
['devise_code'] = taux
.devise
.code
511 data
['taux_euro'] = taux
.taux
513 return HttpResponseGone("Vous devez choisir une valeur de point")
514 return HttpResponse(dumps(data
))
516 def devise_code(request
):
519 output : devise_code, taux_euro
521 method
= request
.method
522 params
= getattr(request
, method
, [])
524 if 'devise' in params
:
525 devise
= params
.get('devise')
526 devise
= rh
.Devise
.objects
.get(pk
=devise
)
527 annee
= date
.today().year
528 taux
= rh
.TauxChange
.objects
.filter(annee
=annee
, devise
=devise
)
530 return HttpResponseGone("Le taux n'est pas disponible")
531 data
['devise_code'] = devise
.code
532 data
['taux_euro'] = taux
[0].taux
533 return HttpResponse(dumps(data
))
535 def add_remun(request
, dossier
, type_remun
):
536 dossier
= get_object_or_404(dae
.Dossier
, pk
=dossier
)
537 type_remun
= get_object_or_404(rh
.TypeRemuneration
, pk
=type_remun
)
538 dae
.Remuneration(dossier
=dossier
, devise
=dossier
.devise
,
539 type=type_remun
).save()
541 return render_to_response('dae/embauche-remun.html', dict(dossier
=dossier
),
542 RequestContext(request
))
544 def salaire(request
, implantation
, devise
, classement
):
545 if not devise
or not classement
:
548 taux_impl
= rh
.TauxChange
.objects
.filter(implantation
=implantation
) \
550 taux
= rh
.TauxChange
.objects
.filter(devise
=devise
).order_by('-annee')
551 vp
= rh
.ValeurPoint
.objects
.filter(implantation
=implantation
) \
553 if vp
.count() * taux
.count() * taux_impl
.count() == 0:
556 classement
= get_object_or_404(rh
.Classement
, pk
=classement
)
557 taux
, taux_impl
, vp
= taux
[0].taux
, taux_impl
[0].taux
, vp
[0].valeur
559 salaire_euro
= round(vp
* classement
.coefficient
* taux_impl
, 2)
560 data
= dict(salaire_euro
=salaire_euro
, taux
=taux
,
561 salaire_devise
=round(salaire_euro
/ taux
, 2))
563 return HttpResponse(dumps(data
))
565 def liste_valeurs_point(request
):
567 input : implantation_id
568 output : JSON liste de valeur point
570 method
= request
.method
571 params
= getattr(request
, method
, [])
573 annee_courante
= datetime
.datetime
.now().year
574 if 'implantation_id' in params
and params
.get('implantation_id') is not u
"":
575 implantation_id
= params
.get('implantation_id')
576 objects
= rh
.ValeurPoint
.objects
.filter(implantation
=implantation_id
, annee__in
=(annee_courante
-1, annee_courante
)).order_by("-annee")
578 objects
= rh
.ValeurPoint
.objects
.filter(annee__in
=(annee_courante
-1, annee_courante
)).order_by("-annee")
580 data
.append({'id' : o
.id, 'label' : o
.__unicode__(), })
581 return HttpResponse(dumps(data
))