1 # -*- encoding: utf-8 -*-
6 from collections
import defaultdict
7 from datetime
import date
8 from simplejson
import dumps
11 from django
.core
.urlresolvers
import reverse
12 from django
.http
import Http404
, HttpResponse
, HttpResponseGone
13 from django
.shortcuts
import redirect
, render_to_response
, get_object_or_404
14 from django
.template
import Context
, RequestContext
15 from django
.template
.loader
import get_template
16 from django
.contrib
import messages
17 from django
.conf
import settings
19 from reversion
.models
import Version
21 from project
.dae
import models
as dae
22 from project
.rh_v1
import models
as rh
24 from decorators
import dae_groupe_requis
, \
25 poste_dans_ma_region_ou_service
, \
26 dossier_dans_ma_region_ou_service
, \
27 vieux_dossier_dans_ma_region_ou_service
, \
28 employe_dans_ma_region_ou_service
, \
29 dossier_est_modifiable
, \
35 for d
in rh
.Devise
.objects
.all():
36 annee
= date
.today().year
37 taux
= rh
.TauxChange
.objects
.filter(annee
=annee
, devise
=d
)
42 data
['taux_euro'] = taux
[0].taux
43 data
['devise_code'] = d
.code
47 def reponse_pdf(template_src
, context_dict
):
49 Générer une réponse HTTP avec un PDF
51 import ho
.pisa
as pisa
54 for f
in ('css/pdf.css', 'css/dae.css'):
55 css_file
= os
.path
.join(settings
.MEDIA_ROOT
, f
)
56 css
+= open(css_file
, 'r').read()
57 context_dict
['css'] = css
59 template
= get_template(template_src
)
60 context
= Context(context_dict
)
61 html
= template
.render(context
)
62 result
= StringIO
.StringIO()
63 pdf
= pisa
.pisaDocument(html
, result
, encoding
='UTF-8')
65 return HttpResponse(result
.getvalue(), mimetype
='application/pdf')
66 return HttpResponse("impossible de générer le pdf! %s" % html
)
71 return render_to_response('dae/index.html', {}, RequestContext(request
))
74 @poste_dans_ma_region_ou_service
75 def poste_consulter(request
, key
):
76 source
, id = key
.split('-')
77 poste
= get_object_or_404(dae
.Poste
, pk
=id)
80 validationForm
= PosteWorkflowForm(request
.POST
, instance
=poste
, request
=request
)
81 if validationForm
.is_valid():
83 messages
.add_message(request
, messages
.SUCCESS
, "La validation a été enregistrée.")
84 return redirect('poste_consulter', key
=key
)
86 validationForm
= PosteWorkflowForm(instance
=poste
, request
=request
)
88 vars = {'poste' : poste
, 'validationForm' : validationForm
, }
91 mode
= request
.GET
.get('mode', None)
93 return render_to_response('dae/poste_consulter.html', vars, RequestContext(request
))
95 return reponse_pdf('dae/poste_pdf.html', vars)
97 return render_to_response('dae/poste_pdf.html', vars, RequestContext(request
))
101 @poste_dans_ma_region_ou_service
102 @poste_est_modifiable
103 def poste(request
, key
=None):
104 """ Formulaire pour un poste.
106 Permet de créer ou modifier un poste. Si le poste n'existe que dans rh_v1
107 il est automatiquement copié dans dae.
110 poste
, data
, vars = None, dict(), dict()
115 source
, id = key
.split('-')
118 poste
= get_object_or_404(dae
.Poste
, pk
=id)
120 p
= get_object_or_404(rh
.Poste
, pk
=id)
121 # Initialisation avec les valeurs du poste de rh_v1
122 poste
= dae
.Poste(id_rh
=p
, nom
=p
.type_poste
.nom
)
123 for field
in ('implantation', 'type_poste', 'actif'):
124 setattr(poste
, field
, getattr(p
, field
))
130 data
.update(dict(request
.POST
.items()))
131 form
= PosteForm(data
, instance
=poste
, request
=request
)
132 financementForm
= FinancementForm(request
.POST
, instance
=poste
)
133 piecesForm
= PostePieceForm(request
.POST
, request
.FILES
, instance
=poste
)
134 if form
.is_valid() and piecesForm
.is_valid() and financementForm
.is_valid():
136 piecesForm
.instance
= poste
138 financementForm
.instance
= poste
139 financementForm
.save()
140 messages
.add_message(request
, messages
.SUCCESS
, "Le poste %s a été sauvegardé." % poste
)
141 if request
.POST
.has_key('save'):
142 return redirect('poste_consulter', key
='dae-%s' % poste
.id)
144 return redirect('poste', key
='dae-%s' % poste
.id)
147 messages
.add_message(request
, messages
.ERROR
, 'Il y a des erreurs dans le formulaire.')
150 # 'initial' évite la validation prémature lors d'une copie de poste de
152 form
= PosteForm(initial
=data
, instance
=poste
, request
=request
)
153 piecesForm
= PostePieceForm(instance
=poste
)
154 financementForm
= FinancementForm(instance
=poste
)
156 vars.update(dict(form
=form
, poste
=poste
, poste_key
=key
, piecesForm
=piecesForm
, financementForm
=financementForm
))
158 return render_to_response('dae/poste.html', vars, RequestContext(request
))
161 def postes_liste(request
):
162 """ Liste des postes. """
164 vars['postes_a_traiter'] = dae
.Poste
.objects
.mes_choses_a_faire(request
.user
).filter(pourvu
=False).order_by('-date_creation')
165 vars['postes_vacants'] = dae
.Poste
.objects
.ma_region_ou_service(request
.user
).filter(pourvu
=False).order_by('-date_creation')
166 vars['postes_pourvus'] = dae
.Poste
.objects
.ma_region_ou_service(request
.user
).filter(pourvu
=True).order_by('-date_creation')
167 return render_to_response('dae/postes_liste.html', vars, RequestContext(request
))
169 def filtered_type_remun():
170 defaut
= (2, 3, 8, 17) # salaire de base, indemnité de fonction, charges patronales
171 return rh
.TypeRemuneration
.objects
.filter(pk__in
=defaut
)
174 @dossier_dans_ma_region_ou_service
175 def embauche_consulter(request
, dossier_id
):
176 dossier
= get_object_or_404(dae
.Dossier
, pk
=dossier_id
)
179 validationForm
= DossierWorkflowForm(request
.POST
, instance
=dossier
, request
=request
)
180 if validationForm
.is_valid():
181 validationForm
.save()
182 messages
.add_message(request
, messages
.SUCCESS
, "La validation a été enregistrée.")
183 return redirect('embauche_consulter', dossier_id
=dossier
.id)
185 validationForm
= DossierWorkflowForm(instance
=dossier
, request
=request
)
189 'validationForm' : validationForm
,
192 mode
= request
.GET
.get('mode', None)
194 return render_to_response('dae/embauche_consulter.html', vars, RequestContext(request
))
196 return reponse_pdf('dae/embauche_pdf.html', vars)
198 return render_to_response('dae/embauche_pdf.html', vars, RequestContext(request
))
201 @dossier_dans_ma_region_ou_service
202 @dossier_est_modifiable
203 def embauche(request
, key
=None, dossier_id
=None):
204 """ Formulaire d'autorisation d'embauche. """
206 vars = dict(step
='poste', form
=ChoosePosteForm(request
=request
))
208 type_remun
= filtered_type_remun()
209 vars = dict(type_remun
=type_remun
)
210 source
, id = key
.split('-')
213 poste
= get_object_or_404(dae
.Poste
, pk
=id)
218 if request
.POST
['employe'] == '':
220 employe
= dae
.Employe()
222 employe_source
, id = request
.POST
['employe'].split('-')
223 if employe_source
== 'dae':
225 employe
= get_object_or_404(dae
.Employe
, pk
=id)
226 elif employe_source
== 'rh':
227 # Employé RH, on le copie dans DAE
228 e
= get_object_or_404(rh
.Employe
, pk
=id)
229 employe
= dae
.Employe(id_rh
=e
, prenom
=e
.prenom
, nom
=e
.nom
,
234 employe_form
= EmployeForm(request
.POST
, instance
=employe
, request
=request
)
237 if employe_form
.is_valid():
238 data
= dict(request
.POST
.items())
239 #with warnings.catch_warnings():
240 # warnings.simplefilter('ignore')
241 employe
= employe_form
.save()
242 data
['employe'] = 'dae-%s' % employe
.id
243 employe_form
= EmployeForm(data
, instance
=employe
, request
=request
)
246 dossier
= dae
.Dossier(poste
=poste
, employe
=employe
)
248 dossier
= get_object_or_404(dae
.Dossier
, pk
=dossier_id
)
249 dossier_form
= DossierForm(request
.POST
, instance
=dossier
)
250 piecesForm
= DossierPieceForm(request
.POST
, request
.FILES
, instance
=dossier
)
251 dossiersComparaisonsForm
= DossierComparaisonForm(request
.POST
, instance
=dossier
)
252 remunForm
= RemunForm(request
.POST
, instance
=dossier
)
253 if dossier_form
.is_valid() and \
254 piecesForm
.is_valid() and \
255 dossiersComparaisonsForm
.is_valid() and \
256 remunForm
.is_valid():
258 dossier
= dossier_form
.save()
259 piecesForm
.instance
= dossier
261 dossiersComparaisonsForm
.instance
= dossier
262 dossiersComparaisonsForm
.save()
263 remunForm
.instance
= dossier
266 #if not dossier.remuneration_set.all():
267 # # Pré-peuplement des entrées de la section "coût
268 # # global", à l'exclusion de "Indemnité de fonction"
269 # for type in type_remun.all():
270 # dae.Remuneration(dossier=dossier, type=type,
271 # devise=dossier.devise).save()
274 # # Sauvegarde du coût global
275 # cg_lines = defaultdict(dict)
276 # for k, v in request.POST.items():
277 # if k.startswith('cg-'):
278 # prefix, field_name, cg_id = k.split('-')
279 # cg_lines[int(cg_id)][unicode(field_name)] = v
281 # for r in dossier.remuneration_set.all():
282 # print 'trying %r' % r
283 # if r.id in cg_lines:
284 # if cg_lines[r.id]['montant'] == '':
287 # for k, v in cg_lines[r.id].items():
291 messages
.add_message(request
, messages
.SUCCESS
, "Le dossier %s a été sauvegardé." % dossier
)
292 if request
.POST
.has_key('save'):
293 return redirect('embauche_consulter', dossier_id
=dossier
.id)
295 return redirect('embauche', key
=dossier
.poste
.key
, dossier_id
=dossier
.id)
298 messages
.add_message(request
, messages
.ERROR
, 'Il y a des erreurs dans le formulaire.')
301 dossier_form
= DossierForm(instance
=dossier
)
302 piecesForm
= DossierPieceForm(instance
=dossier
)
303 dossiersComparaisonsForm
= DossierComparaisonForm(instance
=dossier
)
304 remunForm
= RemunForm(instance
=dossier
)
306 # Initialisation d'un formulaire vide
307 dossier_rh
= rh
.Dossier()
308 poste_rh
= poste
.id_rh
310 dossier
= get_object_or_404(dae
.Dossier
, pk
=dossier_id
)
311 employe
= dossier
.employe
312 data
= dict(employe
='dae-%s' % employe
.id)
313 employe_form
= EmployeForm(initial
=data
, instance
=employe
, request
=request
)
315 dossier
= pre_filled_dossier(dossier_rh
, 'new', poste_rh
)
316 employe_form
= EmployeForm(request
=request
)
318 dossier_form
= DossierForm(instance
=dossier
)
319 piecesForm
= DossierPieceForm(instance
=dossier
)
320 dossiersComparaisonsForm
= DossierComparaisonForm(instance
=dossier
)
321 remunForm
= RemunForm(instance
=dossier
)
323 vars = dict(step
='employe',
324 type_remun
=type_remun
,
328 piecesForm
=piecesForm
,
330 dossiersComparaisonsForm
=dossiersComparaisonsForm
,
331 forms
=dict(employe
=employe_form
, dossier
=dossier_form
, )
335 return render_to_response('dae/embauche.html', vars,
336 RequestContext(request
))
338 @dossier_dans_ma_region_ou_service
339 def embauches_liste(request
):
340 """ Liste des embauches. """
342 vars['embauches_a_traiter'] = dae
.Dossier
.objects
.ma_region_ou_service(request
.user
).filter(poste__pourvu
=False).order_by('-date_creation')
343 vars['embauches_en_cours'] = dae
.Dossier
.objects
.ma_region_ou_service(request
.user
).filter(poste__pourvu
=False).order_by('-date_creation')
344 vars['embauches_non_retenues'] = dae
.Dossier
.objects
.ma_region_ou_service(request
.user
).filter(poste__pourvu
=True).order_by('-date_creation')
345 return render_to_response('dae/embauches_liste.html', vars, RequestContext(request
))
347 def employe(request
, key
):
348 """ Récupération AJAX de l'employé pour la page d'embauche. """
349 data
= dict(employe
=key
)
353 employe
= dae
.Employe()
356 source
, id = key
.split('-')
359 employe
= get_object_or_404(dae
.Employe
, pk
=id)
361 e
= get_object_or_404(rh
.Employe
, id=id)
362 # Initialisation avec les valeurs de l'employé de rh_v1
363 employe
= dae
.Employe(id_rh
=e
)
364 for field
in ('prenom', 'nom', 'genre'):
365 setattr(employe
, field
, getattr(e
, field
))
367 return HttpResponse(EmployeForm(initial
=data
, instance
=employe
, request
=request
).as_table())
369 ################################################################################
371 ################################################################################
373 @employe_dans_ma_region_ou_service
374 def dossier(request
, poste_key
, employe_key
):
375 """ Récupération AJAX du dossier pour la page d'embauche. """
378 poste_source
, poste_id
= poste_key
.split('-')
379 poste
= get_object_or_404(dae
.Poste
, pk
=poste_id
)
381 # Récupérer la devise de l'implantation lié au poste
382 implantation_devise
= poste
.get_default_devise()
383 data
.update({'devise' : implantation_devise
.id})
385 if poste
.id_rh_id
is not None:
386 poste_rh
= get_object_or_404(rh
.Poste
, pk
=poste
.id_rh_id
)
390 ##########################################################################################
392 ##########################################################################################
393 if employe_key
== '':
394 employe_source
= 'new'
396 dossier_rh
= rh
.Dossier()
397 dossier
= pre_filled_dossier(dossier_rh
, employe_source
, poste_rh
)
399 ##########################################################################################
401 ##########################################################################################
402 if employe_key
.startswith('dae'):
403 employe_source
, employe_id
= employe_key
.split('-')
404 employe_dae
= get_object_or_404(dae
.Employe
, pk
=employe_id
)
406 # récupération de l'ancien dossier rh v1 pour l'employe DAE
408 dossier_rh
= rh
.Dossier
.objects
.get(employe
=employe_dae
.id_rh_id
, mandat_date_fin
=None)
409 except (rh
.Dossier
.DoesNotExist
):
410 dossier_rh
= rh
.Dossier()
412 # on tente de récupérer le dossier DAE, au pire on le contruit en le
413 # prépoluant avec son dossier rh v1.
415 dossier
= dae
.Dossier
.objects
.get(employe
=employe_dae
, poste
=poste
)
416 except (dae
.Dossier
.DoesNotExist
):
417 dossier
= pre_filled_dossier(dossier_rh
, employe_source
, poste_rh
)
418 employe
= employe_dae
.id_rh
419 ##########################################################################################
421 ##########################################################################################
422 if employe_key
.startswith('rh'):
423 employe_source
, employe_id
= employe_key
.split('-')
424 employe_rh
= get_object_or_404(rh
.Employe
, pk
=employe_id
)
426 # récupération de l'ancien dossier rh v1 pour l'employe rh v1, s'il n'en a pas,
427 # on en fournit un nouveau qui servira uniquement un créer un nouveau dossier DAE.
429 dossier_rh
= rh
.Dossier
.objects
.get(employe
=employe_rh
, mandat_date_fin
=None)
430 except (rh
.Dossier
.DoesNotExist
):
431 dossier_rh
= rh
.Dossier()
432 dossier
= pre_filled_dossier(dossier_rh
, employe_source
, poste_rh
)
435 dossier_form
= DossierForm(initial
=data
, instance
=dossier
)
436 vars = dict(form
=dossier_form
, poste
=poste
, employe
=employe
)
437 return render_to_response('dae/embauche-dossier.html', vars,
438 RequestContext(request
))
440 # @Cette fonction est appelée à partir de fonctions déjà sécurisée
441 def pre_filled_dossier(dossier_rh
, employe_source
, poste_rh
):
442 dossier
= dae
.Dossier()
444 if employe_source
!= 'new' and dossier_rh
.id:
445 dossier
.statut_anterieur
= dossier_rh
.statut
447 # Certains dossiers ont un classement à zéro
448 if dossier_rh
.classement_id
> 0:
449 dossier
.classement_anterieur
= dossier_rh
.classement
451 # Récupération du salaire de base
452 remun
= dossier_rh
.remuneration_set
.filter(type=1)
454 dossier
.salaire_anterieur
= remun
[0].montant
456 # Récupération du titulaire précédent
458 dossiers
= rh
.Dossier
.objects
.order_by('-mandat_date_fin')
459 dossiers
= dossiers
.filter(poste1
=poste_rh
) | dossiers
.filter(poste2
=poste_rh
)
461 # Ce bloc ignore toutes les erreurs, car les données de rh
462 # manquantes peuvent en générer
465 titulaire
= d
.employe
466 dossier
.employe_anterieur
= titulaire
467 dossier
.classement_titulaire_anterieur
= d
.classement
468 dossier
.statut_titulaire_anterieur
= d
.statut
469 dossier
.salaire_titulaire_anterieur
= \
470 d
.remuneration_set
.all()[0].montant
473 # TODO: afficher l'info, les champs ne sont pas dans le
474 # modèle dae.Dossier: nom, prenom, classement, salaire
477 except (rh
.Dossier
.DoesNotExist
):
478 dossier_rh
= rh
.Dossier()
483 @vieux_dossier_dans_ma_region_ou_service
484 def dossier_resume(request
, dossier_id
=None):
487 output : devise, devise_code, taux_euro
490 dossier
= rh
.Dossier
.objects
.get(id=dossier_id
)
492 return HttpResponseGone("Ce dossier n'est pas accessible")
495 data
['personne'] = unicode(dossier
.employe
)
496 data
['implantation'] = dossier
.implantation1
.id
497 data
['poste'] = u
"%s %s" % (dossier
.poste1
.type_poste
.nom
, dossier
.complement1
)
498 data
['montant'] = dossier
.get_salaire()
499 salaire
= dossier
.get_dernier_salaire_remun()
500 if salaire
is not None:
501 data
['devise'] = salaire
.devise
.id
502 data
['montant_euros'] = salaire
.en_euros()
504 data
['devise'] = None
505 data
['montant_euros'] = 0
506 return HttpResponse(dumps(data
))
508 def liste_postes(request
):
510 input : implantation_id
511 output : JSON liste de valeur point
513 method
= request
.method
514 params
= getattr(request
, method
, [])
517 # Voir le code de _poste_choices dans forms.py
518 dae_
= dae
.Poste
.objects
.filter(actif
=True, id_rh__isnull
=True)
519 copies
= dae
.Poste
.objects
.exclude(id_rh__isnull
=True)
520 rh_postes_actifs
= rh
.Poste
.objects
.filter(actif
=True)
522 if 'implantation_id' in params
and params
.get('implantation_id') is not u
"":
523 implantation_id
= params
.get('implantation_id')
524 dae_
= dae_
.filter(implantation__id
=implantation_id
)
525 copies
= copies
.filter(implantation__id
=implantation_id
)
526 rh_postes_actifs
= rh_postes_actifs
.filter(implantation__id
=implantation_id
)
528 id_copies
= [p
.id_rh_id
for p
in copies
.all()]
529 rhv1
= rh_postes_actifs
.exclude(id__in
=id_copies
)
530 rhv1
= rhv1
.select_related(depth
=1)
532 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])
533 return HttpResponse(dumps(data
))
536 ################################################################################
537 # AJAX SECURITE non nécessaire
538 ################################################################################
539 def coefficient(request
):
544 method
= request
.method
545 params
= getattr(request
, method
, [])
547 if 'classement' in params
and params
.get('classement') is not u
"":
548 classement
= params
.get('classement')
549 classement
= rh
.Classement
.objects
.get(pk
=classement
)
550 data
['coefficient'] = classement
.coefficient
552 data
['coefficient'] = 0
553 return HttpResponse(dumps(data
))
559 output : devise, devise_code, taux_euro
561 method
= request
.method
562 params
= getattr(request
, method
, [])
564 if 'valeur_point' in params
and params
.get('valeur_point') is not u
"":
565 valeur_point
= params
.get('valeur_point')
566 valeur_point
= rh
.ValeurPoint
.objects
.get(pk
=valeur_point
)
567 annee
= valeur_point
.annee
568 implantation
= valeur_point
.implantation
569 taux
= rh
.TauxChange
.objects
.get(annee
=annee
,
570 implantation
=implantation
)
571 data
['devise'] = taux
.devise
.id
572 data
['valeur'] = valeur_point
.valeur
573 data
['devise_code'] = taux
.devise
.code
574 data
['taux_euro'] = taux
.taux
576 return HttpResponseGone("Vous devez choisir une valeur de point")
577 return HttpResponse(dumps(data
))
579 def devise_code(request
):
582 output : devise_code, taux_euro
584 method
= request
.method
585 params
= getattr(request
, method
, [])
587 if 'devise' in params
:
588 devise
= params
.get('devise')
589 devise
= rh
.Devise
.objects
.get(pk
=devise
)
590 annee
= date
.today().year
591 taux
= rh
.TauxChange
.objects
.filter(annee
=annee
, devise
=devise
)
593 return HttpResponseGone("Le taux n'est pas disponible")
594 data
['devise_code'] = devise
.code
595 data
['taux_euro'] = taux
[0].taux
596 return HttpResponse(dumps(data
))
598 def add_remun(request
, dossier
, type_remun
):
599 dossier
= get_object_or_404(dae
.Dossier
, pk
=dossier
)
600 type_remun
= get_object_or_404(rh
.TypeRemuneration
, pk
=type_remun
)
601 dae
.Remuneration(dossier
=dossier
, devise
=dossier
.devise
,
602 type=type_remun
).save()
604 return render_to_response('dae/embauche-remun.html', dict(dossier
=dossier
),
605 RequestContext(request
))
607 def salaire(request
, implantation
, devise
, classement
):
608 if not devise
or not classement
:
611 taux_impl
= rh
.TauxChange
.objects
.filter(implantation
=implantation
) \
613 taux
= rh
.TauxChange
.objects
.filter(devise
=devise
).order_by('-annee')
614 vp
= rh
.ValeurPoint
.objects
.filter(implantation
=implantation
) \
616 if vp
.count() * taux
.count() * taux_impl
.count() == 0:
619 classement
= get_object_or_404(rh
.Classement
, pk
=classement
)
620 taux
, taux_impl
, vp
= taux
[0].taux
, taux_impl
[0].taux
, vp
[0].valeur
622 salaire_euro
= round(vp
* classement
.coefficient
* taux_impl
, 2)
623 data
= dict(salaire_euro
=salaire_euro
, taux
=taux
,
624 salaire_devise
=round(salaire_euro
/ taux
, 2))
626 return HttpResponse(dumps(data
))
628 def liste_valeurs_point(request
):
630 input : implantation_id
631 output : JSON liste de valeur point
633 method
= request
.method
634 params
= getattr(request
, method
, [])
636 annee_courante
= datetime
.datetime
.now().year
637 if 'implantation_id' in params
and params
.get('implantation_id') is not u
"":
638 implantation_id
= params
.get('implantation_id')
639 objects
= rh
.ValeurPoint
.objects
.filter(implantation
=implantation_id
, annee__in
=(annee_courante
-1, annee_courante
)).order_by("-annee")
641 objects
= rh
.ValeurPoint
.objects
.filter(annee__in
=(annee_courante
-1, annee_courante
)).order_by("-annee")
643 data
.append({'id' : o
.id, 'label' : o
.__unicode__(), })
644 return HttpResponse(dumps(data
))