Merge pull request #464 from taigaio/making-total_points-and-total_sprints-nullable
Making total_points and total_sprints nullable valuesremotes/origin/logger
commit
ca6239eda2
|
@ -0,0 +1,26 @@
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
|
from django.db import models, migrations
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('projects', '0026_auto_20150911_1237'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='project',
|
||||||
|
name='total_milestones',
|
||||||
|
field=models.IntegerField(verbose_name='total of milestones', null=True, blank=True),
|
||||||
|
preserve_default=True,
|
||||||
|
),
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='project',
|
||||||
|
name='total_story_points',
|
||||||
|
field=models.FloatField(verbose_name='total story points', null=True, blank=True),
|
||||||
|
preserve_default=True,
|
||||||
|
),
|
||||||
|
]
|
|
@ -146,9 +146,9 @@ class Project(ProjectDefaults, TaggedMixin, models.Model):
|
||||||
members = models.ManyToManyField(settings.AUTH_USER_MODEL, related_name="projects",
|
members = models.ManyToManyField(settings.AUTH_USER_MODEL, related_name="projects",
|
||||||
through="Membership", verbose_name=_("members"),
|
through="Membership", verbose_name=_("members"),
|
||||||
through_fields=("project", "user"))
|
through_fields=("project", "user"))
|
||||||
total_milestones = models.IntegerField(default=0, null=False, blank=False,
|
total_milestones = models.IntegerField(null=True, blank=True,
|
||||||
verbose_name=_("total of milestones"))
|
verbose_name=_("total of milestones"))
|
||||||
total_story_points = models.FloatField(default=0, verbose_name=_("total story points"))
|
total_story_points = models.FloatField(null=True, blank=True, verbose_name=_("total story points"))
|
||||||
|
|
||||||
is_backlog_activated = models.BooleanField(default=True, null=False, blank=True,
|
is_backlog_activated = models.BooleanField(default=True, null=False, blank=True,
|
||||||
verbose_name=_("active backlog panel"))
|
verbose_name=_("active backlog panel"))
|
||||||
|
|
|
@ -342,16 +342,6 @@ class ProjectSerializer(WatchersValidator, LikedResourceSerializerMixin, Watched
|
||||||
def get_notify_level(self, obj):
|
def get_notify_level(self, obj):
|
||||||
return getattr(obj, "notify_level", None)
|
return getattr(obj, "notify_level", None)
|
||||||
|
|
||||||
def validate_total_milestones(self, attrs, source):
|
|
||||||
"""
|
|
||||||
Check that total_milestones is not null, it's an optional parameter but
|
|
||||||
not nullable in the model.
|
|
||||||
"""
|
|
||||||
value = attrs[source]
|
|
||||||
if value is None:
|
|
||||||
raise serializers.ValidationError(_("Total milestones must be major or equal to zero"))
|
|
||||||
return attrs
|
|
||||||
|
|
||||||
|
|
||||||
class ProjectDetailSerializer(ProjectSerializer):
|
class ProjectDetailSerializer(ProjectSerializer):
|
||||||
us_statuses = UserStoryStatusSerializer(many=True, required=False) # User Stories
|
us_statuses = UserStoryStatusSerializer(many=True, required=False) # User Stories
|
||||||
|
|
|
@ -23,6 +23,14 @@ import copy
|
||||||
from taiga.projects.history.models import HistoryEntry
|
from taiga.projects.history.models import HistoryEntry
|
||||||
|
|
||||||
|
|
||||||
|
def _get_total_story_points(project):
|
||||||
|
return (project.total_story_points if project.total_story_points is not None else
|
||||||
|
sum(project.calculated_points["defined"].values()))
|
||||||
|
|
||||||
|
def _get_total_milestones(project):
|
||||||
|
return (project.total_milestones if project.total_milestones is not None else
|
||||||
|
project.milestones.count())
|
||||||
|
|
||||||
def _get_milestones_stats_for_backlog(project):
|
def _get_milestones_stats_for_backlog(project):
|
||||||
"""
|
"""
|
||||||
Get collection of stats for each millestone of project.
|
Get collection of stats for each millestone of project.
|
||||||
|
@ -33,8 +41,12 @@ def _get_milestones_stats_for_backlog(project):
|
||||||
current_client_increment = 0
|
current_client_increment = 0
|
||||||
|
|
||||||
optimal_points_per_sprint = 0
|
optimal_points_per_sprint = 0
|
||||||
if project.total_story_points and project.total_milestones:
|
|
||||||
optimal_points_per_sprint = project.total_story_points / project.total_milestones
|
total_story_points = _get_total_story_points(project)
|
||||||
|
total_milestones = _get_total_milestones(project)
|
||||||
|
|
||||||
|
if total_story_points and total_milestones:
|
||||||
|
optimal_points_per_sprint = total_story_points / total_milestones
|
||||||
|
|
||||||
future_team_increment = sum(project.future_team_increment.values())
|
future_team_increment = sum(project.future_team_increment.values())
|
||||||
future_client_increment = sum(project.future_client_increment.values())
|
future_client_increment = sum(project.future_client_increment.values())
|
||||||
|
@ -50,11 +62,11 @@ def _get_milestones_stats_for_backlog(project):
|
||||||
team_increment = 0
|
team_increment = 0
|
||||||
client_increment = 0
|
client_increment = 0
|
||||||
|
|
||||||
for current_milestone in range(0, max(milestones_count, project.total_milestones)):
|
for current_milestone in range(0, max(milestones_count, total_milestones)):
|
||||||
optimal_points = (project.total_story_points -
|
optimal_points = (total_story_points -
|
||||||
(optimal_points_per_sprint * current_milestone))
|
(optimal_points_per_sprint * current_milestone))
|
||||||
|
|
||||||
evolution = (project.total_story_points - current_evolution
|
evolution = (total_story_points - current_evolution
|
||||||
if current_evolution is not None else None)
|
if current_evolution is not None else None)
|
||||||
|
|
||||||
if current_milestone < milestones_count:
|
if current_milestone < milestones_count:
|
||||||
|
@ -83,8 +95,8 @@ def _get_milestones_stats_for_backlog(project):
|
||||||
}
|
}
|
||||||
|
|
||||||
optimal_points -= optimal_points_per_sprint
|
optimal_points -= optimal_points_per_sprint
|
||||||
evolution = (project.total_story_points - current_evolution
|
evolution = (total_story_points - current_evolution
|
||||||
if current_evolution is not None and project.total_story_points else None)
|
if current_evolution is not None and total_story_points else None)
|
||||||
yield {
|
yield {
|
||||||
'name': _('Project End'),
|
'name': _('Project End'),
|
||||||
'optimal': optimal_points,
|
'optimal': optimal_points,
|
||||||
|
@ -104,6 +116,7 @@ def _count_status_object(status_obj, counting_storage):
|
||||||
counting_storage[status_obj.id]['id'] = status_obj.id
|
counting_storage[status_obj.id]['id'] = status_obj.id
|
||||||
counting_storage[status_obj.id]['color'] = status_obj.color
|
counting_storage[status_obj.id]['color'] = status_obj.color
|
||||||
|
|
||||||
|
|
||||||
def _count_owned_object(user_obj, counting_storage):
|
def _count_owned_object(user_obj, counting_storage):
|
||||||
if user_obj:
|
if user_obj:
|
||||||
if user_obj.id in counting_storage:
|
if user_obj.id in counting_storage:
|
||||||
|
@ -126,6 +139,7 @@ def _count_owned_object(user_obj, counting_storage):
|
||||||
counting_storage[0]['id'] = 0
|
counting_storage[0]['id'] = 0
|
||||||
counting_storage[0]['color'] = 'black'
|
counting_storage[0]['color'] = 'black'
|
||||||
|
|
||||||
|
|
||||||
def get_stats_for_project_issues(project):
|
def get_stats_for_project_issues(project):
|
||||||
project_issues_stats = {
|
project_issues_stats = {
|
||||||
'total_issues': 0,
|
'total_issues': 0,
|
||||||
|
@ -283,6 +297,7 @@ def _get_closed_tasks_per_member_stats(project):
|
||||||
closed_tasks = {p["assigned_to"]: p["count"] for p in closed_tasks}
|
closed_tasks = {p["assigned_to"]: p["count"] for p in closed_tasks}
|
||||||
return closed_tasks
|
return closed_tasks
|
||||||
|
|
||||||
|
|
||||||
def get_member_stats_for_project(project):
|
def get_member_stats_for_project(project):
|
||||||
base_counters = {id: 0 for id in project.members.values_list("id", flat=True)}
|
base_counters = {id: 0 for id in project.members.values_list("id", flat=True)}
|
||||||
closed_bugs = base_counters.copy()
|
closed_bugs = base_counters.copy()
|
||||||
|
|
Loading…
Reference in New Issue