Refactoring de la generation des organigrammes et ajout organigramme par implantation
authorJean-Philippe Caissy <jpcaissy@piji.ca>
Wed, 7 Mar 2012 16:53:07 +0000 (10:53 -0600)
committerJean-Philippe Caissy <jpcaissy@piji.ca>
Wed, 7 Mar 2012 16:53:07 +0000 (10:53 -0600)
project/menu.py
project/rh/admin.py
project/rh/graph.py
project/rh/urls.py
project/rh/views.py

index b2a0b35..200ceb6 100644 (file)
@@ -56,6 +56,7 @@ class CustomMenu(Menu):
                     children=[
                         items.MenuItem('Organigramme par employé', reverse('admin:rh_employeproxy_changelist')),
                         items.MenuItem('Organigramme par service', reverse('admin:rh_serviceproxy_changelist')),
+                        items.MenuItem('Organigramme par implantation', reverse('admin:rh_implantationproxy_changelist')),
                         ]
                     ),
             ]
index 336e05a..c9666f2 100644 (file)
@@ -17,6 +17,15 @@ from change_list import ChangeList
 from groups import grp_drh
 import models as rh
 
+import auf.django.references.models as ref
+
+class ImplantationProxy(ref.Implantation):
+    """ Proxy utilisé pour les organigrammes par implantation """
+    class Meta:
+        proxy = True
+        verbose_name = u"Organigramme par implantations"
+        verbose_name_plural = u"Organigramme par implantations"
+
 
 class ServiceProxy(rh.Service):
     """ Proxy utilisé pour les organigrammes opar service """
@@ -927,7 +936,7 @@ class ServiceProxyAdmin(ServiceAdmin):
         return False
 
     def _organigramme(self, obj):
-        return """<a href="%s">Organigramme</a>""" % (reverse('rho_service', args=(obj.id,)))
+        return """<a href="%s">Organigramme</a>""" % (reverse('rho_implantation', args=(obj.id,)))
     _organigramme.allow_tags = True
     _organigramme.short_description = "Organigramme"
 
@@ -1074,6 +1083,19 @@ class ValeurPointAdmin(AUFMetadataAdminMixin, admin.ModelAdmin):
         return obj.devise.nom
     _devise_nom.short_description = "Nom de la devise"
 
+class ImplantationProxyAdmin(admin.ModelAdmin):
+    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_implantation', args=(obj.id,)))
+    _organigramme.allow_tags = True
+    _organigramme.short_description = "Organigramme"
+
+
 
 admin.site.register(rh.Classement, ClassementAdmin)
 admin.site.register(rh.Devise, DeviseAdmin)
@@ -1093,3 +1115,4 @@ admin.site.register(rh.TypePoste, TypePosteAdmin)
 admin.site.register(rh.TypeRemuneration, TypeRemunerationAdmin)
 admin.site.register(rh.TypeRevalorisation, TypeRevalorisationAdmin)
 admin.site.register(rh.ValeurPoint, ValeurPointAdmin)
+admin.site.register(ImplantationProxy, ImplantationProxyAdmin)
index d684381..1e9f4b4 100644 (file)
@@ -1,3 +1,7 @@
+# -*- encoding: utf-8 -*-
+
+import pygraphviz as pgv
+
 from datetime import date
 from django.db.models import Q
 from django.core.urlresolvers import reverse
@@ -23,3 +27,52 @@ def bind_poste_to_graph(graph, postes_by_id):
         n.attr['href'] = reverse("admin:rh_employe_change", args=(d.employe_id,))
 
     return graph
+
+def organigramme_postes_cluster(cluster_filter, titre=u"Organigramme", cluster_titre=u"Cluster 1"):
+    """ Crée un organigramme des postes avec un cluster défini par le keyword qui sera
+    rajouté au queryset en tant que filter.
+    cluster_filter doit être un map de format (field: value) qui sera appliqué au queryset.
+    Par exemple: cluster_filter={"service__exact": 19}
+    """
+    if type(titre) != type(unicode()):
+        raise "Le titre du graphique doit être un unicode"
+    if type(cluster_titre) != type(unicode()):
+        raise "Le titre du cluster doit être un unicode"
+
+    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(**cluster_filter).exclude(supprime=True, responsable=None).all()
+
+    nom = titre.encode('ascii', 'xmlcharrefreplace')
+    graph = pgv.AGraph(directed=True, name=nom)
+    #pour mettre l'organigramme de gauche à droite (au lieu du haut à bas)
+    #graph.rankdir='LR'
+    graph_service = graph.subgraph(nbunch=[1,2], \
+            name="cluster1", \
+            style='filled', \
+            color='lightgrey', \
+            label=cluster_titre.encode('ascii', 'xmlcharrefreplace'),
+            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)
+
+    bind_poste_to_graph(graph, postes_by_id)
+
+    graph.layout(prog='dot')
+
+    svg = graph.draw(format='svg')
+    
+    return svg
+
+
index 37aff13..11f240e 100644 (file)
@@ -17,4 +17,5 @@ urlpatterns = patterns(
     url(r'^admin/rh/poste/(\d+)/apercu/$', 'poste_apercu', name='poste_apercu'),
     url(r'^admin/rh/organigrammes/employe/(\d+)$', 'organigrammes_employe', name='rho_employe'),
     url(r'^admin/rh/organigrammes/service/(\d+)$', 'organigrammes_service', name='rho_service'),
+    url(r'^admin/rh/organigrammes/implantation/(\d+)$', 'organigrammes_implantation', name='rho_implantation'),
 )
index a3acfd7..6c5bddf 100644 (file)
@@ -3,7 +3,6 @@
 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
@@ -533,49 +532,30 @@ def organigrammes_employe(request, id):
 def organigrammes_service(request, id):
 
     service = get_object_or_404(rh.Service, pk=id)
+    svg = rh_graph.organigramme_postes_cluster( \
+            cluster_filter={"service": service}, \
+            titre=u"Organigramme du service %s" % service.nom,
+            cluster_titre=service.nom)
 
-    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()
-
-    nom = u"Organigramme de « %s »" % (service.nom)
-    nom = nom.encode('ascii', 'xmlcharrefreplace')
-    graph = pgv.AGraph(directed=True, name=nom)
-    graph_service = graph.subgraph(nbunch=[1,2], \
-            name="cluster1", \
-            style='filled', \
-            color='lightgrey', \
-            label=service.nom.encode('ascii', 'xmlcharrefreplace'),
-            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)
+    c = {
+        'svg': svg
+    }
 
-    rh_graph.bind_poste_to_graph(graph, postes_by_id)
+    return render_to_response('rh/organigrammes/service.html', c, RequestContext(request), mimetype="image/svg+xml")
 
-    graph.layout(prog='dot')
+@login_required
+@drh_or_admin_required
+def organigrammes_implantation(request, id):
 
-    svg = graph.draw(format='svg')
+    implantation = get_object_or_404(ref.Implantation, pk=id)
+    svg = rh_graph.organigramme_postes_cluster( \
+            cluster_filter={"implantation": implantation}, \
+            titre=u"Organigramme de l'implantation %s" % implantation.nom,
+            cluster_titre=implantation.nom)
 
     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")
 
-