소스 검색

ajout de la page rapport d'activité

omassot 7 년 전
부모
커밋
5aa82bd5e7
5개의 변경된 파일126개의 추가작업 그리고 8개의 파일을 삭제
  1. 18 0
      main/migrations/0002_sprint_closed.py
  2. 10 3
      main/models.py
  3. 60 0
      main/templates/reports/report_activity.html
  4. 3 1
      main/urls.py
  5. 35 4
      main/views.py

+ 18 - 0
main/migrations/0002_sprint_closed.py

@@ -0,0 +1,18 @@
+# Generated by Django 2.1.1 on 2018-11-12 14:05
+
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+    dependencies = [
+        ('main', '0001_initial'),
+    ]
+
+    operations = [
+        migrations.AddField(
+            model_name='sprint',
+            name='closed',
+            field=models.BooleanField(default=False, verbose_name='Terminé'),
+        ),
+    ]

+ 10 - 3
main/models.py

@@ -85,7 +85,7 @@ class Epic(BaseModel):
                                     INNER JOIN main_story ON main_story_assignees.story_id = main_story.id)
                                     WHERE main_story.epic_id = {};
                                     """.format(self.id))
-        return ", ".join(u.username for u in qry)
+        return list(qry)
     
 class Sprint(BaseModel):
     class Meta:
@@ -94,6 +94,7 @@ class Sprint(BaseModel):
         ordering = ('-date_start', )
     date_start = models.DateField()
     date_end = models.DateField()
+    closed = models.BooleanField(default=False, verbose_name="Terminé")
     retro = MartorField(blank=True, default="", verbose_name="Bilan / Rétrospective")
         
     def __str__(self):
@@ -127,9 +128,15 @@ class Sprint(BaseModel):
 
     @classmethod
     def current(cls):
-        today = datetime.datetime.today()
         try:
-            return Sprint.objects.filter(date_start__lte = today).filter(date_end__gt=today)[0]
+            return Sprint.objects.filter(closed = False).order_by('date_start')[0]
+        except IndexError:
+            return None
+
+    @classmethod
+    def next(cls):
+        try:
+            return Sprint.objects.filter(closed = False).order_by('date_start')[1]
         except IndexError:
             return None
 

+ 60 - 0
main/templates/reports/report_activity.html

@@ -0,0 +1,60 @@
+{% extends '_layout.html' %}
+
+{% block title %}
+	Rapport: Activité
+{% endblock %}
+
+{% block breadcrumb %}
+	<li><a href="{% url 'index' %}">Accueil</a></li>
+	<li><a href="{% url 'reports' %}">Rapports</a></li>
+	<li><a>Activité</a></li>
+{% endblock %}
+
+{% block main %}
+
+<section id="backlog">
+	<header>
+		<div class="flex-row">
+			<h2 class="flex-extend">Les Sprints</h2>
+		</div>
+	</header>
+	
+	<h2>Activité par projets</h2>
+	<h4>Sprint courant</h4>
+	<canvas id="chart-activity-current" width="400" height="160"></canvas>
+
+	<h4>Sur les 6 derniers mois</h4>
+	<canvas id="chart-activity-sixmonths" width="400" height="160"></canvas>
+	
+</section>
+
+<script>
+var ctx = document.getElementById("chart-activity-current").getContext('2d');
+var myChart = new Chart(ctx, {
+	type: 'polarArea',
+    
+    data: {
+        labels: [{% for project in activity %}"{{ project.name }}",{% endfor %}],
+        datasets: [{
+	            label: 'Activité',
+	            data: [{% for project, act in activity.items %}"{{ act.current }}",{% endfor %}],
+	            backgroundColor: [{% for project in activity %}'{{ project.color }}',{% endfor %}]
+            }]
+    }
+});
+var ctx = document.getElementById("chart-activity-sixmonths").getContext('2d');
+var myChart = new Chart(ctx, {
+	type: 'polarArea',
+    
+    data: {
+        labels: [{% for project in activity %}"{{ project.name }}",{% endfor %}],
+        datasets: [{
+	            label: 'Activité',
+	            data: [{% for project, act in activity.items %}"{{ act.sixmonths }}",{% endfor %}],
+	            backgroundColor: [{% for project in activity %}'{{ project.color }}',{% endfor %}]
+            }]
+    }
+});
+</script>
+
+{% endblock %}

+ 3 - 1
main/urls.py

@@ -22,8 +22,9 @@ urlpatterns = [
     path('stories/edit/<int:story_id>/', views.story_edit, name='story_edit'),
     path('stories/delete/<int:story_id>/', views.story_delete, name='story_delete'),
     path('stories/close/<int:story_id>/', views.story_close, name='story_close'),
-    path('stories/axclose/<int:story_id>/', views.story_close_ajax, name='story_close_ajax'),
     path('stories/reopen/<int:story_id>/', views.story_reopen, name='story_reopen'),
+    path('stories/axclose/<int:story_id>/', views.story_close_ajax, name='story_close_ajax'),
+    path('stories/axreaffect/<int:story_id>/', views.story_reaffect_ajax, name='story_reaffect_ajax'),
     path('epics/<int:epic_id>', views.epic_details, name='epic_details'),
     path('epics/create/', views.epic_create, name='epic_create'),
     path('epics/edit/<int:epic_id>/', views.epic_edit, name='epic_edit'),
@@ -35,6 +36,7 @@ urlpatterns = [
     path('reports/', views.reports, name='reports'),
     path('reports/sprints/', views.report_sprints, name='report_sprints'),
     path('reports/projects/', views.report_projects, name='report_projects'),
+    path('reports/activity/', views.report_activity, name='report_activity'),
     path('comment-post/<obj_uuid>/', views.comment_post, name='comment_post'),
     path('comment-edit/<int:comment_id>/', views.comment_edit, name='comment_edit'),
     path('comment-del/<int:comment_id>/', views.comment_del, name='comment_del'),

+ 35 - 4
main/views.py

@@ -12,7 +12,7 @@ from django.shortcuts import render, get_object_or_404, redirect
 
 from main.forms import StoryForm, EpicForm, RegisterForm, ProfileForm, \
     CommentForm, SprintForm
-from main.models import Story, Epic, Sprint, Comment
+from main.models import Story, Epic, Sprint, Comment, Project
 
 
 @login_required
@@ -73,14 +73,16 @@ def backlog_editor(request):
 def sprint_end(request):
     
     current_sprint = Sprint.current()
+    next_sprint = Sprint.next()
     
     if request.method == 'POST':
         current_sprint.retro = request.POST["retro"]
+        current_sprint.closed = True
         current_sprint.save()
-        return HttpResponseRedirect('')
+        return HttpResponseRedirect(request.META['HTTP_REFERER'].split("#")[0] + "#retro-section")
     
     form = SprintForm(instance=current_sprint)
-    return render(request, 'sprint_end.html', {'sprint': current_sprint, 'form': form})
+    return render(request, 'sprint_end.html', {'sprint': current_sprint, 'next': next_sprint, 'form': form})
 
 @login_required
 def story_index(request):
@@ -177,6 +179,14 @@ def story_close_from_sprintend(_, story_id):
     story.save()
     return redirect("sprint_end")
 
+@login_required
+def story_reaffect_ajax(_, story_id):
+    story = get_object_or_404(Story, id=story_id)
+    next_sprint = Sprint.next()
+    story.sprints.add(next_sprint)
+    story.save()
+    return redirect("sprint_end")
+
 @login_required
 def story_reopen(request, story_id):
     story = get_object_or_404(Story, id=story_id)
@@ -266,9 +276,30 @@ def report_sprints(request):
      
 @login_required
 def report_projects(request):
-    epics = Epic.objects.all()
+    epics = Epic.objects.filter(closed=False)
+    
+
     return render(request, 'reports/report_projects.html', {'epics': epics})
 
+def report_activity(request):
+    
+    activity = {}
+    for project in Project.objects.all():
+        activity[project] = {}
+        activity[project]["current"] = 0
+        activity[project]["sixmonths"] = 0
+        
+    current = True
+    for sprint in Sprint.objects.filter(date_end__lt = datetime.today()).order_by('-date_start')[:12]:
+        for story in sprint.stories.all():
+            if current:
+                activity[story.epic.project]["current"] += story.weight
+            activity[story.epic.project]["sixmonths"] += story.weight
+        
+        current = False
+        
+    return render(request, 'reports/report_activity.html', {'activity': activity})
+        
 def com_pack(obj):
     pack = {}
     pack['obj'] = obj