[#2658] Retrait du hack app_label() dans rh.models
[auf_rh_dae.git] / project / rh / views.py
1 # -*- encoding: utf-8 -*-
2
3 import urllib
4 from datetime import date
5 from itertools import izip
6 import StringIO
7
8 import pygraphviz as pgv
9 from datamaster_modeles import models as ref
10 from django import forms
11 from django.conf import settings
12 from django.contrib.auth.decorators import login_required
13 from django.core.servers.basehttp import FileWrapper
14 from django.core.urlresolvers import reverse
15 from django.db.models import Q
16 from django.http import HttpResponse
17 from django.shortcuts import render_to_response, get_object_or_404
18 from django.template import RequestContext
19 from django.utils.encoding import smart_str
20
21 from project.dae.utils import get_employe_from_user
22 from project.dae.decorators import redirect_interdiction
23 from project.dae.workflow import grp_drh, grp_correspondants_rh
24 from project.rh import models as rh
25 from project.rh.lib import calc_remun
26 from project.rh.decorators import drh_or_admin_required
27 from project.rh.templatetags.rapports import SortHeaders
28 from project.rh.change_list import RechercheTemporelle
29 from project.rh import graph as rh_graph
30 from project.rh.masse_salariale import MasseSalariale
31
32
33 @login_required
34 def profil(request):
35 """Profil personnel de l'employé - éditable"""
36 rc = RequestContext(request)
37 c = {}
38
39 employe = rc['this_employe']
40
41 c['user'] = request.user
42 c['employe'] = employe
43 return render_to_response('rh/profil.html', c, rc)
44
45
46 @login_required
47 def employes_liste(request):
48 """Liste des employés."""
49 today = date.today()
50 employes = rh.Employe.objects \
51 .exclude(dossiers__date_debut__gt=today) \
52 .exclude(dossiers__date_fin__lt=today) \
53 .order_by('nom')
54 c = {
55 'user': request.user,
56 'employes': employes,
57 }
58 return render_to_response('rh/employes_liste.html',
59 c,
60 RequestContext(request))
61
62
63 @login_required
64 def employe(request, id):
65 """Information publique sur un employé."""
66 try:
67 employe = rh.Employe.objects.get(pk=id)
68 except:
69 employe = rh.Employe.objects.none()
70 c = {
71 'user': request.user,
72 'employe': employe,
73 }
74 return render_to_response('rh/employe.html', c, RequestContext(request))
75
76
77 @login_required
78 @drh_or_admin_required
79 def rapports_poste(request):
80
81 lookup_params = dict(request.GET.items())
82
83 for key, value in lookup_params.items():
84 if key == 'o' or key == 'ot':
85 del lookup_params[key]
86 continue
87 if not isinstance(key, str):
88 # 'key' will be used as a keyword argument later, so Python
89 # requires it to be a string.
90 del lookup_params[key]
91 lookup_params[smart_str(key)] = value
92
93 if key == 'comble':
94 del lookup_params[key]
95
96 sort_order = 'ASC' if request.GET.get('ot') == 'asc' else 'DESC'
97
98 postes = rh.Poste.objects.select_related('implantation') \
99 .extra(select={
100 'employe_id':
101 'SELECT GROUP_CONCAT(employe SEPARATOR "|") '
102 'FROM rh_dossier '
103 'WHERE poste = rh_poste.id '
104 'AND rh_dossier.date_fin IS NULL ' + (
105 'ORDER BY employe ' + sort_order
106 if request.GET.get('o') == 'employe_id' else ''
107 )
108 }) \
109 .extra(select={
110 'employe_nom':
111 'SELECT GROUP_CONCAT(rh_employe.nom SEPARATOR "|") '
112 'FROM rh_dossier INNER JOIN rh_employe '
113 'ON rh_dossier.employe = rh_employe.id '
114 'WHERE poste = rh_poste.id '
115 'AND rh_dossier.date_fin IS NULL ' + (
116 'ORDER BY rh_employe.nom ' + sort_order
117 if request.GET.get('o') == 'employe_nom' else ''
118 )
119 }) \
120 .extra(select={
121 'employe_prenom':
122 'SELECT GROUP_CONCAT(rh_employe.prenom SEPARATOR "|") '
123 'FROM rh_dossier INNER JOIN rh_employe '
124 'ON rh_dossier.employe = rh_employe.id '
125 'WHERE poste = rh_poste.id '
126 'AND rh_dossier.date_fin IS NULL ' + (
127 'ORDER BY rh_employe.prenom ' + sort_order
128 if request.GET.get('o') == 'employe_prenom' else ''
129 )
130 })
131
132 postes = postes.filter(**lookup_params)
133 if 'o' in request.GET:
134 postes = postes.order_by(
135 ('-' if sort_order == "DESC" else '') + request.GET['o']
136 )
137
138 out = []
139 for p in postes:
140 out.append({
141 'id': p.id,
142 'nom': p.nom,
143 'implantation': p.implantation,
144 'employes': [] if not p.employe_id else [
145 {'id': id, 'nom': nom, 'prenom': prenom}
146 for id, nom, prenom in izip(
147 p.employe_id.split('|'),
148 p.employe_nom.split('|'),
149 p.employe_prenom.split('|')
150 )
151 ]
152 })
153
154 headers = [
155 ("id", u"# du poste"),
156 ("nom", u"Nom du poste"),
157 ("implantation__id", u"Implantation"),
158 ("employe_nom", u"Nom"),
159 ]
160 h = SortHeaders(request, headers, order_field_type="ot", order_field="o")
161 c = {
162 'title': 'Rapport des postes',
163 'postes': out,
164 'count': len(out),
165 'headers': list(h.headers()),
166 }
167
168 return render_to_response(
169 'rh/rapports/postes.html', c, RequestContext(request)
170 )
171
172
173 @login_required
174 @drh_or_admin_required
175 def rapports_contrat(request):
176 if 'HTTP_REFERER' in request.META.keys():
177 referer = request.META['HTTP_REFERER']
178 referer = "/".join(referer.split('/')[3:])
179 referer = "/%s" % referer.split('?')[0]
180 if referer != reverse('rhr_contrats'):
181 params = request.GET.copy()
182 params.update({'statut': 'Actif'})
183 request.GET = params
184
185 lookup_params = dict(request.GET.items())
186 if 'ot' in lookup_params:
187 del lookup_params['ot']
188 if 'o' in lookup_params:
189 del lookup_params['o']
190
191 for key, value in lookup_params.items():
192 if not isinstance(key, str):
193 # 'key' will be used as a keyword argument later, so Python
194 # requires it to be a string.
195 del lookup_params[key]
196 lookup_params[smart_str(key)] = value
197
198 contrats = rh.Contrat.objects.select_related(
199 'dossier', 'dossier__poste', 'dossier__poste__implantation',
200 'type_contrat', 'dossier__employe'
201 )
202
203 cl = RechercheTemporelle(dict(request.GET.items()), rh.Contrat)
204 lookup_params = cl.purge_params(lookup_params)
205 q_temporel = cl.get_q_temporel(contrats)
206 q = Q(**lookup_params) & q_temporel
207 contrats = contrats.filter(q).exclude(dossier__employe__supprime=1)
208
209 if 'o' in request.GET:
210 contrats = contrats.order_by(
211 ('-' if request.GET.get('ot') == "desc" else '') + request.GET['o']
212 )
213
214 employes = set([c.dossier.employe_id for c in contrats])
215
216 headers = [
217 ("dossier__employe__id", u"# de l'employé"),
218 ("dossier__employe__nom", u"Employé"),
219 ("type_contrat__nom", u"Poste"),
220 ("dossier__poste__implantation__region", u"Région"),
221 ("dossier__poste__implantation", u"Implantation"),
222 ("type_contrat__nom", u"Type de contrat"),
223 ("date_debut", u"Date début"),
224 ("date_fin", u"Date fin"),
225 ]
226 h = SortHeaders(request, headers, order_field_type="ot", order_field="o")
227
228 c = {
229 'cl': cl,
230 'title': 'Rapport des contrats',
231 'contrats': contrats,
232 'count': len(contrats),
233 'count_employe': len(employes),
234 'headers': list(h.headers()),
235 }
236
237 return render_to_response(
238 'rh/rapports/contrats.html', c, RequestContext(request)
239 )
240
241
242 @login_required
243 @drh_or_admin_required
244 def rapports_masse_salariale(request):
245
246 class RechercheTemporelle(forms.Form):
247 CHOICE_ANNEES = range(
248 rh.Remuneration.objects.exclude(date_debut=None)
249 .order_by('date_debut')[0].date_debut.year,
250 date.today().year + 1
251 )
252
253 annee = forms.CharField(
254 initial=date.today().year,
255 widget=forms.Select(
256 choices=((a, a) for a in reversed(CHOICE_ANNEES))
257 )
258 )
259
260 region = forms.CharField(
261 widget=forms.Select(choices=[('', '')] +
262 [(i.id, i) for i in ref.Region.objects.all()]
263 )
264 )
265
266 implantation = forms.CharField(
267 widget=forms.Select(choices=[('', '')] +
268 [(i.id, i) for i in ref.Implantation.objects.all()]
269 )
270 )
271
272 #date_debut = forms.DateField(widget=adminwidgets.AdminDateWidget)
273 #date_fin = forms.DateField(widget=adminwidgets.AdminDateWidget)
274
275 form = RechercheTemporelle(request.GET)
276 get_filtre = [
277 (k, v) for k, v in request.GET.items()
278 if k not in ('date_debut', 'date_fin', 'implantation')
279 ]
280 query_string = urllib.urlencode(get_filtre)
281
282 date_debut = None
283 date_fin = None
284 if request.GET.get('annee', None):
285 date_debut = "01-01-%s" % request.GET.get('annee', None)
286 date_fin = "31-12-%s" % request.GET.get('annee', None)
287
288 implantation = request.GET.get('implantation')
289 region = request.GET.get('region')
290
291 custom_filter = {}
292 if implantation:
293 custom_filter['dossier__poste__implantation'] = implantation
294 if region:
295 custom_filter['dossier__poste__implantation__region'] = region
296
297 c = {
298 'title': 'Rapport de masse salariale',
299 'form': form,
300 'headers': [],
301 'query_string': query_string,
302 }
303 if date_debut or date_fin:
304 masse = MasseSalariale(date_debut, date_fin, custom_filter,
305 request.GET.get('ne_pas_grouper', False))
306 if masse.rapport:
307 if request.GET.get('ods'):
308 for h in (
309 h for h in masse.headers if 'background-color' in h[2]
310 ):
311 del h[2]['background-color']
312 masse.ods()
313 output = StringIO.StringIO()
314 masse.doc.save(output)
315 output.seek(0)
316
317 response = HttpResponse(
318 FileWrapper(output),
319 content_type=(
320 'application/vnd.oasis.opendocument.spreadsheet'
321 )
322 )
323 response['Content-Disposition'] = \
324 'attachment; filename=Masse Salariale %s.ods' % \
325 masse.annee
326 return response
327 else:
328 c['rapport'] = masse.rapport
329 c['header_keys'] = [h[0] for h in masse.headers]
330 #on enleve le background pour le header
331 for h in (
332 h for h in masse.headers if 'background-color' in h[2]
333 ):
334 h[2]['background'] = 'none'
335 h = SortHeaders(request, masse.headers, order_field_type="ot",
336 not_sortable=c['header_keys'], order_field="o")
337 c['headers'] = list(h.headers())
338 for key, nom, opts in masse.headers:
339 c['headers']
340 c['total'] = masse.grand_totaux[0]
341 c['total_euro'] = masse.grand_totaux[1]
342 c['colspan'] = len(c['header_keys']) - 1
343 get_filtre.append(('ods', True))
344 query_string = urllib.urlencode(get_filtre)
345 c['url_ods'] = "%s?%s" % (
346 reverse('rhr_masse_salariale'), query_string)
347
348 return render_to_response(
349 'rh/rapports/masse_salariale.html', c, RequestContext(request)
350 )
351
352
353 @login_required
354 @drh_or_admin_required
355 def rapports_remuneration(request):
356
357 lookup_params = dict(request.GET.items())
358 if 'ot' in lookup_params:
359 del lookup_params['ot']
360 if 'o' in lookup_params:
361 del lookup_params['o']
362
363 for key, value in lookup_params.items():
364 if not isinstance(key, str):
365 # 'key' will be used as a keyword argument later, so Python
366 # requires it to be a string.
367 del lookup_params[key]
368 lookup_params[smart_str(key)] = value
369
370 employes = rh.Employe.objects.all()
371 if 'o' in request.GET:
372 employes = employes.order_by(
373 ('-' if request.GET.get('ot') == "desc" else '') + request.GET['o']
374 )
375
376 employes = employes.filter(**lookup_params)
377
378 output = []
379 headers = [
380 ("id", u"# de l'employé"),
381 ("nom", u"Nom"),
382 ("prenom", u"Prénom"),
383 ("", u"Salaire"),
384 ("", u"RAS"),
385 ("", u"Indemnités"),
386 ("", u"Accessoire"),
387 ("", u"Charges patronales"),
388 ("", u"Total"),
389 ]
390 h = SortHeaders(request, headers, order_field_type="ot", order_field="o")
391
392 for employe in employes:
393 line = {}
394 output.append(line)
395
396 dossiers = employe.rh_dossiers.all()
397
398 remun = {}
399 remun_sum_euro = 0
400
401 for dossier in dossiers:
402 this_remun, this_remun_sum, this_remun_sum_euro = \
403 calc_remun(dossier)
404
405 for item in this_remun:
406 if item not in remun:
407 remun[item] = this_remun[item]
408 else:
409 remun[item][0] += this_remun[item][0]
410 remun[item][1] += this_remun[item][1]
411
412 remun_sum_euro += this_remun_sum_euro
413
414 line['remun_sum_euro'] = remun_sum_euro
415
416 for r in remun:
417 if r == u'Indemnité':
418 line['Indemnite'] = remun[r][1]
419 else:
420 line[r] = remun[r][1]
421
422 line['id'] = employe.id
423 line['nom'] = employe.nom
424 line['prenom'] = employe.prenom
425
426 c = {
427 'title': 'Rapport de remuneration',
428 'employes': output,
429 'headers': list(h.headers()),
430 }
431
432 return render_to_response(
433 'rh/rapports/remuneration.html', c, RequestContext(request)
434 )
435
436
437 @login_required
438 @drh_or_admin_required
439 def rapports_employe_sans_contrat(request):
440
441 lookup_params = dict(request.GET.items())
442 if 'ot' in lookup_params:
443 del lookup_params['ot']
444 if 'o' in lookup_params:
445 del lookup_params['o']
446
447 for key, value in lookup_params.items():
448 if not isinstance(key, str):
449 # 'key' will be used as a keyword argument later, so Python
450 # requires it to be a string.
451 del lookup_params[key]
452 lookup_params[smart_str(key)] = value
453
454 employes_query = rh.Employe.objects
455 if 'o' in request.GET:
456 employes_query = employes_query.order_by(
457 ('-' if request.GET.get('ot') == "desc" else '') + request.GET['o']
458 )
459
460 employes = {}
461
462 dossiers_en_cours = rh.Dossier.objects.filter(
463 Q(date_fin=None) | Q(date_fin__gt=date.today())
464 )
465 tous_contrats_echus = rh.Contrat.objects.filter(
466 date_fin__lt=date.today(), dossier__in=dossiers_en_cours
467 )
468 contrats = tous_contrats_echus.filter(**lookup_params).all()
469 for c in contrats:
470 if c.dossier.employe.id not in employes.keys():
471 employes[c.dossier.employe.id] = {
472 'employe': c.dossier.employe,
473 'dossiers': []
474 }
475 employes[c.dossier.employe.id]['dossiers'] += [c.dossier]
476
477 headers = [
478 ("id", u"# de l'employé"),
479 ("nom", u"Nom"),
480 ("prenom", u"Prénom"),
481 ("dossier", u"Dossiers"),
482 ]
483 h = SortHeaders(
484 request, headers, order_field_type="ot", order_field="o",
485 not_sortable=('dossier',)
486 )
487
488 c = {
489 'title': u'Rapport des employés sans contrat',
490 'employes': employes,
491 'count': len(employes),
492 'headers': list(h.headers()),
493 }
494
495 return render_to_response(
496 'rh/rapports/employes_sans_contrat.html', c, RequestContext(request)
497 )
498
499
500 @login_required
501 @drh_or_admin_required
502 def rapports_postes_modelisation(request):
503 c = {}
504 data = []
505
506 for categorie in rh.CategorieEmploi.objects.all():
507 types = rh.TypePoste.objects.filter(categorie_emploi=categorie)
508 data_types = []
509 for t in types.all():
510 postes = rh.Poste.objects.filter(type_poste=t)
511 data_types.append({
512 'num_postes': postes.count(),
513 'postes': postes.all(),
514 'type': categorie,
515 })
516
517 data.append({
518 'categorie': categorie,
519 'nb_types': types.count(),
520 'types': data_types
521 })
522
523 c['data'] = data
524
525 return render_to_response(
526 'rh/rapports/postes_modelisation.html', c, RequestContext(request)
527 )
528
529
530 @login_required
531 @drh_or_admin_required
532 def rapports_postes_implantation(request):
533 c = {}
534 data = []
535 for r in ref.Region.objects.all():
536 implantations = []
537 for i in ref.Implantation.objects.filter(region=r):
538 implantations.append({
539 'implantation': i,
540 'postes': rh.Poste.objects.filter(implantation=i),
541 'num_postes': rh.Poste.objects.filter(implantation=i).count(),
542 })
543 data.append({
544 'region': r,
545 'implantations': implantations
546 })
547
548 c['data'] = data
549
550 return render_to_response(
551 'rh/rapports/postes_implantation.html', c, RequestContext(request)
552 )
553
554
555 @login_required
556 @drh_or_admin_required
557 def rapports_postes_service(request):
558 c = {}
559 data = []
560 for s in rh.Service.objects.all():
561 postes = rh.Poste.objects.filter(service=s).all()
562 num_postes = rh.Poste.objects.filter(service=s).count()
563 data.append({'service': s, 'num_postes': num_postes, 'postes': postes})
564
565 c['data'] = data
566 return render_to_response(
567 'rh/rapports/postes_service.html', c, RequestContext(request)
568 )
569
570
571 def region_protected(model):
572 def wrapper(func):
573 def wrapped(request, id):
574 if request.user.is_superuser:
575 return func(request, id)
576 user_groups = request.user.groups.all()
577 if grp_drh in user_groups:
578 return func(request, id)
579 if grp_correspondants_rh in user_groups:
580 employe = get_employe_from_user(request.user)
581 q = Q(**{
582 model.prefix_implantation: employe.implantation.region
583 })
584 qs = model.objects.filter(q)
585 if int(id) in [o.id for o in qs]:
586 return func(request, id)
587 return redirect_interdiction(request)
588 return wrapped
589 return wrapper
590
591
592 @region_protected(rh.Dossier)
593 def dossier_apercu(request, dossier_id):
594 d = get_object_or_404(rh.Dossier, pk=dossier_id)
595 c = {
596 'title': u"Dossier %s" % (d, ),
597 'is_popup': request.GET.get('_popup', False),
598 'dossier': d,
599 'pieces': rh.DossierPiece.objects.filter(dossier__exact=d),
600 'contrats': rh.Contrat.objects.filter(dossier__exact=d),
601 'commentaires': rh.DossierCommentaire.objects.filter(dossier=d).all(),
602 'media_url': settings.PRIVE_MEDIA_URL,
603 }
604 return render_to_response(
605 'admin/rh/dossier/apercu.html', c, RequestContext(request)
606 )
607
608
609 @region_protected(rh.Poste)
610 def poste_apercu(request, poste_id):
611 p = get_object_or_404(rh.Poste, pk=poste_id)
612 c = {
613 'title': u"Poste %s" % (p, ),
614 'is_popup': request.GET.get('_popup', False),
615 'poste': p,
616 'financements': (
617 rh.PosteFinancement.objects.filter(poste=poste_id).all()
618 ),
619 'pieces': rh.PostePiece.objects.filter(poste=poste_id).all(),
620 'dossiers': (
621 rh.Dossier.objects.filter(poste=poste_id)
622 .order_by("-date_debut").all()
623 ),
624 'comparaisons': (
625 rh.PosteComparaison.objects.filter(poste=poste_id).all()
626 ),
627 'commentaires': (
628 rh.PosteCommentaire.objects.filter(poste=poste_id).all()
629 ),
630 'media_url': settings.PRIVE_MEDIA_URL,
631 }
632 return render_to_response(
633 'admin/rh/poste/apercu.html', c, RequestContext(request)
634 )
635
636
637 def employe_apercu(request, employe_id):
638 employe = get_object_or_404(rh.Employe, pk=employe_id)
639 user_groups = request.user.groups.all()
640 dossiers = None
641
642 if request.user.is_superuser or \
643 grp_drh in user_groups:
644 q = Q(employe=employe)
645 if grp_correspondants_rh in user_groups:
646 regions = [
647 d.poste.implantation.region for d in employe.rh_dossiers.all()
648 ]
649 q = Q(employe=employe) & Q(implantation__region__in=regions)
650
651 dossiers = rh.Dossier.objects.filter(q).order_by('-date_debut')
652
653 c = {
654 'title': u"Employe %s" % (employe, ),
655 'is_popup': request.GET.get('_popup', False),
656 'employe': employe,
657 'dossiers': dossiers,
658 'media_url': settings.PRIVE_MEDIA_URL,
659 }
660 return render_to_response(
661 'admin/rh/employe/apercu.html', c, RequestContext(request)
662 )
663
664
665 @login_required
666 @drh_or_admin_required
667 def organigrammes_employe(request, id, level="all"):
668
669 poste = get_object_or_404(rh.Poste, pk=id)
670 dossiers_by_poste = dict(
671 (d.poste_id, d)
672 for d in rh.Dossier.objects.select_related('employe', 'poste').all()
673 )
674 postes_by_id = dict((p.id, p) for p in rh.Poste.objects.all())
675
676 e = dossiers_by_poste[poste.id].employe
677 name = u"Organigramme de [%s] %s %s" % (e.id, e.nom.upper(), e.prenom)
678 graph = pgv.AGraph()
679
680 if rh.Poste.objects.filter(responsable=poste).count() > 0:
681 postes_handle = [poste]
682 while postes_handle:
683 postes_handle = rh.Poste.objects.select_related('implantation') \
684 .filter(
685 Q(date_fin__gt=date.today()) | Q(date_fin=None),
686 Q(date_debut__lt=date.today()) | Q(date_debut=None),
687 responsable__in=postes_handle
688 ).exclude(supprime=True).exclude(responsable=None).all()
689
690 for p in postes_handle:
691 if p.responsable_id != p.id:
692 graph.add_edge(
693 dossiers_by_poste[p.responsable_id].poste_id, p.id
694 )
695
696 else:
697 graph.add_node(poste.id)
698
699 if level != "all":
700 postes_niveau = [poste.id]
701 for niveau in range(int(level)):
702 postes_niveau = [
703 p.id for p in
704 rh.Poste.objects.filter(responsable__in=postes_niveau).all()
705 ]
706
707 while postes_niveau:
708 postes_niveau = [
709 p.id for p in
710 rh.Poste.objects.filter(responsable__in=postes_niveau).all()
711 ]
712 if postes_niveau:
713 for p in postes_niveau:
714 if graph.has_node(p):
715 graph.delete_node(p)
716
717 a = graph
718 a.name = name.encode('ascii', 'xmlcharrefreplace')
719
720 poste_remontant = poste
721 while poste_remontant.responsable_id:
722 a.add_edge(poste_remontant.responsable_id, poste_remontant.id)
723 poste_remontant = poste_remontant.responsable
724
725 rh_graph.bind_poste_to_graph(a, postes_by_id)
726 #a.graph_attr['normalize'] = True
727 #a.graph_attr['level'] = 2
728 a.layout(prog='dot')
729
730 svg = a.draw(format='svg')
731
732 c = {
733 'svg': svg
734 }
735
736 if 'forcer' in request.GET:
737 response = HttpResponse(svg, mimetype='image/svg+xml')
738 response['Content-Disposition'] = \
739 'attachment; filename=organigramme.svg'
740 return response
741
742 return render_to_response(
743 'rh/organigrammes/employe.html', c, RequestContext(request),
744 mimetype="image/svg+xml"
745 )
746
747
748 @login_required
749 @drh_or_admin_required
750 def organigrammes_service(request, id):
751
752 service = get_object_or_404(rh.Service, pk=id)
753 svg = rh_graph.organigramme_postes_cluster( \
754 cluster_filter={"service": service}, \
755 titre=u"Organigramme du service %s" % service.nom,
756 cluster_titre=service.nom)
757
758 c = {
759 'svg': svg
760 }
761
762 return render_to_response(
763 'rh/organigrammes/vide.html', c, RequestContext(request),
764 mimetype="image/svg+xml"
765 )
766
767
768 @login_required
769 @drh_or_admin_required
770 def organigrammes_implantation(request, id):
771
772 implantation = get_object_or_404(ref.Implantation, pk=id)
773 svg = rh_graph.organigramme_postes_cluster( \
774 cluster_filter={"implantation": implantation}, \
775 titre=u"Organigramme de l'implantation %s" % implantation.nom,
776 cluster_titre=implantation.nom)
777
778 c = {
779 'svg': svg
780 }
781
782 return render_to_response(
783 'rh/organigrammes/vide.html', c, RequestContext(request),
784 mimetype="image/svg+xml"
785 )
786
787
788 @login_required
789 @drh_or_admin_required
790 def organigrammes_region(request, id):
791
792 region = get_object_or_404(ref.Region, pk=id)
793 svg = rh_graph.organigramme_postes_cluster( \
794 cluster_filter={"implantation__region": region}, \
795 titre=u"Organigramme du bureau de %s" % region.nom,
796 cluster_titre=region.nom)
797
798 c = {
799 'svg': svg
800 }
801
802 return render_to_response(
803 'rh/organigrammes/vide.html', c, RequestContext(request),
804 mimetype="image/svg+xml"
805 )