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'] = dae
.Poste
.objects
.ma_region_ou_service(request
.user
).order_by('-date_creation')
165 return render_to_response('dae/postes_liste.html', vars, RequestContext(request
))
167 def filtered_type_remun():
168 defaut
= (2, 3, 8, 17) # salaire de base, indemnité de fonction, charges patronales
169 return rh
.TypeRemuneration
.objects
.filter(pk__in
=defaut
)
172 @dossier_dans_ma_region_ou_service
173 def embauche_consulter(request
, dossier_id
):
174 dossier
= get_object_or_404(dae
.Dossier
, pk
=dossier_id
)
177 validationForm
= DossierWorkflowForm(request
.POST
, instance
=dossier
, request
=request
)
178 if validationForm
.is_valid():
179 validationForm
.save()
180 messages
.add_message(request
, messages
.SUCCESS
, "La validation a été enregistrée.")
181 return redirect('embauche_consulter', dossier_id
=dossier
.id)
183 validationForm
= DossierWorkflowForm(instance
=dossier
, request
=request
)
187 'validationForm' : validationForm
,
190 mode
= request
.GET
.get('mode', None)
192 return render_to_response('dae/embauche_consulter.html', vars, RequestContext(request
))
194 return reponse_pdf('dae/embauche_pdf.html', vars)
196 return render_to_response('dae/embauche_pdf.html', vars, RequestContext(request
))
199 @dossier_dans_ma_region_ou_service
200 @dossier_est_modifiable
201 def embauche(request
, key
=None, dossier_id
=None):
202 """ Formulaire d'autorisation d'embauche. """
204 vars = dict(step
='poste', form
=ChoosePosteForm(request
=request
))
206 type_remun
= filtered_type_remun()
207 vars = dict(type_remun
=type_remun
)
208 source
, id = key
.split('-')
211 poste
= get_object_or_404(dae
.Poste
, pk
=id)
216 if request
.POST
['employe'] == '':
218 employe
= dae
.Employe()
220 employe_source
, id = request
.POST
['employe'].split('-')
221 if employe_source
== 'dae':
223 employe
= get_object_or_404(dae
.Employe
, pk
=id)
224 elif employe_source
== 'rh':
225 # Employé RH, on le copie dans DAE
226 e
= get_object_or_404(rh
.Employe
, pk
=id)
227 employe
= dae
.Employe(id_rh
=e
, prenom
=e
.prenom
, nom
=e
.nom
,
232 employe_form
= EmployeForm(request
.POST
, instance
=employe
, request
=request
)
235 if employe_form
.is_valid():
236 data
= dict(request
.POST
.items())
237 #with warnings.catch_warnings():
238 # warnings.simplefilter('ignore')
239 employe
= employe_form
.save()
240 data
['employe'] = 'dae-%s' % employe
.id
241 employe_form
= EmployeForm(data
, instance
=employe
, request
=request
)
244 dossier
= dae
.Dossier(poste
=poste
, employe
=employe
)
246 dossier
= get_object_or_404(dae
.Dossier
, pk
=dossier_id
)
247 dossier_form
= DossierForm(request
.POST
, instance
=dossier
)
248 piecesForm
= DossierPieceForm(request
.POST
, request
.FILES
, instance
=dossier
)
249 justificationsNouveauForm
= JustificationNouvelEmployeForm(request
.POST
, instance
=dossier
)
250 justificationsAutreForm
= JustificationAutreEmployeForm(request
.POST
, instance
=dossier
)
251 dossiersComparaisonsForm
= DossierComparaisonForm(request
.POST
, instance
=dossier
)
252 remunForm
= RemunForm(request
.POST
, instance
=dossier
)
253 print remunForm
.errors
254 if dossier_form
.is_valid() and \
255 piecesForm
.is_valid() and \
256 justificationsNouveauForm
.is_valid() and \
257 justificationsAutreForm
.is_valid() and \
258 dossiersComparaisonsForm
.is_valid() and \
259 remunForm
.is_valid():
261 dossier
= dossier_form
.save()
262 piecesForm
.instance
= dossier
264 justificationsNouveauForm
.instance
= dossier
265 justificationsNouveauForm
.save()
266 justificationsAutreForm
.instance
= dossier
267 justificationsAutreForm
.save()
268 dossiersComparaisonsForm
.instance
= dossier
269 dossiersComparaisonsForm
.save()
270 remunForm
.instance
= dossier
273 #if not dossier.remuneration_set.all():
274 # # Pré-peuplement des entrées de la section "coût
275 # # global", à l'exclusion de "Indemnité de fonction"
276 # for type in type_remun.all():
277 # dae.Remuneration(dossier=dossier, type=type,
278 # devise=dossier.devise).save()
281 # # Sauvegarde du coût global
282 # cg_lines = defaultdict(dict)
283 # for k, v in request.POST.items():
284 # if k.startswith('cg-'):
285 # prefix, field_name, cg_id = k.split('-')
286 # cg_lines[int(cg_id)][unicode(field_name)] = v
288 # for r in dossier.remuneration_set.all():
289 # print 'trying %r' % r
290 # if r.id in cg_lines:
291 # if cg_lines[r.id]['montant'] == '':
294 # for k, v in cg_lines[r.id].items():
298 messages
.add_message(request
, messages
.SUCCESS
, "Le dossier %s a été sauvegardé." % dossier
)
299 if request
.POST
.has_key('save'):
300 return redirect('embauche_consulter', dossier_id
=dossier
.id)
302 return redirect('embauche', key
=dossier
.poste
.key
, dossier_id
=dossier
.id)
305 messages
.add_message(request
, messages
.ERROR
, 'Il y a des erreurs dans le formulaire.')
308 dossier_form
= DossierForm(instance
=dossier
)
309 piecesForm
= DossierPieceForm(instance
=dossier
)
310 justificationsNouveauForm
= JustificationNouvelEmployeForm(instance
=dossier
)
311 justificationsAutreForm
= JustificationAutreEmployeForm(instance
=dossier
)
312 dossiersComparaisonsForm
= DossierComparaisonForm(instance
=dossier
)
313 remunForm
= RemunForm(instance
=dossier
)
315 # Initialisation d'un formulaire vide
316 dossier_rh
= rh
.Dossier()
317 poste_rh
= poste
.id_rh
319 dossier
= get_object_or_404(dae
.Dossier
, pk
=dossier_id
)
320 employe
= dossier
.employe
321 data
= dict(employe
='dae-%s' % employe
.id)
322 employe_form
= EmployeForm(initial
=data
, instance
=employe
, request
=request
)
324 dossier
= pre_filled_dossier(dossier_rh
, 'new', poste_rh
)
325 employe_form
= EmployeForm(request
=request
)
327 dossier_form
= DossierForm(instance
=dossier
)
328 piecesForm
= DossierPieceForm(instance
=dossier
)
329 justificationsNouveauForm
= JustificationNouvelEmployeForm(instance
=dossier
)
330 justificationsAutreForm
= JustificationAutreEmployeForm(instance
=dossier
)
331 dossiersComparaisonsForm
= DossierComparaisonForm(instance
=dossier
)
332 remunForm
= RemunForm(instance
=dossier
)
334 vars = dict(step
='employe',
335 type_remun
=type_remun
,
339 piecesForm
=piecesForm
,
341 justificationsNouveauForm
=justificationsNouveauForm
,
342 justificationsAutreForm
=justificationsAutreForm
,
343 dossiersComparaisonsForm
=dossiersComparaisonsForm
,
344 forms
=dict(employe
=employe_form
, dossier
=dossier_form
, )
348 return render_to_response('dae/embauche.html', vars,
349 RequestContext(request
))
351 @dossier_dans_ma_region_ou_service
352 def embauches_liste(request
):
353 """ Liste des embauches. """
355 vars['embauches'] = dae
.Dossier
.objects
.ma_region_ou_service(request
.user
).order_by('-date_creation')
356 return render_to_response('dae/embauches_liste.html', vars, RequestContext(request
))
358 def employe(request
, key
):
359 """ Récupération AJAX de l'employé pour la page d'embauche. """
360 data
= dict(employe
=key
)
364 employe
= dae
.Employe()
367 source
, id = key
.split('-')
370 employe
= get_object_or_404(dae
.Employe
, pk
=id)
372 e
= get_object_or_404(rh
.Employe
, id=id)
373 # Initialisation avec les valeurs de l'employé de rh_v1
374 employe
= dae
.Employe(id_rh
=e
)
375 for field
in ('prenom', 'nom', 'genre'):
376 setattr(employe
, field
, getattr(e
, field
))
378 return HttpResponse(EmployeForm(initial
=data
, instance
=employe
, request
=request
).as_table())
380 ################################################################################
382 ################################################################################
384 @employe_dans_ma_region_ou_service
385 def dossier(request
, poste_key
, employe_key
):
386 """ Récupération AJAX du dossier pour la page d'embauche. """
389 poste_source
, poste_id
= poste_key
.split('-')
390 poste
= get_object_or_404(dae
.Poste
, pk
=poste_id
)
392 # Récupérer la devise de l'implantation lié au poste
393 implantation_devise
= poste
.get_default_devise()
394 data
.update({'devise' : implantation_devise
.id})
396 if poste
.id_rh_id
is not None:
397 poste_rh
= get_object_or_404(rh
.Poste
, pk
=poste
.id_rh_id
)
401 ##########################################################################################
403 ##########################################################################################
404 if employe_key
== '':
405 employe_source
= 'new'
407 dossier_rh
= rh
.Dossier()
408 dossier
= pre_filled_dossier(dossier_rh
, employe_source
, poste_rh
)
410 ##########################################################################################
412 ##########################################################################################
413 if employe_key
.startswith('dae'):
414 employe_source
, employe_id
= employe_key
.split('-')
415 employe_dae
= get_object_or_404(dae
.Employe
, pk
=employe_id
)
417 # récupération de l'ancien dossier rh v1 pour l'employe DAE
419 dossier_rh
= rh
.Dossier
.objects
.get(employe
=employe_dae
.id_rh_id
, mandat_date_fin
=None)
420 except (rh
.Dossier
.DoesNotExist
):
421 dossier_rh
= rh
.Dossier()
423 # on tente de récupérer le dossier DAE, au pire on le contruit en le
424 # prépoluant avec son dossier rh v1.
426 dossier
= dae
.Dossier
.objects
.get(employe
=employe_dae
, poste
=poste
)
427 except (dae
.Dossier
.DoesNotExist
):
428 dossier
= pre_filled_dossier(dossier_rh
, employe_source
, poste_rh
)
429 employe
= employe_dae
.id_rh
430 ##########################################################################################
432 ##########################################################################################
433 if employe_key
.startswith('rh'):
434 employe_source
, employe_id
= employe_key
.split('-')
435 employe_rh
= get_object_or_404(rh
.Employe
, pk
=employe_id
)
437 # récupération de l'ancien dossier rh v1 pour l'employe rh v1, s'il n'en a pas,
438 # on en fournit un nouveau qui servira uniquement un créer un nouveau dossier DAE.
440 dossier_rh
= rh
.Dossier
.objects
.get(employe
=employe_rh
, mandat_date_fin
=None)
441 except (rh
.Dossier
.DoesNotExist
):
442 dossier_rh
= rh
.Dossier()
443 dossier
= pre_filled_dossier(dossier_rh
, employe_source
, poste_rh
)
446 dossier_form
= DossierForm(initial
=data
, instance
=dossier
)
447 vars = dict(form
=dossier_form
, poste
=poste
, employe
=employe
)
448 return render_to_response('dae/embauche-dossier.html', vars,
449 RequestContext(request
))
451 # @Cette fonction est appelée à partir de fonctions déjà sécurisée
452 def pre_filled_dossier(dossier_rh
, employe_source
, poste_rh
):
453 dossier
= dae
.Dossier()
455 if employe_source
!= 'new' and dossier_rh
.id:
456 dossier
.statut_anterieur
= dossier_rh
.statut
458 # Certains dossiers ont un classement à zéro
459 if dossier_rh
.classement_id
> 0:
460 dossier
.classement_anterieur
= dossier_rh
.classement
462 # Récupération du salaire de base
463 remun
= dossier_rh
.remuneration_set
.filter(type=1)
465 dossier
.salaire_anterieur
= remun
[0].montant
467 # Récupération du titulaire précédent
469 dossiers
= rh
.Dossier
.objects
.order_by('-mandat_date_fin')
470 dossiers
= dossiers
.filter(poste1
=poste_rh
) | dossiers
.filter(poste2
=poste_rh
)
472 # Ce bloc ignore toutes les erreurs, car les données de rh
473 # manquantes peuvent en générer
476 titulaire
= d
.employe
477 dossier
.employe_anterieur
= titulaire
478 dossier
.classement_titulaire_anterieur
= d
.classement
479 dossier
.statut_titulaire_anterieur
= d
.statut
480 dossier
.salaire_titulaire_anterieur
= \
481 d
.remuneration_set
.all()[0].montant
484 # TODO: afficher l'info, les champs ne sont pas dans le
485 # modèle dae.Dossier: nom, prenom, classement, salaire
488 except (rh
.Dossier
.DoesNotExist
):
489 dossier_rh
= rh
.Dossier()
494 @vieux_dossier_dans_ma_region_ou_service
495 def dossier_resume(request
, dossier_id
=None):
498 output : devise, devise_code, taux_euro
501 dossier
= rh
.Dossier
.objects
.get(id=dossier_id
)
503 return HttpResponseGone("Ce dossier n'est pas accessible")
506 data
['personne'] = unicode(dossier
.employe
)
507 data
['implantation'] = dossier
.implantation1
.id
508 data
['poste'] = u
"%s %s" % (dossier
.poste1
.type_poste
.nom
, dossier
.complement1
)
509 data
['montant'] = dossier
.get_salaire()
510 salaire
= dossier
.get_dernier_salaire_remun()
511 if salaire
is not None:
512 data
['devise'] = salaire
.devise
.id
513 data
['montant_euros'] = salaire
.en_euros()
515 data
['devise'] = None
516 data
['montant_euros'] = 0
517 return HttpResponse(dumps(data
))
519 def liste_postes(request
):
521 input : implantation_id
522 output : JSON liste de valeur point
524 method
= request
.method
525 params
= getattr(request
, method
, [])
528 # Voir le code de _poste_choices dans forms.py
529 dae_
= dae
.Poste
.objects
.filter(actif
=True, id_rh__isnull
=True)
530 copies
= dae
.Poste
.objects
.exclude(id_rh__isnull
=True)
531 rh_postes_actifs
= rh
.Poste
.objects
.filter(actif
=True)
533 if 'implantation_id' in params
and params
.get('implantation_id') is not u
"":
534 implantation_id
= params
.get('implantation_id')
535 dae_
= dae_
.filter(implantation__id
=implantation_id
)
536 copies
= copies
.filter(implantation__id
=implantation_id
)
537 rh_postes_actifs
= rh_postes_actifs
.filter(implantation__id
=implantation_id
)
539 id_copies
= [p
.id_rh_id
for p
in copies
.all()]
540 rhv1
= rh_postes_actifs
.exclude(id__in
=id_copies
)
541 rhv1
= rhv1
.select_related(depth
=1)
543 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])
544 return HttpResponse(dumps(data
))
547 ################################################################################
548 # AJAX SECURITE non nécessaire
549 ################################################################################
550 def coefficient(request
):
555 method
= request
.method
556 params
= getattr(request
, method
, [])
558 if 'classement' in params
and params
.get('classement') is not u
"":
559 classement
= params
.get('classement')
560 classement
= rh
.Classement
.objects
.get(pk
=classement
)
561 data
['coefficient'] = classement
.coefficient
563 data
['coefficient'] = 0
564 return HttpResponse(dumps(data
))
570 output : devise, devise_code, taux_euro
572 method
= request
.method
573 params
= getattr(request
, method
, [])
575 if 'valeur_point' in params
and params
.get('valeur_point') is not u
"":
576 valeur_point
= params
.get('valeur_point')
577 valeur_point
= rh
.ValeurPoint
.objects
.get(pk
=valeur_point
)
578 annee
= valeur_point
.annee
579 implantation
= valeur_point
.implantation
580 taux
= rh
.TauxChange
.objects
.get(annee
=annee
,
581 implantation
=implantation
)
582 data
['devise'] = taux
.devise
.id
583 data
['valeur'] = valeur_point
.valeur
584 data
['devise_code'] = taux
.devise
.code
585 data
['taux_euro'] = taux
.taux
587 return HttpResponseGone("Vous devez choisir une valeur de point")
588 return HttpResponse(dumps(data
))
590 def devise_code(request
):
593 output : devise_code, taux_euro
595 method
= request
.method
596 params
= getattr(request
, method
, [])
598 if 'devise' in params
:
599 devise
= params
.get('devise')
600 devise
= rh
.Devise
.objects
.get(pk
=devise
)
601 annee
= date
.today().year
602 taux
= rh
.TauxChange
.objects
.filter(annee
=annee
, devise
=devise
)
604 return HttpResponseGone("Le taux n'est pas disponible")
605 data
['devise_code'] = devise
.code
606 data
['taux_euro'] = taux
[0].taux
607 return HttpResponse(dumps(data
))
609 def add_remun(request
, dossier
, type_remun
):
610 dossier
= get_object_or_404(dae
.Dossier
, pk
=dossier
)
611 type_remun
= get_object_or_404(rh
.TypeRemuneration
, pk
=type_remun
)
612 dae
.Remuneration(dossier
=dossier
, devise
=dossier
.devise
,
613 type=type_remun
).save()
615 return render_to_response('dae/embauche-remun.html', dict(dossier
=dossier
),
616 RequestContext(request
))
618 def salaire(request
, implantation
, devise
, classement
):
619 if not devise
or not classement
:
622 taux_impl
= rh
.TauxChange
.objects
.filter(implantation
=implantation
) \
624 taux
= rh
.TauxChange
.objects
.filter(devise
=devise
).order_by('-annee')
625 vp
= rh
.ValeurPoint
.objects
.filter(implantation
=implantation
) \
627 if vp
.count() * taux
.count() * taux_impl
.count() == 0:
630 classement
= get_object_or_404(rh
.Classement
, pk
=classement
)
631 taux
, taux_impl
, vp
= taux
[0].taux
, taux_impl
[0].taux
, vp
[0].valeur
633 salaire_euro
= round(vp
* classement
.coefficient
* taux_impl
, 2)
634 data
= dict(salaire_euro
=salaire_euro
, taux
=taux
,
635 salaire_devise
=round(salaire_euro
/ taux
, 2))
637 return HttpResponse(dumps(data
))
639 def liste_valeurs_point(request
):
641 input : implantation_id
642 output : JSON liste de valeur point
644 method
= request
.method
645 params
= getattr(request
, method
, [])
647 annee_courante
= datetime
.datetime
.now().year
648 if 'implantation_id' in params
and params
.get('implantation_id') is not u
"":
649 implantation_id
= params
.get('implantation_id')
650 objects
= rh
.ValeurPoint
.objects
.filter(implantation
=implantation_id
, annee__in
=(annee_courante
-1, annee_courante
)).order_by("-annee")
652 objects
= rh
.ValeurPoint
.objects
.filter(annee__in
=(annee_courante
-1, annee_courante
)).order_by("-annee")
654 data
.append({'id' : o
.id, 'label' : o
.__unicode__(), })
655 return HttpResponse(dumps(data
))