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