import models as rh
-class EmployeProxy(rh.Employe):
+class ServiceProxy(rh.Service):
+ """ Proxy utilisé pour les organigrammes opar service """
+ class Meta:
+ proxy = True
+ verbose_name = u"Organigramme par services"
+ verbose_name_plural = u"Organigramme par services"
+
+class EmployeProxy(rh.Employe):
+ """ Proxy utilisé pour les organigrammes des employés """
class Meta:
proxy = True
verbose_name = u"Organigramme des employés"
_date_modification.admin_order_field = 'date_modification'
+class ServiceProxyAdmin(ServiceAdmin):
+ list_display = ('nom', '_organigramme')
+ list_display_links = ('nom',)
+
+ def has_add_permission(self, obj):
+ return False
+
+ def _organigramme(self, obj):
+ return """<a href="%s">Organigramme</a>""" % (reverse('rho_service', args=(obj.id,)))
+ _organigramme.allow_tags = True
+ _organigramme.short_description = "Organigramme"
+
class StatutAdmin(AUFMetadataAdminMixin, admin.ModelAdmin):
list_display = ('code', 'nom', '_date_modification', 'user_modification', )
fieldsets = AUFMetadataAdminMixin.fieldsets + (
admin.site.register(rh.Devise, DeviseAdmin)
admin.site.register(rh.Dossier, DossierAdmin)
admin.site.register(EmployeProxy, EmployeProxyAdmin)
+admin.site.register(ServiceProxy, ServiceProxyAdmin)
admin.site.register(rh.Employe, EmployeAdmin)
admin.site.register(rh.FamilleEmploi, FamilleEmploiAdmin)
admin.site.register(rh.OrganismeBstg, OrganismeBstgAdmin)
--- /dev/null
+import unicodedata
+from datetime import date
+from django.db.models import Q
+from django.core.urlresolvers import reverse
+
+from rh import models as rh
+
+def bind_poste_to_graph(graph, postes_by_id):
+ for n in graph.nodes():
+ p = postes_by_id[int(n)]
+ try:
+ d = rh.Dossier.objects.select_related('employe').filter((Q(date_fin__gt=date.today()) | Q(date_fin=None)) & (Q(date_debut__lt=date.today()) | Q(date_debut=None)) & Q(poste=p)).exclude(supprime=True).all()[0]
+
+
+ label = u"%s\\n[%s] %s\\n%s" % (d.poste.nom, d.employe_id, "%s %s" %
+ (d.employe.nom.upper(), d.employe.prenom),
+ d.poste.implantation)
+ except IndexError:
+ label = u"%s\\n---\\n%s" % (d.poste.nom, d.poste.implantation)
+ n.attr['fillcolor'] = 'azure4'
+ n.attr['style'] = 'filled'
+
+ label = unicodedata.normalize('NFKD', label).encode('ascii','ignore')
+ n.attr['label'] = label
+ n.attr['href'] = reverse("admin:rh_employe_change", args=(d.employe_id,))
+
+ return graph
# -*- encoding: utf-8 -*-
-import unicodedata
from datetime import date
from itertools import izip
import networkx as nx
+import pygraphviz as pgv
from django.db.models import Q
from django.contrib.auth.decorators import login_required
from django.utils.encoding import smart_str
from django.shortcuts import render_to_response, get_object_or_404
from django.template import RequestContext
-from django.core.urlresolvers import reverse
from django.http import HttpResponse
from datamaster_modeles import models as ref
from rh.decorators import drh_or_admin_required
from rh.templatetags.rapports import SortHeaders
from rh.change_list import RechercheTemporelle
+from rh import graph as rh_graph
# pas de reference a DAE devrait etre refactorisé
from dae.utils import get_employe_from_user
def organigrammes_employe(request, id):
poste = get_object_or_404(rh.Poste, pk=id)
+ dossiers_by_poste = dict((d.poste_id, d) for d in rh.Dossier.objects.select_related('employe', 'poste').all())
+ postes_by_id = dict((p.id, p) for p in rh.Poste.objects.all())
+
+ e = dossiers_by_poste[poste.id].employe
+ name = u"Organigramme de [%s] %s %s" % (e.id, e.nom.upper(), e.prenom)
+ graph = nx.DiGraph(name=name)
+
if rh.Poste.objects.filter(responsable=poste).count() > 0:
- graph = nx.DiGraph()
postes = rh.Poste.objects.select_related('implantation').filter((Q(date_fin__gt=date.today()) | Q(date_fin=None)) & (Q(date_debut__lt=date.today()) | Q(date_debut=None)) ).exclude(supprime=True).exclude(responsable=None).all()
- dossiers_by_poste = dict((d.poste_id, d) for d in rh.Dossier.objects.select_related('employe', 'poste').all())
- postes_by_id = dict((p.id, p) for p in rh.Poste.objects.all())
for p in rh.Poste.objects.filter((Q(date_fin__gt=date.today()) | Q(date_fin=None)) & (Q(date_debut__lt=date.today()) | Q(date_debut=None)) ).exclude(supprime=True).exclude(responsable=None).all():
graph.add_node(p.id)
graph.add_edge(dossiers_by_poste[p.responsable_id].poste_id, p.id)
graph = nx.bfs_tree(graph, poste.id)
- a = nx.to_agraph(graph)
-
- poste_remontant = poste
- while poste_remontant.responsable_id:
- a.add_edge(poste_remontant.responsable_id, poste_remontant.id)
- poste_remontant = poste_remontant.responsable
-
- for n in a.nodes():
- p = postes_by_id[int(n)]
- try:
- d = rh.Dossier.objects.select_related('employe').filter((Q(date_fin__gt=date.today()) | Q(date_fin=None)) & (Q(date_debut__lt=date.today()) | Q(date_debut=None)) & Q(poste=p)).exclude(supprime=True).all()[0]
-
-
- label = u"%s\\n[%s] %s\\n%s" % (d.poste.nom, d.employe_id, "%s %s" %
- (d.employe.nom.upper(), d.employe.prenom),
- d.poste.implantation)
- except IndexError:
- label = u"%s\\n---\\n%s" % (d.poste.nom, d.poste.implantation)
- n.attr['fillcolor'] = 'azure4'
- n.attr['style'] = 'filled'
-
- label = unicodedata.normalize('NFKD', label).encode('ascii','ignore')
- n.attr['label'] = label
- n.attr['href'] = reverse("admin:rh_employe_change", args=(d.employe_id,))
-
- #a.graph_attr['normalize'] = True
- #a.graph_attr['level'] = 2
- a.layout(prog='dot')
-
- svg = a.draw(format='svg')
-
- c = {
- 'svg': svg
- }
else:
- c = {}
+ graph.add_node(poste.id)
+
+ a = nx.to_agraph(graph)
+
+ poste_remontant = poste
+ while poste_remontant.responsable_id:
+ a.add_edge(poste_remontant.responsable_id, poste_remontant.id)
+ poste_remontant = poste_remontant.responsable
+
+ rh_graph.bind_poste_to_graph(a, postes_by_id)
+ #a.graph_attr['normalize'] = True
+ #a.graph_attr['level'] = 2
+ a.layout(prog='dot')
+
+ svg = a.draw(format='svg')
+
+ c = {
+ 'svg': svg
+ }
if 'forcer' in request.GET:
response = HttpResponse(svg, mimetype='image/svg+xml')
return response
return render_to_response('rh/organigrammes/employe.html', c, RequestContext(request), mimetype="image/svg+xml")
+
+
+@login_required
+@drh_or_admin_required
+def organigrammes_service(request, id):
+
+ service = get_object_or_404(rh.Service, pk=id)
+
+ postes_by_id = dict((p.id, p) for p in rh.Poste.objects.all())
+
+ postes = rh.Poste.objects.select_related('implantation').filter((Q(date_fin__gt=date.today()) | Q(date_fin=None)) & (Q(date_debut__lt=date.today()) | Q(date_debut=None)) ).filter(service=service).exclude(supprime=True, responsable=None).all()
+
+ graph = pgv.AGraph(directed=True, name=u"Organigramme de « %s »" % service.nom)
+ graph_service = graph.subgraph(nbunch=[1,2], \
+ name="cluster1", \
+ style='filled', \
+ color='lightgrey', \
+ label=service.nom,
+ labeljust="l")
+
+ for p in postes:
+ graph_service.add_node(p.id)
+ if p.responsable_id:
+ graph.add_edge(p.responsable_id, p.id)
+
+ for p_id in graph_service.nodes():
+ if postes_by_id[int(p_id)].responsable_id:
+ poste_remontant = postes_by_id[int(p_id)]
+ while poste_remontant.responsable_id and poste_remontant.responsable_id and poste_remontant.responsable_id != poste_remontant.id:
+ poste_remontant = postes_by_id[poste_remontant.responsable_id]
+ if poste_remontant.responsable_id:
+ graph.add_edge(poste_remontant.responsable_id, poste_remontant.id)
+
+ rh_graph.bind_poste_to_graph(graph, postes_by_id)
+
+ graph.layout(prog='dot')
+
+ svg = graph.draw(format='svg')
+
+ c = {
+ 'svg': svg
+ }
+
+ if 'forcer' in request.GET:
+ response = HttpResponse(svg, mimetype='image/svg+xml')
+ response['Content-Disposition'] = 'attachment; filename=organigramme.svg'
+ return response
+
+ return render_to_response('rh/organigrammes/service.html', c, RequestContext(request), mimetype="image/svg+xml")
+
+