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 project
.decorators
import admin_required
25 return render_to_response('dae/index.html', {}, RequestContext(request
))
28 def poste_consulter(request
, key
):
29 source
, id = key
.split('-')
30 poste
= get_object_or_404(dae
.Poste
, pk
=id)
33 validationForm
= PosteWorkflowForm(request
.POST
, instance
=poste
, request
=request
)
34 if validationForm
.is_valid():
36 messages
.add_message(request
, messages
.SUCCESS
, "La validation a été enregistrée.")
37 return redirect('poste_consulter', key
=key
)
39 validationForm
= PosteWorkflowForm(instance
=poste
, request
=request
)
41 vars = {'poste' : poste
, 'validationForm' : validationForm
, }
42 return render_to_response('dae/poste_consulter.html', vars, RequestContext(request
))
45 def poste(request
, key
=None):
46 """ Formulaire pour un poste.
48 Permet de créer ou modifier un poste. Si le poste n'existe que dans rh_v1
49 il est automatiquement copié dans dae.
52 poste
, data
, vars = None, dict(), dict()
57 source
, id = key
.split('-')
60 poste
= get_object_or_404(dae
.Poste
, pk
=id)
62 p
= get_object_or_404(rh
.Poste
, pk
=id)
63 # Initialisation avec les valeurs du poste de rh_v1
64 poste
= dae
.Poste(id_rh
=p
, nom
=p
.type_poste
.nom
)
65 for field
in ('implantation', 'type_poste', 'actif'):
66 setattr(poste
, field
, getattr(p
, field
))
72 data
.update(dict(request
.POST
.items()))
73 form
= PosteForm(data
, instance
=poste
)
74 financementForm
= FinancementForm(request
.POST
, instance
=poste
)
75 piecesForm
= PostePieceForm(request
.POST
, request
.FILES
, instance
=poste
)
76 if 'save' in data
and form
.is_valid() and piecesForm
.is_valid() and financementForm
.is_valid():
78 piecesForm
.instance
= poste
80 financementForm
.instance
= poste
81 financementForm
.save()
82 messages
.add_message(request
, messages
.SUCCESS
, "Le poste %s a été sauvegardé." % poste
)
83 return redirect('poste_consulter', key
='dae-%s' % poste
.id)
85 messages
.add_message(request
, messages
.ERROR
, 'Il y a des erreurs dans le formulaire.')
88 # 'initial' évite la validation prémature lors d'une copie de poste de
90 form
= PosteForm(initial
=data
, instance
=poste
)
91 piecesForm
= PostePieceForm(instance
=poste
)
92 financementForm
= FinancementForm(instance
=poste
)
94 vars.update(dict(form
=form
, poste
=poste
, poste_key
=key
, piecesForm
=piecesForm
, financementForm
=financementForm
))
96 return render_to_response('dae/poste.html', vars, RequestContext(request
))
99 def postes_liste(request
):
100 """ Liste des postes. """
102 vars['postes'] = dae
.Poste
.objects
.all().order_by('-date_creation')
103 return render_to_response('dae/postes_liste.html', vars,
104 RequestContext(request
))
106 def filtered_type_remun():
107 # Exclusion de "Indemnité de fonction" des types de rémun utilisés
108 return rh
.TypeRemuneration
.objects
.exclude(pk
=7)
110 def get_dossiers_connexes(poste
):
111 # Chargement des données de comparaison
112 comparaison_dossiers
= []
113 famille
= poste
.type_poste
.famille_emploi
114 # postes DAE (vieux dossiers)
115 postes_region
= dae
.Poste
.objects
.filter(implantation__region
=poste
.implantation
.region
)
116 for p
in postes_region
:
117 dossiers
= p
.get_dossiers()
118 if len(dossiers
) > 0 and dossiers
[0].poste1
.type_poste
.famille_emploi
== famille
:
119 comparaison_dossiers
.append(dossiers
[0])
120 # poste RHv1 (vieux dossiers)
121 postes_region
= rh
.Poste
.objects
.filter(implantation__region
=poste
.implantation
.region
)
122 for p
in postes_region
:
123 dossiers
= p
.poste1
.all().order_by('rh_v1_dossier.date_creation') # through key incohérente... (dossiers)
124 if len(dossiers
) > 0 and dossiers
[0].poste1
.type_poste
.famille_emploi
== famille
:
125 comparaison_dossiers
.append(dossiers
[0])
126 return comparaison_dossiers
130 def embauche_consulter(request
, dossier_id
):
131 dossier
= get_object_or_404(dae
.Dossier
, pk
=dossier_id
)
134 validationForm
= DossierWorkflowForm(request
.POST
, instance
=dossier
, request
=request
)
135 if validationForm
.is_valid():
136 validationForm
.save()
137 messages
.add_message(request
, messages
.SUCCESS
, "La validation a été enregistrée.")
138 return redirect('embauche_consulter', dossier_id
=dossier
.id)
140 validationForm
= DossierWorkflowForm(instance
=dossier
, request
=request
)
144 'comparaison_dossiers' : get_dossiers_connexes(dossier
.poste
),
145 'validationForm' : validationForm
,
147 return render_to_response('dae/embauche_consulter.html', vars, RequestContext(request
))
150 def embauche(request
, key
=None, dossier
=None):
151 """ Formulaire d'autorisation d'embauche. """
153 vars = dict(step
='poste', form
=ChoosePosteForm())
155 type_remun
= filtered_type_remun()
156 vars = dict(type_remun
=type_remun
)
157 source
, id = key
.split('-')
160 poste
= get_object_or_404(dae
.Poste
, pk
=id)
165 if request
.POST
['employe'] == '':
167 employe
= dae
.Employe()
169 employe_source
, id = request
.POST
['employe'].split('-')
170 if employe_source
== 'dae':
172 employe
= get_object_or_404(dae
.Employe
, pk
=id)
173 elif employe_source
== 'rh':
174 # Employé RH, on le copie dans DAE
175 e
= get_object_or_404(rh
.Employe
, pk
=id)
176 employe
= dae
.Employe(id_rh
=e
, prenom
=e
.prenom
, nom
=e
.nom
,
181 employe_form
= EmployeForm(request
.POST
, instance
=employe
)
183 if 'save' in request
.POST
:
184 if employe_form
.is_valid():
185 data
= dict(request
.POST
.items())
186 #with warnings.catch_warnings():
187 # warnings.simplefilter('ignore')
188 employe
= employe_form
.save()
189 data
['employe'] = 'dae-%s' % employe
.id
190 employe_form
= EmployeForm(data
, instance
=employe
)
193 dossier
= dae
.Dossier(poste
=poste
, employe
=employe
)
195 dossier
= get_object_or_404(dae
.Dossier
, pk
=dossier
)
196 dossier_form
= DossierForm(request
.POST
, instance
=dossier
)
197 piecesForm
= DossierPieceForm(request
.POST
, request
.FILES
, instance
=dossier
)
198 justificationsNouveauForm
= JustificationNouvelEmployeForm(request
.POST
, instance
=dossier
)
199 justificationsAutreForm
= JustificationAutreEmployeForm(request
.POST
, instance
=dossier
)
201 if dossier_form
.is_valid() and piecesForm
.is_valid() and justificationsNouveauForm
.is_valid() and justificationsAutreForm
.is_valid():
202 dossier
= dossier_form
.save()
203 piecesForm
.instance
= dossier
205 justificationsNouveauForm
.instance
= dossier
206 justificationsNouveauForm
.save()
207 justificationsAutreForm
.instance
= dossier
208 justificationsAutreForm
.save()
209 if not dossier
.remuneration_set
.all():
210 # Pré-peuplement des entrées de la section "coût
211 # global", à l'exclusion de "Indemnité de fonction"
212 for type in type_remun
.all():
213 dae
.Remuneration(dossier
=dossier
, type=type,
214 devise
=dossier
.devise
).save()
217 # Sauvegarde du coût global
218 cg_lines
= defaultdict(dict)
219 for k
, v
in request
.POST
.items():
220 if k
.startswith('cg-'):
221 prefix
, field_name
, cg_id
= k
.split('-')
222 cg_lines
[int(cg_id
)][unicode(field_name
)] = v
224 for r
in dossier
.remuneration_set
.all():
225 print 'trying %r' % r
227 if cg_lines
[r
.id]['montant'] == '':
230 for k
, v
in cg_lines
[r
.id].items():
234 messages
.add_message(request
, messages
.SUCCESS
, "Le dossier %s a été sauvegardé." % dossier
)
235 return redirect('embauche_consulter', dossier_id
=dossier
.id)
237 messages
.add_message(request
, messages
.ERROR
, 'Il y a des erreurs dans le formulaire.')
240 dossier_form
= DossierForm(instance
=dossier
)
241 piecesForm
= DossierPieceForm(instance
=dossier
)
242 justificationsNouveauForm
= JustificationNouvelEmployeForm(instance
=dossier
)
243 justificationsAutreForm
= JustificationAutreEmployeForm(instance
=dossier
)
245 # Initialisation d'un formulaire vide
246 dossier_rh
= rh
.Dossier()
247 poste_rh
= poste
.id_rh
249 dossier
= get_object_or_404(dae
.Dossier
, pk
=dossier
)
250 employe
= dossier
.employe
251 data
= dict(employe
='dae-%s' % employe
.id)
252 employe_form
= EmployeForm(initial
=data
, instance
=employe
)
254 dossier
= pre_filled_dossier(dossier_rh
, 'new', poste_rh
)
255 employe_form
= EmployeForm()
257 dossier_form
= DossierForm(instance
=dossier
)
258 piecesForm
= DossierPieceForm(instance
=dossier
)
259 justificationsNouveauForm
= JustificationNouvelEmployeForm(instance
=dossier
)
260 justificationsAutreForm
= JustificationAutreEmployeForm(instance
=dossier
)
262 vars = dict(step
='employe',
263 type_remun
=type_remun
,
266 piecesForm
=piecesForm
,
267 justificationsNouveauForm
=justificationsNouveauForm
,
268 justificationsAutreForm
=justificationsAutreForm
,
269 comparaison_dossiers
=get_dossiers_connexes(poste
),
270 forms
=dict(employe
=employe_form
, dossier
=dossier_form
, )
274 return render_to_response('dae/embauche.html', vars,
275 RequestContext(request
))
277 def embauches_liste(request
):
278 """ Liste des embauches. """
280 vars['embauches'] = dae
.Dossier
.objects
.all().order_by('-date_creation')
281 return render_to_response('dae/embauches_liste.html', vars, RequestContext(request
))
283 def employe(request
, key
):
284 """ Récupération AJAX de l'employé pour la page d'embauche. """
285 data
= dict(employe
=key
)
289 employe
= dae
.Employe()
292 source
, id = key
.split('-')
295 employe
= get_object_or_404(dae
.Employe
, pk
=id)
297 e
= get_object_or_404(rh
.Employe
, id=id)
298 # Initialisation avec les valeurs de l'employé de rh_v1
299 employe
= dae
.Employe(id_rh
=e
)
300 for field
in ('prenom', 'nom', 'genre'):
301 setattr(employe
, field
, getattr(e
, field
))
303 return HttpResponse(EmployeForm(initial
=data
, instance
=employe
).as_table())
305 def dossier(request
, poste_key
, employe_key
):
306 """ Récupération AJAX du dossier pour la page d'embauche. """
309 poste_source
, poste_id
= poste_key
.split('-')
310 poste
= get_object_or_404(dae
.Poste
, pk
=poste_id
)
312 # Récupérer la devise de l'implantation lié au poste
313 implantation_devise
= poste
.get_default_devise()
314 data
.update({'devise' : implantation_devise
.id})
316 if poste
.id_rh_id
is not None:
317 poste_rh
= get_object_or_404(rh
.Poste
, pk
=poste
.id_rh_id
)
321 ##########################################################################################
323 ##########################################################################################
324 if employe_key
== '':
325 employe_source
= 'new'
327 dossier_rh
= rh
.Dossier()
328 dossier
= pre_filled_dossier(dossier_rh
, employe_source
, poste_rh
)
330 ##########################################################################################
332 ##########################################################################################
333 if employe_key
.startswith('dae'):
334 employe_source
, employe_id
= employe_key
.split('-')
335 employe_dae
= get_object_or_404(dae
.Employe
, pk
=employe_id
)
337 # récupération de l'ancien dossier rh v1 pour l'employe DAE
339 dossier_rh
= rh
.Dossier
.objects
.get(employe
=employe_dae
.id_rh_id
, mandat_date_fin
=None)
340 except (rh
.Dossier
.DoesNotExist
):
341 dossier_rh
= rh
.Dossier()
343 # on tente de récupérer le dossier DAE, au pire on le contruit en le
344 # prépoluant avec son dossier rh v1.
346 dossier
= dae
.Dossier
.objects
.get(employe
=employe_dae
, poste
=poste
)
347 except (dae
.Dossier
.DoesNotExist
):
348 dossier
= pre_filled_dossier(dossier_rh
, employe_source
, poste_rh
)
349 employe
= employe_dae
.id_rh
350 ##########################################################################################
352 ##########################################################################################
353 if employe_key
.startswith('rh'):
354 employe_source
, employe_id
= employe_key
.split('-')
355 employe_rh
= get_object_or_404(rh
.Employe
, pk
=employe_id
)
357 # récupération de l'ancien dossier rh v1 pour l'employe rh v1, s'il n'en a pas,
358 # on en fournit un nouveau qui servira uniquement un créer un nouveau dossier DAE.
360 dossier_rh
= rh
.Dossier
.objects
.get(employe
=employe_rh
, mandat_date_fin
=None)
361 except (rh
.Dossier
.DoesNotExist
):
362 dossier_rh
= rh
.Dossier()
363 dossier
= pre_filled_dossier(dossier_rh
, employe_source
, poste_rh
)
366 dossier_form
= DossierForm(initial
=data
, instance
=dossier
)
367 vars = dict(form
=dossier_form
, poste
=poste
, employe
=employe
)
368 return render_to_response('dae/embauche-dossier.html', vars,
369 RequestContext(request
))
371 def salaire(request
, implantation
, devise
, classement
):
372 if not devise
or not classement
:
375 taux_impl
= rh
.TauxChange
.objects
.filter(implantation
=implantation
) \
377 taux
= rh
.TauxChange
.objects
.filter(devise
=devise
).order_by('-annee')
378 vp
= rh
.ValeurPoint
.objects
.filter(implantation
=implantation
) \
380 if vp
.count() * taux
.count() * taux_impl
.count() == 0:
383 classement
= get_object_or_404(rh
.Classement
, pk
=classement
)
384 taux
, taux_impl
, vp
= taux
[0].taux
, taux_impl
[0].taux
, vp
[0].valeur
386 salaire_euro
= round(vp
* classement
.coefficient
* taux_impl
, 2)
387 data
= dict(salaire_euro
=salaire_euro
, taux
=taux
,
388 salaire_devise
=round(salaire_euro
/ taux
, 2))
390 return HttpResponse(dumps(data
))
392 def pre_filled_dossier(dossier_rh
, employe_source
, poste_rh
):
393 dossier
= dae
.Dossier()
395 if employe_source
!= 'new' and dossier_rh
.id:
396 dossier
.statut_anterieur
= dossier_rh
.statut
398 # Certains dossiers ont un classement à zéro
399 if dossier_rh
.classement_id
> 0:
400 dossier
.classement_anterieur
= dossier_rh
.classement
402 # Récupération du salaire de base
403 remun
= dossier_rh
.remuneration_set
.filter(type=1)
405 dossier
.salaire_anterieur
= remun
[0].montant
407 # Récupération du titulaire précédent
409 dossiers
= rh
.Dossier
.objects
.order_by('-mandat_date_fin')
410 dossiers
= dossiers
.filter(poste1
=poste_rh
) | dossiers
.filter(poste2
=poste_rh
)
412 # Ce bloc ignore toutes les erreurs, car les données de rh
413 # manquantes peuvent en générer
416 titulaire
= d
.employe
417 dossier
.employe_anterieur
= titulaire
418 dossier
.classement_titulaire_anterieur
= d
.classement
419 dossier
.statut_titulaire_anterieur
= d
.statut
420 dossier
.salaire_titulaire_anterieur
= \
421 d
.remuneration_set
.all()[0].montant
424 # TODO: afficher l'info, les champs ne sont pas dans le
425 # modèle dae.Dossier: nom, prenom, classement, salaire
428 except (rh
.Dossier
.DoesNotExist
):
429 dossier_rh
= rh
.Dossier()
433 def coefficient(request
):
438 method
= request
.method
439 params
= getattr(request
, method
, [])
441 if 'classement' in params
and params
.get('classement') is not u
"":
442 classement
= params
.get('classement')
443 classement
= rh
.Classement
.objects
.get(pk
=classement
)
444 data
['coefficient'] = classement
.coefficient
446 data
['coefficient'] = 0
447 return HttpResponse(dumps(data
))
450 def liste_valeurs_point(request
):
452 input : implantation_id
453 output : JSON liste de valeur point
455 method
= request
.method
456 params
= getattr(request
, method
, [])
458 annee_courante
= datetime
.datetime
.now().year
459 if 'implantation_id' in params
and params
.get('implantation_id') is not u
"":
460 implantation_id
= params
.get('implantation_id')
461 objects
= rh
.ValeurPoint
.objects
.filter(implantation
=implantation_id
, annee__in
=(annee_courante
-1, annee_courante
)).order_by("-annee")
463 objects
= rh
.ValeurPoint
.objects
.filter(annee__in
=(annee_courante
-1, annee_courante
)).order_by("-annee")
465 data
.append({'id' : o
.id, 'label' : o
.__unicode__(), })
466 return HttpResponse(dumps(data
))
468 def liste_postes(request
):
470 input : implantation_id
471 output : JSON liste de valeur point
473 method
= request
.method
474 params
= getattr(request
, method
, [])
477 # Voir le code de _poste_choices dans forms.py
478 dae_
= dae
.Poste
.objects
.filter(actif
=True, id_rh__isnull
=True)
479 copies
= dae
.Poste
.objects
.exclude(id_rh__isnull
=True)
480 rh_postes_actifs
= rh
.Poste
.objects
.filter(actif
=True)
482 if 'implantation_id' in params
and params
.get('implantation_id') is not u
"":
483 implantation_id
= params
.get('implantation_id')
484 dae_
= dae_
.filter(implantation__id
=implantation_id
)
485 copies
= copies
.filter(implantation__id
=implantation_id
)
486 rh_postes_actifs
= rh_postes_actifs
.filter(implantation__id
=implantation_id
)
488 id_copies
= [p
.id_rh_id
for p
in copies
.all()]
489 rhv1
= rh_postes_actifs
.exclude(id__in
=id_copies
)
490 rhv1
= rhv1
.select_related(depth
=1)
492 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])
493 return HttpResponse(dumps(data
))
498 output : devise, devise_code, taux_euro
500 method
= request
.method
501 params
= getattr(request
, method
, [])
503 if 'valeur_point' in params
and params
.get('valeur_point') is not u
"":
504 valeur_point
= params
.get('valeur_point')
505 valeur_point
= rh
.ValeurPoint
.objects
.get(pk
=valeur_point
)
506 annee
= valeur_point
.annee
507 implantation
= valeur_point
.implantation
508 taux
= rh
.TauxChange
.objects
.get(annee
=annee
,
509 implantation
=implantation
)
510 data
['devise'] = taux
.devise
.id
511 data
['valeur'] = valeur_point
.valeur
512 data
['devise_code'] = taux
.devise
.code
513 data
['taux_euro'] = taux
.taux
515 return HttpResponseGone("Vous devez choisir une valeur de point")
516 return HttpResponse(dumps(data
))
518 def devise_code(request
):
521 output : devise_code, taux_euro
523 method
= request
.method
524 params
= getattr(request
, method
, [])
526 if 'devise' in params
:
527 devise
= params
.get('devise')
528 devise
= rh
.Devise
.objects
.get(pk
=devise
)
529 annee
= date
.today().year
530 taux
= rh
.TauxChange
.objects
.filter(annee
=annee
, devise
=devise
)
532 return HttpResponseGone("Le taux n'est pas disponible")
533 data
['devise_code'] = devise
.code
534 data
['taux_euro'] = taux
[0].taux
535 return HttpResponse(dumps(data
))
537 def add_remun(request
, dossier
, type_remun
):
538 dossier
= get_object_or_404(dae
.Dossier
, pk
=dossier
)
539 type_remun
= get_object_or_404(rh
.TypeRemuneration
, pk
=type_remun
)
540 dae
.Remuneration(dossier
=dossier
, devise
=dossier
.devise
,
541 type=type_remun
).save()
543 return render_to_response('dae/embauche-remun.html', dict(dossier
=dossier
),
544 RequestContext(request
))