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(request
, key
=None):
29 """ Formulaire pour un poste.
31 Permet de créer ou modifier un poste. Si le poste n'existe que dans rh_v1
32 il est automatiquement copié dans dae.
35 poste
, data
, vars = None, dict(), dict()
40 source
, id = key
.split('-')
43 poste
= get_object_or_404(dae
.Poste
, pk
=id)
45 p
= get_object_or_404(rh
.Poste
, pk
=id)
46 # Initialisation avec les valeurs du poste de rh_v1
47 poste
= dae
.Poste(id_rh
=p
, nom
=p
.type_poste
.nom
)
48 for field
in ('implantation', 'type_poste', 'actif'):
49 setattr(poste
, field
, getattr(p
, field
))
55 data
.update(dict(request
.POST
.items()))
56 form
= PosteForm(data
, instance
=poste
)
57 financementForm
= FinancementForm(request
.POST
, instance
=poste
)
58 piecesForm
= PostePieceForm(request
.POST
, request
.FILES
, instance
=poste
)
59 if 'save' in data
and form
.is_valid() and piecesForm
.is_valid() and financementForm
.is_valid():
61 piecesForm
.instance
= poste
63 financementForm
.instance
= poste
64 financementForm
.save()
65 messages
.add_message(request
, messages
.SUCCESS
, "Le poste %s a été sauvegardé." % poste
)
66 return redirect('poste', key
='dae-%s' % poste
.id)
68 messages
.add_message(request
, messages
.ERROR
, 'Il y a des erreurs dans le formulaire.')
71 # 'initial' évite la validation prémature lors d'une copie de poste de
73 form
= PosteForm(initial
=data
, instance
=poste
)
74 piecesForm
= PostePieceForm(instance
=poste
)
75 financementForm
= FinancementForm(instance
=poste
)
77 vars.update(dict(form
=form
, poste
=poste
, poste_key
=key
, piecesForm
=piecesForm
, financementForm
=financementForm
))
79 return render_to_response('dae/poste.html', vars, RequestContext(request
))
82 def postes_liste(request
):
83 """ Liste des postes. """
87 for p
in dae
.Poste
.objects
.all().order_by('-date_creation'):
88 versions
= Version
.objects
.get_for_object(p
)
90 premiere_revision
= versions
[0].revision
92 premiere_revision
= None
95 validationForm
= PosteValidationForm(request
.POST
, instance
=p
, prefix
=p
.id)
96 if validationForm
.is_valid():
97 p
= validationForm
.save()
99 validationForm
= PosteValidationForm(instance
=p
, prefix
=p
.id)
101 vars['postes'].append((p
, premiere_revision
, validationForm
))
104 return redirect(reverse('dae_postes_liste'))
106 return render_to_response('dae/postes_liste.html', vars,
107 RequestContext(request
))
109 def filtered_type_remun():
110 # Exclusion de "Indemnité de fonction" des types de rémun utilisés
111 return rh
.TypeRemuneration
.objects
.exclude(pk
=7)
114 def embauche(request
, key
=None, dossier
=None):
115 """ Formulaire d'autorisation d'embauche. """
117 vars = dict(step
='poste', form
=ChoosePosteForm())
119 type_remun
= filtered_type_remun()
120 vars = dict(type_remun
=type_remun
)
121 source
, id = key
.split('-')
124 poste
= get_object_or_404(dae
.Poste
, pk
=id)
129 if request
.POST
['employe'] == '':
131 employe
= dae
.Employe()
133 employe_source
, id = request
.POST
['employe'].split('-')
134 if employe_source
== 'dae':
136 employe
= get_object_or_404(dae
.Employe
, pk
=id)
137 elif employe_source
== 'rh':
138 # Employé RH, on le copie dans DAE
139 e
= get_object_or_404(rh
.Employe
, pk
=id)
140 employe
= dae
.Employe(id_rh
=e
, prenom
=e
.prenom
, nom
=e
.nom
,
145 employe_form
= EmployeForm(request
.POST
, instance
=employe
)
147 if 'save' in request
.POST
:
148 if employe_form
.is_valid():
149 data
= dict(request
.POST
.items())
150 #with warnings.catch_warnings():
151 # warnings.simplefilter('ignore')
152 employe
= employe_form
.save()
153 data
['employe'] = 'dae-%s' % employe
.id
154 employe_form
= EmployeForm(data
, instance
=employe
)
157 dossier
= dae
.Dossier(poste
=poste
, employe
=employe
)
159 dossier
= get_object_or_404(dae
.Dossier
, pk
=dossier
)
160 dossier_form
= DossierForm(request
.POST
, instance
=dossier
)
161 piecesForm
= DossierPieceForm(request
.POST
, request
.FILES
, instance
=dossier
)
162 justificationsNouveauForm
= JustificationNouvelEmployeForm(request
.POST
, instance
=dossier
)
163 justificationsAutreForm
= JustificationAutreEmployeForm(request
.POST
, instance
=dossier
)
165 if dossier_form
.is_valid() and piecesForm
.is_valid() and justificationsNouveauForm
.is_valid() and justificationsAutreForm
.is_valid():
166 dossier
= dossier_form
.save()
167 piecesForm
.instance
= dossier
169 justificationsNouveauForm
.instance
= dossier
170 justificationsNouveauForm
.save()
171 justificationsAutreForm
.instance
= dossier
172 justificationsAutreForm
.save()
173 if not dossier
.remuneration_set
.all():
174 # Pré-peuplement des entrées de la section "coût
175 # global", à l'exclusion de "Indemnité de fonction"
176 for type in type_remun
.all():
177 dae
.Remuneration(dossier
=dossier
, type=type,
178 devise
=dossier
.devise
).save()
181 # Sauvegarde du coût global
182 cg_lines
= defaultdict(dict)
183 for k
, v
in request
.POST
.items():
184 if k
.startswith('cg-'):
185 prefix
, field_name
, cg_id
= k
.split('-')
186 cg_lines
[int(cg_id
)][unicode(field_name
)] = v
188 for r
in dossier
.remuneration_set
.all():
189 print 'trying %r' % r
191 if cg_lines
[r
.id]['montant'] == '':
194 for k
, v
in cg_lines
[r
.id].items():
198 messages
.add_message(request
, messages
.SUCCESS
, "Le dossier %s a été sauvegardé." % dossier
)
199 return redirect('embauche', key
='dae-%s' % poste
.id,
202 messages
.add_message(request
, messages
.ERROR
, 'Il y a des erreurs dans le formulaire.')
205 dossier_form
= DossierForm(instance
=dossier
)
206 piecesForm
= DossierPieceForm(instance
=dossier
)
207 justificationsNouveauForm
= JustificationNouvelEmployeForm(instance
=dossier
)
208 justificationsAutreForm
= JustificationAutreEmployeForm(instance
=dossier
)
210 # Initialisation d'un formulaire vide
211 dossier_rh
= rh
.Dossier()
212 poste_rh
= poste
.id_rh
214 dossier
= get_object_or_404(dae
.Dossier
, pk
=dossier
)
215 employe
= dossier
.employe
216 data
= dict(employe
='dae-%s' % employe
.id)
217 employe_form
= EmployeForm(initial
=data
, instance
=employe
)
219 dossier
= pre_filled_dossier(dossier_rh
, 'new', poste_rh
)
220 employe_form
= EmployeForm()
222 dossier_form
= DossierForm(instance
=dossier
)
223 piecesForm
= DossierPieceForm(instance
=dossier
)
224 justificationsNouveauForm
= JustificationNouvelEmployeForm(instance
=dossier
)
225 justificationsAutreForm
= JustificationAutreEmployeForm(instance
=dossier
)
227 # Chargement des données de comparaison
228 comparaison_dossiers
= []
229 famille
= poste
.type_poste
.famille_emploi
230 # postes DAE (vieux dossiers)
231 postes_region
= dae
.Poste
.objects
.filter(implantation__region
=poste
.implantation
.region
)
232 for p
in postes_region
:
233 dossiers
= p
.get_dossiers()
234 if len(dossiers
) > 0 and dossiers
[0].poste1
.type_poste
.famille_emploi
== famille
:
235 comparaison_dossiers
.append(dossiers
[0])
236 # poste RHv1 (vieux dossiers)
237 postes_region
= rh
.Poste
.objects
.filter(implantation__region
=poste
.implantation
.region
)
238 for p
in postes_region
:
239 dossiers
= p
.poste1
.all().order_by('rh_v1_dossier.date_creation') # through key incohérente... (dossiers)
240 if len(dossiers
) > 0 and dossiers
[0].poste1
.type_poste
.famille_emploi
== famille
:
241 comparaison_dossiers
.append(dossiers
[0])
243 vars = dict(step
='employe',
246 piecesForm
=piecesForm
,
247 justificationsNouveauForm
=justificationsNouveauForm
,
248 justificationsAutreForm
=justificationsAutreForm
,
249 comparaison_dossiers
=comparaison_dossiers
,
250 forms
=dict(employe
=employe_form
, dossier
=dossier_form
, )
254 return render_to_response('dae/embauche.html', vars,
255 RequestContext(request
))
257 def embauches_liste(request
):
258 """ Liste des embauches. """
260 vars['embauches'] = []
261 for d
in dae
.Dossier
.objects
.all().order_by('-date_creation'):
262 versions
= Version
.objects
.get_for_object(d
)
263 if len(versions
) > 0:
264 premiere_revision
= versions
[0].revision
266 premiere_revision
= None
267 vars['embauches'].append((d
, premiere_revision
))
268 return render_to_response('dae/embauches_liste.html', vars,
269 RequestContext(request
))
271 def employe(request
, key
):
272 """ Récupération AJAX de l'employé pour la page d'embauche. """
273 data
= dict(employe
=key
)
277 employe
= dae
.Employe()
280 source
, id = key
.split('-')
283 employe
= get_object_or_404(dae
.Employe
, pk
=id)
285 e
= get_object_or_404(rh
.Employe
, id=id)
286 # Initialisation avec les valeurs de l'employé de rh_v1
287 employe
= dae
.Employe(id_rh
=e
)
288 for field
in ('prenom', 'nom', 'genre'):
289 setattr(employe
, field
, getattr(e
, field
))
291 return HttpResponse(EmployeForm(initial
=data
, instance
=employe
).as_table())
293 def dossier(request
, poste_key
, employe_key
):
294 """ Récupération AJAX du dossier pour la page d'embauche. """
297 poste_source
, poste_id
= poste_key
.split('-')
298 poste
= get_object_or_404(dae
.Poste
, pk
=poste_id
)
300 # Récupérer la devise de l'implantation lié au poste
301 implantation_devise
= poste
.get_default_devise()
302 data
.update({'devise' : implantation_devise
.id})
304 if poste
.id_rh_id
is not None:
305 poste_rh
= get_object_or_404(rh
.Poste
, pk
=poste
.id_rh_id
)
309 ##########################################################################################
311 ##########################################################################################
312 if employe_key
== '':
313 employe_source
= 'new'
315 dossier_rh
= rh
.Dossier()
316 dossier
= pre_filled_dossier(dossier_rh
, employe_source
, poste_rh
)
318 ##########################################################################################
320 ##########################################################################################
321 if employe_key
.startswith('dae'):
322 employe_source
, employe_id
= employe_key
.split('-')
323 employe_dae
= get_object_or_404(dae
.Employe
, pk
=employe_id
)
325 # récupération de l'ancien dossier rh v1 pour l'employe DAE
327 dossier_rh
= rh
.Dossier
.objects
.get(employe
=employe_dae
.id_rh_id
, mandat_date_fin
=None)
328 except (rh
.Dossier
.DoesNotExist
):
329 dossier_rh
= rh
.Dossier()
331 # on tente de récupérer le dossier DAE, au pire on le contruit en le
332 # prépoluant avec son dossier rh v1.
334 dossier
= dae
.Dossier
.objects
.get(employe
=employe_dae
, poste
=poste
)
335 except (dae
.Dossier
.DoesNotExist
):
336 dossier
= pre_filled_dossier(dossier_rh
, employe_source
, poste_rh
)
337 employe
= employe_dae
.id_rh
338 ##########################################################################################
340 ##########################################################################################
341 if employe_key
.startswith('rh'):
342 employe_source
, employe_id
= employe_key
.split('-')
343 employe_rh
= get_object_or_404(rh
.Employe
, pk
=employe_id
)
345 # récupération de l'ancien dossier rh v1 pour l'employe rh v1, s'il n'en a pas,
346 # on en fournit un nouveau qui servira uniquement un créer un nouveau dossier DAE.
348 dossier_rh
= rh
.Dossier
.objects
.get(employe
=employe_rh
, mandat_date_fin
=None)
349 except (rh
.Dossier
.DoesNotExist
):
350 dossier_rh
= rh
.Dossier()
351 dossier
= pre_filled_dossier(dossier_rh
, employe_source
, poste_rh
)
354 dossier_form
= DossierForm(initial
=data
, instance
=dossier
)
355 vars = dict(form
=dossier_form
, poste
=poste
, employe
=employe
)
356 return render_to_response('dae/embauche-dossier.html', vars,
357 RequestContext(request
))
359 def salaire(request
, implantation
, devise
, classement
):
360 if not devise
or not classement
:
363 taux_impl
= rh
.TauxChange
.objects
.filter(implantation
=implantation
) \
365 taux
= rh
.TauxChange
.objects
.filter(devise
=devise
).order_by('-annee')
366 vp
= rh
.ValeurPoint
.objects
.filter(implantation
=implantation
) \
368 if vp
.count() * taux
.count() * taux_impl
.count() == 0:
371 classement
= get_object_or_404(rh
.Classement
, pk
=classement
)
372 taux
, taux_impl
, vp
= taux
[0].taux
, taux_impl
[0].taux
, vp
[0].valeur
374 salaire_euro
= round(vp
* classement
.coefficient
* taux_impl
, 2)
375 data
= dict(salaire_euro
=salaire_euro
, taux
=taux
,
376 salaire_devise
=round(salaire_euro
/ taux
, 2))
378 return HttpResponse(dumps(data
))
380 def pre_filled_dossier(dossier_rh
, employe_source
, poste_rh
):
381 dossier
= dae
.Dossier()
383 if employe_source
!= 'new' and dossier_rh
.id:
384 dossier
.statut_anterieur
= dossier_rh
.statut
386 # Certains dossiers ont un classement à zéro
387 if dossier_rh
.classement_id
> 0:
388 dossier
.classement_anterieur
= dossier_rh
.classement
390 # Récupération du salaire de base
391 remun
= dossier_rh
.remuneration_set
.filter(type=1)
393 dossier
.salaire_anterieur
= remun
[0].montant
395 # Récupération du titulaire précédent
397 dossiers
= rh
.Dossier
.objects
.order_by('-mandat_date_fin')
398 dossiers
= dossiers
.filter(poste1
=poste_rh
) | dossiers
.filter(poste2
=poste_rh
)
400 # Ce bloc ignore toutes les erreurs, car les données de rh
401 # manquantes peuvent en générer
404 titulaire
= d
.employe
405 dossier
.employe_anterieur
= titulaire
406 dossier
.classement_titulaire_anterieur
= d
.classement
407 dossier
.statut_titulaire_anterieur
= d
.statut
408 dossier
.salaire_titulaire_anterieur
= \
409 d
.remuneration_set
.all()[0].montant
412 # TODO: afficher l'info, les champs ne sont pas dans le
413 # modèle dae.Dossier: nom, prenom, classement, salaire
416 except (rh
.Dossier
.DoesNotExist
):
417 dossier_rh
= rh
.Dossier()
421 def coefficient(request
):
426 method
= request
.method
427 params
= getattr(request
, method
, [])
429 if 'classement' in params
and params
.get('classement') is not u
"":
430 classement
= params
.get('classement')
431 classement
= rh
.Classement
.objects
.get(pk
=classement
)
432 data
['coefficient'] = classement
.coefficient
434 data
['coefficient'] = 0
435 return HttpResponse(dumps(data
))
438 def liste_valeurs_point(request
):
440 input : implantation_id
441 output : JSON liste de valeur point
443 method
= request
.method
444 params
= getattr(request
, method
, [])
446 annee_courante
= datetime
.datetime
.now().year
447 if 'implantation_id' in params
and params
.get('implantation_id') is not u
"":
448 implantation_id
= params
.get('implantation_id')
449 objects
= rh
.ValeurPoint
.objects
.filter(implantation
=implantation_id
, annee__in
=(annee_courante
-1, annee_courante
)).order_by("-annee")
451 objects
= rh
.ValeurPoint
.objects
.filter(annee__in
=(annee_courante
-1, annee_courante
)).order_by("-annee")
453 data
.append({'id' : o
.id, 'label' : o
.__unicode__(), })
454 return HttpResponse(dumps(data
))
456 def liste_postes(request
):
458 input : implantation_id
459 output : JSON liste de valeur point
461 method
= request
.method
462 params
= getattr(request
, method
, [])
465 # Voir le code de _poste_choices dans forms.py
466 dae_
= dae
.Poste
.objects
.filter(actif
=True, id_rh__isnull
=True)
467 copies
= dae
.Poste
.objects
.exclude(id_rh__isnull
=True)
468 rh_postes_actifs
= rh
.Poste
.objects
.filter(actif
=True)
470 if 'implantation_id' in params
and params
.get('implantation_id') is not u
"":
471 implantation_id
= params
.get('implantation_id')
472 dae_
= dae_
.filter(implantation__id
=implantation_id
)
473 copies
= copies
.filter(implantation__id
=implantation_id
)
474 rh_postes_actifs
= rh_postes_actifs
.filter(implantation__id
=implantation_id
)
476 id_copies
= [p
.id_rh_id
for p
in copies
.all()]
477 rhv1
= rh_postes_actifs
.exclude(id__in
=id_copies
)
478 rhv1
= rhv1
.select_related(depth
=1)
479 data
= [('', 'Nouveau poste')] + \
480 sorted([('dae-%s' % p
.id, unicode(p
)) for p
in dae_ | copies
] +
481 [('rh-%s' % p
.id, unicode(p
)) for p
in rhv1
],
483 return HttpResponse(dumps(data
))
488 output : devise, devise_code, taux_euro
490 method
= request
.method
491 params
= getattr(request
, method
, [])
493 if 'valeur_point' in params
and params
.get('valeur_point') is not u
"":
494 valeur_point
= params
.get('valeur_point')
495 valeur_point
= rh
.ValeurPoint
.objects
.get(pk
=valeur_point
)
496 annee
= valeur_point
.annee
497 implantation
= valeur_point
.implantation
498 taux
= rh
.TauxChange
.objects
.get(annee
=annee
,
499 implantation
=implantation
)
500 data
['devise'] = taux
.devise
.id
501 data
['valeur'] = valeur_point
.valeur
502 data
['devise_code'] = taux
.devise
.code
503 data
['taux_euro'] = taux
.taux
505 return HttpResponseGone("Vous devez choisir une valeur de point")
506 return HttpResponse(dumps(data
))
508 def devise_code(request
):
511 output : devise_code, taux_euro
513 method
= request
.method
514 params
= getattr(request
, method
, [])
516 if 'devise' in params
:
517 devise
= params
.get('devise')
518 devise
= rh
.Devise
.objects
.get(pk
=devise
)
519 annee
= date
.today().year
520 taux
= rh
.TauxChange
.objects
.filter(annee
=annee
, devise
=devise
)
522 return HttpResponseGone("Le taux n'est pas disponible")
523 data
['devise_code'] = devise
.code
524 data
['taux_euro'] = taux
[0].taux
525 return HttpResponse(dumps(data
))
527 def add_remun(request
, dossier
, type_remun
):
528 dossier
= get_object_or_404(dae
.Dossier
, pk
=dossier
)
529 type_remun
= get_object_or_404(rh
.TypeRemuneration
, pk
=type_remun
)
530 dae
.Remuneration(dossier
=dossier
, devise
=dossier
.devise
,
531 type=type_remun
).save()
533 return render_to_response('dae/embauche-remun.html', dict(dossier
=dossier
),
534 RequestContext(request
))