1 # -*- encoding: utf-8 -*-
4 from datetime
import date
5 from itertools
import izip
8 import pygraphviz
as pgv
9 from datamaster_modeles
import models
as ref
10 from django
.core
.urlresolvers
import reverse
11 from django
.db
.models
import Q
12 from django
.utils
.encoding
import smart_str
13 from django
.shortcuts
import render_to_response
, get_object_or_404
14 from django
.template
import RequestContext
15 from django
.http
import HttpResponse
16 from django
import forms
17 from django
.contrib
.auth
.decorators
import login_required
18 from django
.core
.servers
.basehttp
import FileWrapper
20 from rh
import models
as rh
21 from rh
.lib
import calc_remun
22 from project
.rh
.decorators
import drh_or_admin_required
, in_one_of_group
23 from rh
.templatetags
.rapports
import SortHeaders
24 from rh
.change_list
import RechercheTemporelle
25 from rh
import graph
as rh_graph
26 from rh
.masse_salariale
import MasseSalariale
28 # pas de reference a DAE devrait etre refactorisé
29 from dae
.utils
import get_employe_from_user
30 from dae
.decorators
import redirect_interdiction
31 from django
.conf
import settings
32 from project
.rh
.decorators
import in_drh_or_admin
33 from project
.rh
import groups
38 """Profil personnel de l'employé - éditable"""
39 rc
= RequestContext(request
)
42 employe
= rc
['this_employe']
44 c
['user'] = request
.user
45 c
['employe'] = employe
46 return render_to_response('rh/profil.html', c
, rc
)
50 def employes_liste(request
):
51 """Liste des employés."""
53 employes
= rh
.Employe
.objects \
54 .exclude(dossiers__date_debut__gt
=today
) \
55 .exclude(dossiers__date_fin__lt
=today
) \
61 return render_to_response('rh/employes_liste.html',
63 RequestContext(request
))
67 def employe(request
, id):
68 """Information publique sur un employé."""
70 employe
= rh
.Employe
.objects
.get(pk
=id)
72 employe
= rh
.Employe
.objects
.none()
77 return render_to_response('rh/employe.html', c
, RequestContext(request
))
81 @drh_or_admin_required
82 def rapports_poste(request
):
84 lookup_params
= dict(request
.GET
.items())
86 for key
, value
in lookup_params
.items():
87 if key
== 'o' or key
== 'ot':
88 del lookup_params
[key
]
90 if not isinstance(key
, str):
91 # 'key' will be used as a keyword argument later, so Python
92 # requires it to be a string.
93 del lookup_params
[key
]
94 lookup_params
[smart_str(key
)] = value
97 del lookup_params
[key
]
99 sort_order
= 'ASC' if request
.GET
.get('ot') == 'asc' else 'DESC'
101 postes
= rh
.Poste
.objects
.select_related('implantation') \
104 'SELECT GROUP_CONCAT(employe SEPARATOR "|") '
106 'WHERE poste = rh_poste.id '
107 'AND rh_dossier.date_fin IS NULL ' + (
108 'ORDER BY employe ' + sort_order
109 if request
.GET
.get('o') == 'employe_id' else ''
114 'SELECT GROUP_CONCAT(rh_employe.nom SEPARATOR "|") '
115 'FROM rh_dossier INNER JOIN rh_employe '
116 'ON rh_dossier.employe = rh_employe.id '
117 'WHERE poste = rh_poste.id '
118 'AND rh_dossier.date_fin IS NULL ' + (
119 'ORDER BY rh_employe.nom ' + sort_order
120 if request
.GET
.get('o') == 'employe_nom' else ''
125 'SELECT GROUP_CONCAT(rh_employe.prenom SEPARATOR "|") '
126 'FROM rh_dossier INNER JOIN rh_employe '
127 'ON rh_dossier.employe = rh_employe.id '
128 'WHERE poste = rh_poste.id '
129 'AND rh_dossier.date_fin IS NULL ' + (
130 'ORDER BY rh_employe.prenom ' + sort_order
131 if request
.GET
.get('o') == 'employe_prenom' else ''
135 postes
= postes
.filter(**lookup_params
)
136 if 'o' in request
.GET
:
137 postes
= postes
.order_by(
138 ('-' if sort_order
== "DESC" else '') + request
.GET
['o']
146 'implantation': p
.implantation
,
147 'employes': [] if not p
.employe_id
else [
148 {'id': id, 'nom': nom
, 'prenom': prenom
}
149 for id, nom
, prenom
in izip(
150 p
.employe_id
.split('|'),
151 p
.employe_nom
.split('|'),
152 p
.employe_prenom
.split('|')
158 ("id", u
"# du poste"),
159 ("nom", u
"Nom du poste"),
160 ("implantation__id", u
"Implantation"),
161 ("employe_nom", u
"Nom"),
163 h
= SortHeaders(request
, headers
, order_field_type
="ot", order_field
="o")
165 'title': 'Rapport des postes',
168 'headers': list(h
.headers()),
171 return render_to_response(
172 'rh/rapports/postes.html', c
, RequestContext(request
)
177 @in_one_of_group((groups
.grp_correspondants_rh
,
178 groups
.grp_administrateurs
,
179 groups
.grp_directeurs_bureau
,
182 def rapports_contrat(request
):
183 if 'HTTP_REFERER' in request
.META
.keys():
184 referer
= request
.META
['HTTP_REFERER']
185 referer
= "/".join(referer
.split('/')[3:])
186 referer
= "/%s" % referer
.split('?')[0]
187 if referer
!= reverse('rhr_contrats'):
188 params
= request
.GET
.copy()
189 params
.update({'statut': 'Actif'})
192 lookup_params
= dict(request
.GET
.items())
193 if 'ot' in lookup_params
:
194 del lookup_params
['ot']
195 if 'o' in lookup_params
:
196 del lookup_params
['o']
198 for key
, value
in lookup_params
.items():
199 if not isinstance(key
, str):
200 # 'key' will be used as a keyword argument later, so Python
201 # requires it to be a string.
202 del lookup_params
[key
]
203 lookup_params
[smart_str(key
)] = value
205 contrats
= rh
.Contrat
.objects
.select_related(
206 'dossier', 'dossier__poste', 'dossier__poste__implantation',
207 'type_contrat', 'dossier__employe'
210 cl
= RechercheTemporelle(dict(request
.GET
.items()), rh
.Contrat
)
211 lookup_params
= cl
.purge_params(lookup_params
)
212 q_temporel
= cl
.get_q_temporel(contrats
)
213 q
= Q(**lookup_params
) & q_temporel
214 user_groups
= request
.user
.groups
.all()
215 if groups
.grp_correspondants_rh
in user_groups
or\
216 groups
.grp_administrateurs
in user_groups
or\
217 groups
.grp_directeurs_bureau
in user_groups
:
218 employe
= get_employe_from_user(request
.user
)
219 q
= q
& Q(dossier__poste__implantation__region
=employe
.implantation
.region
)
221 contrats
= contrats
.filter(q
).exclude(dossier__employe__supprime
=1)
223 if 'o' in request
.GET
:
224 contrats
= contrats
.order_by(
225 ('-' if request
.GET
.get('ot') == "desc" else '') + request
.GET
['o']
228 employes
= set([c
.dossier
.employe_id
for c
in contrats
])
231 ("dossier__employe__id", u
"# de l'employé"),
232 ("dossier__employe__nom", u
"Employé"),
233 ("type_contrat__nom", u
"Poste"),
234 ("dossier__poste__implantation__region", u
"Région"),
235 ("dossier__poste__implantation", u
"Implantation"),
236 ("type_contrat__nom", u
"Type de contrat"),
237 ("date_debut", u
"Date début"),
238 ("date_fin", u
"Date fin"),
240 h
= SortHeaders(request
, headers
, order_field_type
="ot", order_field
="o")
244 'title': 'Rapport des contrats',
245 'contrats': contrats
,
246 'count': len(contrats
),
247 'count_employe': len(employes
),
248 'headers': list(h
.headers()),
251 return render_to_response(
252 'rh/rapports/contrats.html', c
, RequestContext(request
)
257 @in_one_of_group((groups
.grp_correspondants_rh
,
258 groups
.grp_administrateurs
,
259 groups
.grp_directeurs_bureau
,
262 def rapports_masse_salariale(request
):
264 class RechercheTemporelle(forms
.Form
):
265 remunerations
= rh
.Remuneration
.objects
.exclude(date_debut
=None)
266 if len(remunerations
) > 0:
267 annee_debut
= remunerations
.order_by('date_debut')[0].date_debut
.year
270 CHOICE_ANNEES
= range(annee_debut
, date
.today().year
+ 1)
272 annee
= forms
.CharField(
273 initial
=date
.today().year
,
275 choices
=((a
, a
) for a
in reversed(CHOICE_ANNEES
))
279 user_groups
= request
.user
.groups
.all()
280 if groups
.grp_correspondants_rh
in user_groups
or\
281 groups
.grp_administrateurs
in user_groups
or\
282 groups
.grp_directeurs_bureau
in user_groups
:
283 employe
= get_employe_from_user(request
.user
)
284 regions
= ref
.Region
.objects
.filter(id=employe
.implantation
.region
.id)
285 implantations
= ref
.Implantation
.objects
.filter(region
=employe
.implantation
.region
)
287 regions
= ref
.Region
.objects
.all()
288 implantations
= ref
.Implantation
.objects
.all()
290 region
= forms
.CharField(
291 widget
=forms
.Select(choices
=[('', '')] +
292 [(i
.id, i
) for i
in regions
]
296 implantation
= forms
.CharField(
297 widget
=forms
.Select(choices
=[('', '')] +
298 [(i
.id, i
) for i
in implantations
]
302 #date_debut = forms.DateField(widget=adminwidgets.AdminDateWidget)
303 #date_fin = forms.DateField(widget=adminwidgets.AdminDateWidget)
305 form
= RechercheTemporelle(request
.GET
)
307 (k
, v
) for k
, v
in request
.GET
.items()
308 if k
not in ('date_debut', 'date_fin', 'implantation')
310 query_string
= urllib
.urlencode(get_filtre
)
314 if request
.GET
.get('annee', None):
315 date_debut
= "01-01-%s" % request
.GET
.get('annee', None)
316 date_fin
= "31-12-%s" % request
.GET
.get('annee', None)
318 implantation
= request
.GET
.get('implantation')
319 region
= request
.GET
.get('region')
323 custom_filter
['dossier__poste__implantation'] = implantation
325 custom_filter
['dossier__poste__implantation__region'] = region
327 # on force la région dans tous les cas pour les membres de ce groupe
328 user_groups
= request
.user
.groups
.all()
329 if groups
.grp_correspondants_rh
in user_groups
or\
330 groups
.grp_administrateurs
in user_groups
or\
331 groups
.grp_directeurs_bureau
in user_groups
:
332 employe
= get_employe_from_user(request
.user
)
333 custom_filter
['dossier__poste__implantation__region'] = employe
.implantation
.region
.id
337 'title': 'Rapport de masse salariale',
340 'query_string': query_string
,
342 if date_debut
or date_fin
:
343 masse
= MasseSalariale(date_debut
, date_fin
, custom_filter
,
344 request
.GET
.get('ne_pas_grouper', False))
346 if request
.GET
.get('ods'):
348 h
for h
in masse
.headers
if 'background-color' in h
[2]
350 del h
[2]['background-color']
352 output
= StringIO
.StringIO()
353 masse
.doc
.save(output
)
356 response
= HttpResponse(
359 'application/vnd.oasis.opendocument.spreadsheet'
362 response
['Content-Disposition'] = \
363 'attachment; filename=Masse Salariale %s.ods' % \
367 c
['rapport'] = masse
.rapport
368 c
['header_keys'] = [h
[0] for h
in masse
.headers
]
369 #on enleve le background pour le header
371 h
for h
in masse
.headers
if 'background-color' in h
[2]
373 h
[2]['background'] = 'none'
374 h
= SortHeaders(request
, masse
.headers
, order_field_type
="ot",
375 not_sortable
=c
['header_keys'], order_field
="o")
376 c
['headers'] = list(h
.headers())
377 for key
, nom
, opts
in masse
.headers
:
379 c
['total'] = masse
.grand_totaux
[0]
380 c
['total_euro'] = masse
.grand_totaux
[1]
381 c
['colspan'] = len(c
['header_keys']) - 1
382 get_filtre
.append(('ods', True))
383 query_string
= urllib
.urlencode(get_filtre
)
384 c
['url_ods'] = "%s?%s" % (
385 reverse('rhr_masse_salariale'), query_string
)
387 return render_to_response(
388 'rh/rapports/masse_salariale.html', c
, RequestContext(request
)
393 @drh_or_admin_required
394 def rapports_remuneration(request
):
396 lookup_params
= dict(request
.GET
.items())
397 if 'ot' in lookup_params
:
398 del lookup_params
['ot']
399 if 'o' in lookup_params
:
400 del lookup_params
['o']
402 for key
, value
in lookup_params
.items():
403 if not isinstance(key
, str):
404 # 'key' will be used as a keyword argument later, so Python
405 # requires it to be a string.
406 del lookup_params
[key
]
407 lookup_params
[smart_str(key
)] = value
409 employes
= rh
.Employe
.objects
.all()
410 if 'o' in request
.GET
:
411 employes
= employes
.order_by(
412 ('-' if request
.GET
.get('ot') == "desc" else '') + request
.GET
['o']
415 employes
= employes
.filter(**lookup_params
)
419 ("id", u
"# de l'employé"),
421 ("prenom", u
"Prénom"),
426 ("", u
"Charges patronales"),
429 h
= SortHeaders(request
, headers
, order_field_type
="ot", order_field
="o")
431 for employe
in employes
:
435 dossiers
= employe
.rh_dossiers
.all()
440 for dossier
in dossiers
:
441 this_remun
, this_remun_sum
, this_remun_sum_euro
= \
444 for item
in this_remun
:
445 if item
not in remun
:
446 remun
[item
] = this_remun
[item
]
448 remun
[item
][0] += this_remun
[item
][0]
449 remun
[item
][1] += this_remun
[item
][1]
451 remun_sum_euro
+= this_remun_sum_euro
453 line
['remun_sum_euro'] = remun_sum_euro
456 if r
== u
'Indemnité':
457 line
['Indemnite'] = remun
[r
][1]
459 line
[r
] = remun
[r
][1]
461 line
['id'] = employe
.id
462 line
['nom'] = employe
.nom
463 line
['prenom'] = employe
.prenom
466 'title': 'Rapport de remuneration',
468 'headers': list(h
.headers()),
471 return render_to_response(
472 'rh/rapports/remuneration.html', c
, RequestContext(request
)
477 @drh_or_admin_required
478 def rapports_employe_sans_contrat(request
):
480 lookup_params
= dict(request
.GET
.items())
481 if 'ot' in lookup_params
:
482 del lookup_params
['ot']
483 if 'o' in lookup_params
:
484 del lookup_params
['o']
486 for key
, value
in lookup_params
.items():
487 if not isinstance(key
, str):
488 # 'key' will be used as a keyword argument later, so Python
489 # requires it to be a string.
490 del lookup_params
[key
]
491 lookup_params
[smart_str(key
)] = value
493 employes_query
= rh
.Employe
.objects
494 if 'o' in request
.GET
:
495 employes_query
= employes_query
.order_by(
496 ('-' if request
.GET
.get('ot') == "desc" else '') + request
.GET
['o']
501 dossiers_en_cours
= rh
.Dossier
.objects
.filter(
502 Q(date_fin
=None) |
Q(date_fin__gt
=date
.today())
504 tous_contrats_echus
= rh
.Contrat
.objects
.filter(
505 date_fin__lt
=date
.today(), dossier__in
=dossiers_en_cours
507 contrats
= tous_contrats_echus
.filter(**lookup_params
).all()
509 if c
.dossier
.employe
.id not in employes
.keys():
510 employes
[c
.dossier
.employe
.id] = {
511 'employe': c
.dossier
.employe
,
514 employes
[c
.dossier
.employe
.id]['dossiers'] += [c
.dossier
]
517 ("id", u
"# de l'employé"),
519 ("prenom", u
"Prénom"),
520 ("dossier", u
"Dossiers"),
523 request
, headers
, order_field_type
="ot", order_field
="o",
524 not_sortable
=('dossier',)
528 'title': u
'Rapport des employés sans contrat',
529 'employes': employes
,
530 'count': len(employes
),
531 'headers': list(h
.headers()),
534 return render_to_response(
535 'rh/rapports/employes_sans_contrat.html', c
, RequestContext(request
)
540 @drh_or_admin_required
541 def rapports_postes_modelisation(request
):
545 for categorie
in rh
.CategorieEmploi
.objects
.all():
546 types
= rh
.TypePoste
.objects
.filter(categorie_emploi
=categorie
)
548 for t
in types
.all():
549 postes
= rh
.Poste
.objects
.filter(type_poste
=t
)
551 'num_postes': postes
.count(),
552 'postes': postes
.all(),
557 'categorie': categorie
,
558 'nb_types': types
.count(),
564 return render_to_response(
565 'rh/rapports/postes_modelisation.html', c
, RequestContext(request
)
570 @drh_or_admin_required
571 def rapports_postes_implantation(request
):
574 for r
in ref
.Region
.objects
.all():
576 for i
in ref
.Implantation
.objects
.filter(region
=r
):
577 implantations
.append({
579 'postes': rh
.Poste
.objects
.filter(implantation
=i
),
580 'num_postes': rh
.Poste
.objects
.filter(implantation
=i
).count(),
584 'implantations': implantations
589 return render_to_response(
590 'rh/rapports/postes_implantation.html', c
, RequestContext(request
)
595 @drh_or_admin_required
596 def rapports_postes_service(request
):
599 for s
in rh
.Service
.objects
.all():
600 postes
= rh
.Poste
.objects
.filter(service
=s
).all()
601 num_postes
= rh
.Poste
.objects
.filter(service
=s
).count()
602 data
.append({'service': s
, 'num_postes': num_postes
, 'postes': postes
})
605 return render_to_response(
606 'rh/rapports/postes_service.html', c
, RequestContext(request
)
610 def region_protected(model
):
612 def wrapped(request
, id):
613 if request
.user
.is_superuser
:
614 return func(request
, id)
615 user_groups
= request
.user
.groups
.all()
616 if in_drh_or_admin(request
.user
):
617 return func(request
, id)
618 if groups
.grp_correspondants_rh
in user_groups
or\
619 groups
.grp_administrateurs
in user_groups
or\
620 groups
.grp_directeurs_bureau
in user_groups
:
621 employe
= get_employe_from_user(request
.user
)
623 model
.prefix_implantation
: employe
.implantation
.region
625 qs
= model
.objects
.filter(q
)
626 if int(id) in [o
.id for o
in qs
]:
627 return func(request
, id)
628 return redirect_interdiction(request
)
633 @region_protected(rh
.Dossier
)
634 def dossier_apercu(request
, dossier_id
):
635 d
= get_object_or_404(rh
.Dossier
, pk
=dossier_id
)
637 'title': u
"Dossier %s" % (d
, ),
638 'is_popup': request
.GET
.get('_popup', False),
640 'pieces': rh
.DossierPiece
.objects
.filter(dossier__exact
=d
),
641 'contrats': rh
.Contrat
.objects
.filter(dossier__exact
=d
),
642 'commentaires': rh
.DossierCommentaire
.objects
.filter(dossier
=d
).all(),
643 'media_url': settings
.PRIVE_MEDIA_URL
,
645 return render_to_response(
646 'admin/rh/dossier/apercu.html', c
, RequestContext(request
)
650 @region_protected(rh
.Poste
)
651 def poste_apercu(request
, poste_id
):
652 p
= get_object_or_404(rh
.Poste
, pk
=poste_id
)
654 'title': u
"Poste %s" % (p
, ),
655 'is_popup': request
.GET
.get('_popup', False),
658 rh
.PosteFinancement
.objects
.filter(poste
=poste_id
).all()
660 'pieces': rh
.PostePiece
.objects
.filter(poste
=poste_id
).all(),
662 rh
.Dossier
.objects
.filter(poste
=poste_id
)
663 .order_by("-date_debut").all()
666 rh
.PosteComparaison
.objects
.filter(poste
=poste_id
).all()
669 rh
.PosteCommentaire
.objects
.filter(poste
=poste_id
).all()
671 'media_url': settings
.PRIVE_MEDIA_URL
,
673 return render_to_response(
674 'admin/rh/poste/apercu.html', c
, RequestContext(request
)
678 def employe_apercu(request
, employe_id
):
679 employe
= get_object_or_404(rh
.Employe
, pk
=employe_id
)
680 user_groups
= request
.user
.groups
.all()
683 if in_drh_or_admin(request
.user
):
684 q
= Q(employe
=employe
)
686 if groups
.grp_correspondants_rh
in user_groups
or\
687 groups
.grp_administrateurs
in user_groups
or\
688 groups
.grp_directeurs_bureau
in user_groups
:
689 employe_connecte
= get_employe_from_user(request
.user
)
690 q
= Q(employe
=employe
) & Q(poste__implantation__region
=employe_connecte
.implantation
.region
)
692 dossiers
= rh
.Dossier
.objects
.filter(q
).order_by('-date_debut')
695 'title': u
"Employe %s" % (employe
, ),
696 'is_popup': request
.GET
.get('_popup', False),
698 'dossiers': dossiers
,
699 'media_url': settings
.PRIVE_MEDIA_URL
,
701 return render_to_response(
702 'admin/rh/employe/apercu.html', c
, RequestContext(request
)
707 @drh_or_admin_required
708 def organigrammes_employe(request
, id, level
="all"):
710 poste
= get_object_or_404(rh
.Poste
, pk
=id)
711 dossiers_by_poste
= dict(
713 for d
in rh
.Dossier
.objects
.select_related('employe', 'poste').all()
715 postes_by_id
= dict((p
.id, p
) for p
in rh
.Poste
.objects
.all())
717 e
= dossiers_by_poste
[poste
.id].employe
718 name
= u
"Organigramme de [%s] %s %s" % (e
.id, e
.nom
.upper(), e
.prenom
)
721 if rh
.Poste
.objects
.filter(responsable
=poste
).count() > 0:
722 postes_handle
= [poste
]
724 postes_handle
= rh
.Poste
.objects
.select_related('implantation') \
726 Q(date_fin__gt
=date
.today()) |
Q(date_fin
=None),
727 Q(date_debut__lt
=date
.today()) |
Q(date_debut
=None),
728 responsable__in
=postes_handle
729 ).exclude(supprime
=True).exclude(responsable
=None).all()
731 for p
in postes_handle
:
732 if p
.responsable_id
!= p
.id:
734 dossiers_by_poste
[p
.responsable_id
].poste_id
, p
.id
738 graph
.add_node(poste
.id)
741 postes_niveau
= [poste
.id]
742 for niveau
in range(int(level
)):
745 rh
.Poste
.objects
.filter(responsable__in
=postes_niveau
).all()
751 rh
.Poste
.objects
.filter(responsable__in
=postes_niveau
).all()
754 for p
in postes_niveau
:
755 if graph
.has_node(p
):
759 a
.name
= name
.encode('ascii', 'xmlcharrefreplace')
761 poste_remontant
= poste
762 while poste_remontant
.responsable_id
:
763 a
.add_edge(poste_remontant
.responsable_id
, poste_remontant
.id)
764 poste_remontant
= poste_remontant
.responsable
766 rh_graph
.bind_poste_to_graph(a
, postes_by_id
)
767 #a.graph_attr['normalize'] = True
768 #a.graph_attr['level'] = 2
771 svg
= a
.draw(format
='svg')
777 if 'forcer' in request
.GET
:
778 response
= HttpResponse(svg
, mimetype
='image/svg+xml')
779 response
['Content-Disposition'] = \
780 'attachment; filename=organigramme.svg'
783 return render_to_response(
784 'rh/organigrammes/employe.html', c
, RequestContext(request
),
785 mimetype
="image/svg+xml"
790 @drh_or_admin_required
791 def organigrammes_service(request
, id):
793 service
= get_object_or_404(rh
.Service
, pk
=id)
794 svg
= rh_graph
.organigramme_postes_cluster( \
795 cluster_filter
={"service": service
}, \
796 titre
=u
"Organigramme du service %s" % service
.nom
,
797 cluster_titre
=service
.nom
)
803 return render_to_response(
804 'rh/organigrammes/vide.html', c
, RequestContext(request
),
805 mimetype
="image/svg+xml"
810 @drh_or_admin_required
811 def organigrammes_implantation(request
, id):
813 implantation
= get_object_or_404(ref
.Implantation
, pk
=id)
814 svg
= rh_graph
.organigramme_postes_cluster( \
815 cluster_filter
={"implantation": implantation
}, \
816 titre
=u
"Organigramme de l'implantation %s" % implantation
.nom
,
817 cluster_titre
=implantation
.nom
)
823 return render_to_response(
824 'rh/organigrammes/vide.html', c
, RequestContext(request
),
825 mimetype
="image/svg+xml"
830 @drh_or_admin_required
831 def organigrammes_region(request
, id):
833 region
= get_object_or_404(ref
.Region
, pk
=id)
834 svg
= rh_graph
.organigramme_postes_cluster( \
835 cluster_filter
={"implantation__region": region
}, \
836 titre
=u
"Organigramme du bureau de %s" % region
.nom
,
837 cluster_titre
=region
.nom
)
843 return render_to_response(
844 'rh/organigrammes/vide.html', c
, RequestContext(request
),
845 mimetype
="image/svg+xml"