def sprint_burndown_json(request, sprint_id): """ Returns a list of points with the iteration day as the X axis and the number of remaining hours as the Y axis. """ sprint = get_object_or_404(Sprint, pk=int(sprint_id)) remaining_hours = [] user_remaining_hours = [] open_tasks = [] for day, date in date_range(sprint.start_date, sprint.end_date): cache = TaskSnapshotCache.objects.filter( task_snapshot__task__sprints=sprint, date=date) data = cache.aggregate(rem=Sum('task_snapshot__remaining_hours')) remaining_hours.append([day, data['rem'] if data['rem'] else 'null']) data = cache.exclude(Q(task_snapshot__status__istartswith='RESOLVED') \ | Q(task_snapshot__status__istartswith='CLOSED') \ | Q(task_snapshot__status__istartswith='VERIFIED')) \ .aggregate(count=Count('task_snapshot')) if data['count']: open_tasks.append([day, data['count']]) if not request.user.is_authenticated(): continue data = cache.filter(task_snapshot__assigned_to=request.user) \ .aggregate(rem=Sum('task_snapshot__remaining_hours')) user_remaining_hours.append( [day, data['rem'] if data['rem'] else 'null']) weekends = [] for day, date in date_range(sprint.start_date, sprint.end_date): if date.isoweekday() == 7: weekends.append({'start': day - 2, 'end': day}) return HttpResponse( simplejson.dumps({ 'data': [remaining_hours, user_remaining_hours, open_tasks], 'weekends': weekends, }))
def sprint_burndown_json(request, sprint_id): """ Returns a list of points with the iteration day as the X axis and the number of remaining hours as the Y axis. """ sprint = get_object_or_404(Sprint, pk=int(sprint_id)) remaining_hours = [] user_remaining_hours = [] open_tasks = [] for day, date in date_range(sprint.start_date, sprint.end_date): cache = TaskSnapshotCache.objects.filter(task_snapshot__task__sprints=sprint, date=date) data = cache.aggregate(rem=Sum('task_snapshot__remaining_hours')) remaining_hours.append([day, data['rem'] if data['rem'] else 'null']) data = cache.exclude(Q(task_snapshot__status__istartswith='RESOLVED') \ | Q(task_snapshot__status__istartswith='CLOSED') \ | Q(task_snapshot__status__istartswith='VERIFIED')) \ .aggregate(count=Count('task_snapshot')) if data['count']: open_tasks.append([day, data['count']]) if not request.user.is_authenticated(): continue data = cache.filter(task_snapshot__assigned_to=request.user) \ .aggregate(rem=Sum('task_snapshot__remaining_hours')) user_remaining_hours.append([day, data['rem'] if data['rem'] else 'null']) weekends = [] for day, date in date_range(sprint.start_date, sprint.end_date): if date.isoweekday() == 7: weekends.append({'start': day - 2, 'end': day}) return HttpResponse(simplejson.dumps({ 'data': [remaining_hours, user_remaining_hours, open_tasks], 'weekends': weekends, }))
def load_and_effort_by_user(self): """ Returns a tuple containing two child dicts. - The first dict maps a User to an array of their effort for every day in the Sprint. Effort is the total remaining hours left in an Sprint-day. - The second dict maps a User to an array of their load for every day in the Sprint. Load is calculated by: (total_hours / (weekdays * velocity) * 100. """ users_load = {} users_effort = {} for day, date in date_range(self.start_date, self.end_date): if date > date.today(): continue rows = TaskSnapshotCache.objects.filter(date__lte=date, date__gte=date, task_snapshot__task__sprints=self) \ .values('task_snapshot__assigned_to') \ .annotate(Sum('task_snapshot__remaining_hours')) for row in rows: assigned_to = row['task_snapshot__assigned_to'] if assigned_to == None: continue try: user = User.objects.get(pk=int(assigned_to)) except ObjectDoesNotExist: continue if not users_load.has_key(user): users_load[user] = [''] * (self.iteration_days() + 1) users_effort[user] = [''] * (self.iteration_days() + 1) users_effort[user][day] = int( row['task_snapshot__remaining_hours__sum']) users_load[user][day] = _calc_load( users_effort[user][day], _workday_diff(self.start_date, date), self.iteration_workdays(), self.velocity) return (users_load, users_effort)
def load_and_effort_by_user(self): """ Returns a tuple containing two child dicts. - The first dict maps a User to an array of their effort for every day in the Sprint. Effort is the total remaining hours left in an Sprint-day. - The second dict maps a User to an array of their load for every day in the Sprint. Load is calculated by: (total_hours / (weekdays * velocity) * 100. """ users_load = {} users_effort = {} for day, date in date_range(self.start_date, self.end_date): if date > date.today(): continue rows = TaskSnapshotCache.objects.filter(date__lte=date, date__gte=date, task_snapshot__task__sprints=self) \ .values('task_snapshot__assigned_to') \ .annotate(Sum('task_snapshot__remaining_hours')) for row in rows: assigned_to = row['task_snapshot__assigned_to'] if assigned_to == None: continue try: user = User.objects.get(pk=int(assigned_to)) except ObjectDoesNotExist: continue if not users_load.has_key(user): users_load[user] = ['']*(self.iteration_days() + 1) users_effort[user] = ['']*(self.iteration_days() + 1) users_effort[user][day] = int(row['task_snapshot__remaining_hours__sum']) users_load[user][day] = _calc_load(users_effort[user][day], _workday_diff(self.start_date, date), self.iteration_workdays(), self.velocity) return (users_load, users_effort)
def _workday_diff(start, end): return len([d for dy, d in date_range(start, end) if d.isoweekday() <= 5])