コード例 #1
0
def state_transition_counts(state, months, count_type="exit", raw=False):
    end = make_end_date(date=datetime.datetime.now())

    start = end - relativedelta(months=months)
    start = make_start_date(date=start)

    counts = []
    data = []

    current_date = start
    while current_date <= end:
        if current_date.weekday() == 5:  # Saturday
            current_date += relativedelta(days=2)
        elif current_date.weekday() == 6:  # Sunday
            current_date += relativedelta(days=1)

        range_start = make_start_date(date=current_date)
        range_end = make_end_date(date=current_date)

        if count_type == "exit":
            kwargs = dict(
                exited__gte=range_start,
                exited__lte=range_end,
            )
        elif count_type == "enter":
            kwargs = dict(
                entered__gte=range_start,
                entered__lte=range_end,
            )

        count = StateLog.objects.filter(
            state=state,
            **kwargs
        ).count()

        data.append((current_date, count))
        counts.append(count)
        current_date = current_date + relativedelta(days=1)

    counts.sort()

    print "%s\t%s" % (start, end)
    print "Median\t%s" % median(counts)
    print "Average\t%s" % average(counts)
    print "Min\t%s" % counts[0]
    print "Max\t%s" % counts[-1]

    hist = histogram(counts)
    keys = hist.keys()
    keys.sort()
    for k in keys:
        print "%s\t%s" % (k, hist[k])

    if raw is True:
        for date, count in data:
            print "%s\t%s" % (date, count)
コード例 #2
0
def state_transition_counts(state, months, count_type="exit", raw=False):
    end = make_end_date(date=datetime.datetime.now())

    start = end - relativedelta(months=months)
    start = make_start_date(date=start)

    counts = []
    data = []

    current_date = start
    while current_date <= end:
        if current_date.weekday() == 5:  # Saturday
            current_date += relativedelta(days=2)
        elif current_date.weekday() == 6:  # Sunday
            current_date += relativedelta(days=1)

        range_start = make_start_date(date=current_date)
        range_end = make_end_date(date=current_date)

        if count_type == "exit":
            kwargs = dict(
                exited__gte=range_start,
                exited__lte=range_end,
            )
        elif count_type == "enter":
            kwargs = dict(
                entered__gte=range_start,
                entered__lte=range_end,
            )

        count = StateLog.objects.filter(state=state, **kwargs).count()

        data.append((current_date, count))
        counts.append(count)
        current_date = current_date + relativedelta(days=1)

    counts.sort()

    print "%s\t%s" % (start, end)
    print "Median\t%s" % median(counts)
    print "Average\t%s" % average(counts)
    print "Min\t%s" % counts[0]
    print "Max\t%s" % counts[-1]

    hist = histogram(counts)
    keys = hist.keys()
    keys.sort()
    for k in keys:
        print "%s\t%s" % (k, hist[k])

    if raw is True:
        for date, count in data:
            print "%s\t%s" % (date, count)
コード例 #3
0
    def test_regress_service_class_miscalc(self):
        from kardboard.util import make_start_date, make_end_date

        c = self.make_card(
            key="JANUS-234",
            title="MMF: Database visualization (Iteration 1)",
            backlog_date=datetime(2013, 2, 14),
            start_date=datetime(2013, 5, 30),
            done_date=datetime(2013, 8, 1),
            _service_class="Normal",
            state="Done",
            team="Team Venture",
        )
        c.save()

        Record = self._get_target_class()
        start_date = make_start_date(date=datetime(2013, 8, 1))
        end_date = make_end_date(date=datetime(2013, 8, 31))
        Record.calculate(start_date, end_date, group="team-venture")

        r = Record.objects.get(
            start_date=start_date,
            end_date=end_date,
            group="team-venture",
        )
        actual = r.data

        assert actual['Normal']['wip'] == 1
コード例 #4
0
    def test_regress_service_class_miscalc(self):
        from kardboard.util import make_start_date, make_end_date

        c = self.make_card(
            key="JANUS-234",
            title="MMF: Database visualization (Iteration 1)",
            backlog_date=datetime(2013, 2, 14),
            start_date=datetime(2013, 5, 30),
            done_date=datetime(2013, 8, 1),
            _service_class="Normal",
            state="Done",
            team="Team Venture",
        )
        c.save()

        Record = self._get_target_class()
        start_date = make_start_date(date=datetime(2013, 8, 1))
        end_date = make_end_date(date=datetime(2013, 8, 31))
        Record.calculate(start_date, end_date, group="team-venture")

        r = Record.objects.get(
            start_date=start_date,
            end_date=end_date,
            group="team-venture",
        )
        actual = r.data

        assert actual['Normal']['wip'] == 1
コード例 #5
0
    def calculate(cls, start_date, end_date, group="all"):
        from kardboard.models import Kard
        from kardboard.models import ReportGroup

        start_date = make_start_date(date=start_date)
        end_date = make_end_date(date=end_date)

        try:
            record = cls.objects.get(
                group=group,
                start_date=start_date,
                end_date=end_date,
            )
        except cls.DoesNotExist:
            record = cls()
            record.start_date = start_date
            record.end_date = end_date
            record.group = group
            record.data = {}

        kards = ReportGroup(group,
            Kard.objects.filter(
                done_date__gte=start_date,
                done_date__lte=end_date,
            )
        )
        record.data = report_on_cards(list(kards.queryset))
        record.save()
        return record
コード例 #6
0
def report_detailed_flow(group="all", months=3, cards_only=False):
    end = kardboard.util.now()
    months_ranges = month_ranges(end, months)

    start_day = make_start_date(date=months_ranges[0][0])
    end_day = make_end_date(date=end)

    if cards_only:
        only_arg = ('state_card_counts', 'date', 'group')
    else:
        only_arg = ('state_counts', 'date', 'group')

    reports = FlowReport.objects.filter(
        date__gte=start_day,
        date__lte=end_day,
        group=group).only(*only_arg)
    if not reports:
        abort(404)

    chart = {}
    chart['categories'] = []

    series = []
    for state in States():
        seri = {'name': state, 'data': []}
        series.append(seri)

    done_starting_point = 0
    for report in reports:
        chart['categories'].append(report.date.strftime("%m/%d"))
        for seri in series:
            if cards_only:
                daily_seri_data = report.state_card_counts.get(seri['name'], 0)
            else:
                daily_seri_data = report.state_counts.get(seri['name'], 0)

            if seri['name'] == "Done":
                if len(seri['data']) == 0:
                    done_starting_point = daily_seri_data
                    daily_seri_data = 0
                else:
                    daily_seri_data = daily_seri_data - done_starting_point

            seri['data'].append(daily_seri_data)
    chart['series'] = series

    start_date = reports.order_by('date').first().date
    reports.order_by('-date')
    context = {
        'title': "Detailed Cumulative Flow",
        'reports': reports,
        'months': months,
        'cards_only': cards_only,
        'chart': chart,
        'start_date': start_date,
        'updated_at': reports[0].updated_at,
        'states': States(),
        'version': VERSION,
    }
    return render_template('report-detailed-flow.html', **context)
コード例 #7
0
ファイル: moving_data.py プロジェクト: vdreamakitex/kardboard
def weekly_moving_data(report_group_slug, start):
    start = parse_date(start)
    stop = start + relativedelta(days=6)

    start = make_start_date(date=start)
    stop = make_end_date(date=stop)
    return moving_data(report_group_slug, start, stop)
コード例 #8
0
def std_dev(start, stop):
    start = make_start_date(date=start)
    stop = make_end_date(date=stop)

    rg = ReportGroup('dev', Kard.objects.filter(done_date__gte=start, done_date__lte=stop))

    cards = [c for c in rg.queryset if c.is_card]
    cycle_times = [c.cycle_time for c in cards]

    over_21 = [c for c in cycle_times if c > 21]
    over_21_pct = float(len(over_21)) / len(cycle_times)

    print "%s -- %s" % (start, stop)
    print "\t Sample: %s" % len(cards)
    print "\t Over 21: %s / %s" % (len(over_21), over_21_pct * 100)
    print "\t Ave: %s" % average(cycle_times)
    print "\t Stdev: %s" % standard_deviation(cycle_times)
    ct, pct = percentile(.8, cycle_times)
    print "\t 80pct: %s / %s" % (ct, pct * 100)

    cards_by_class = {}
    for c in cards:
        cards_by_class.setdefault(c.service_class['name'], [])
        cards_by_class[c.service_class['name']].append(c)

    for sclass, cards in cards_by_class.items():
        cycle_times = [c.cycle_time for c in cards]

        print "\t ## %s" % (sclass)
        print "\t\t Sample: %s" % len(cards)
        print "\t\t Ave: %s" % average(cycle_times)
        print "\t\t Stdev: %s" % standard_deviation(cycle_times)
コード例 #9
0
ファイル: views.py プロジェクト: antiface/kardboard
def report_flow(group="all", months=3):
    end = kardboard.util.now()
    months_ranges = month_ranges(end, months)

    start_day = make_start_date(date=months_ranges[0][0])
    end_day = make_end_date(date=end)

    records = DailyRecord.objects.filter(date__gte=start_day, date__lte=end_day, group=group)

    chart = {}
    chart["categories"] = [report.date.strftime("%m/%d") for report in records]
    series = [{"name": "Planning", "data": []}, {"name": "Todo", "data": []}, {"name": "Done", "data": []}]
    for row in records:
        series[0]["data"].append(row.backlog)
        series[1]["data"].append(row.in_progress)
        series[2]["data"].append(row.done)
    chart["series"] = series

    start_date = records.order_by("date").first().date
    records.order_by("-date")
    context = {
        "title": "Cumulative Flow",
        "updated_at": datetime.datetime.now(),
        "chart": chart,
        "start_date": start_date,
        "flowdata": records,
        "version": VERSION,
    }
    return render_template("chart-flow.html", **context)
コード例 #10
0
ファイル: views.py プロジェクト: memeticlabs/kardboard
def report_detailed_flow(group="all", months=3, cards_only=False):
    end = kardboard.util.now()
    months_ranges = month_ranges(end, months)

    start_day = make_start_date(date=months_ranges[0][0])
    end_day = make_end_date(date=end)

    if cards_only:
        only_arg = ('state_card_counts', 'date', 'group')
    else:
        only_arg = ('state_counts', 'date', 'group')

    reports = FlowReport.objects.filter(
        date__gte=start_day,
        date__lte=end_day,
        group=group).only(*only_arg)
    if not reports:
        abort(404)

    chart = {}
    chart['categories'] = []

    series = []
    for state in States():
        seri = {'name': state, 'data': []}
        series.append(seri)

    done_starting_point = 0
    for report in reports:
        chart['categories'].append(report.date.strftime("%m/%d"))
        for seri in series:
            if cards_only:
                daily_seri_data = report.state_card_counts.get(seri['name'], 0)
            else:
                daily_seri_data = report.state_counts.get(seri['name'], 0)

            if seri['name'] == "Done":
                if len(seri['data']) == 0:
                    done_starting_point = daily_seri_data
                    daily_seri_data = 0
                else:
                    daily_seri_data = daily_seri_data - done_starting_point

            seri['data'].append(daily_seri_data)
    chart['series'] = series

    start_date = reports.order_by('date').first().date
    reports.order_by('-date')
    context = {
        'title': "Detailed Cumulative Flow",
        'reports': reports,
        'months': months,
        'cards_only': cards_only,
        'chart': chart,
        'start_date': start_date,
        'updated_at': reports[0].updated_at,
        'states': States(),
        'version': VERSION,
    }
    return render_template('report-detailed-flow.html', **context)
コード例 #11
0
def value_txt_report(year_number, month_number, group="all"):
    start_date = munge_date(year=year_number, month=month_number, day=1)
    start_date = make_start_date(date=start_date)

    start_date, end_date = month_range(start_date)

    rg = ReportGroup(group, Kard.objects.done())
    done = rg.queryset

    cards = done.filter(done_date__gte=start_date,
                        done_date__lte=end_date).order_by('-done_date')

    cards = [c for c in cards if c.is_card]

    context = {
        'title': "Completed Value Cards",
        'cards': cards,
        'start_date': start_date,
        'end_date': end_date,
        'updated_at': datetime.datetime.now(),
        'version': VERSION,
    }

    response = make_response(render_template('done-report.txt', **context))
    response.headers['Content-Type'] = "text/plain"
    return response
コード例 #12
0
ファイル: views.py プロジェクト: GregMeno/kardboard
def chart_flow(group="all", months=3):
    end = kardboard.util.now()
    months_ranges = month_ranges(end, months)

    start_day = make_start_date(date=months_ranges[0][0])
    end_day = make_end_date(date=end)

    records = DailyRecord.objects.filter(
        date__gte=start_day,
        date__lte=end_day,
        group=group)

    chart = CumulativeFlowChart(900, 300)
    chart.add_data([r.backlog_cum for r in records])
    chart.add_data([r.in_progress_cum for r in records])
    chart.add_data([r.done for r in records])
    chart.setup_grid(records)

    records.order_by('-date')
    context = {
        'title': "Cumulative Flow",
        'updated_at': datetime.datetime.now(),
        'chart': chart,
        'flowdata': records,
        'version': VERSION,
    }

    return render_template('chart-flow.html', **context)
コード例 #13
0
ファイル: kard.py プロジェクト: mgravesCMG/kardboard
    def moving_median_abs_dev(self, year=None, month=None, day=None, weeks=4):
        """
        The moving median absolute deviation of cycle time for every day in the last N weeks.
        See http://en.wikipedia.org/wiki/Median_absolute_deviation
        """

        end_date = make_end_date(year, month, day)
        start_date = end_date - relativedelta(weeks=weeks)
        start_date = make_start_date(date=start_date)

        qs = self.done().filter(
            done_date__lte=end_date,
            done_date__gte=start_date,
        ).scalar('_cycle_time')

        cycle_times = [t for t in qs if t is not None]
        median_cycle_time = median(cycle_times)

        if median_cycle_time is not None:
            absolute_deviations = [math.fabs(median_cycle_time - c) for c in cycle_times]
            mad = median(absolute_deviations)
        else:
            mad = None

        if mad is None:
            mad = 0

        return int(round(mad))
コード例 #14
0
    def calculate(cls, start_date, end_date, group="all"):
        from kardboard.models import Kard
        from kardboard.models import ReportGroup

        start_date = make_start_date(date=start_date)
        end_date = make_end_date(date=end_date)

        try:
            record = cls.objects.get(
                group=group,
                start_date=start_date,
                end_date=end_date,
            )
        except cls.DoesNotExist:
            record = cls()
            record.start_date = start_date
            record.end_date = end_date
            record.group = group
            record.data = {}

        kards = ReportGroup(group,
            Kard.objects.filter(
                start_date__gte=start_date,
                start_date__lte=end_date,
            )
        )
        record.data = report_on_cards(kards)
        record.save()
        return record
コード例 #15
0
ファイル: views.py プロジェクト: brandonivey/kardboard
def value_txt_report(year_number, month_number, group="all"):
    start_date = munge_date(year=year_number, month=month_number, day=1)
    start_date = make_start_date(date=start_date)

    start_date, end_date = month_range(start_date)

    rg = ReportGroup(group, Kard.objects.done())
    done = rg.queryset

    cards = done.filter(done_date__gte=start_date,
        done_date__lte=end_date).order_by('-done_date')

    cards = [c for c in cards if c.is_card]

    context = {
        'title': "Completed Value Cards",
        'cards': cards,
        'start_date': start_date,
        'end_date': end_date,
        'updated_at': datetime.datetime.now(),
        'version': VERSION,
    }

    response = make_response(render_template('done-report.txt', **context))
    response.headers['Content-Type'] = "text/plain"
    return response
コード例 #16
0
    def moving_median_abs_dev(self, year=None, month=None, day=None, weeks=4):
        """
        The moving median absolute deviation of cycle time for every day in the last N weeks.
        See http://en.wikipedia.org/wiki/Median_absolute_deviation
        """

        end_date = make_end_date(year, month, day)
        start_date = end_date - relativedelta(weeks=weeks)
        start_date = make_start_date(date=start_date)

        qs = self.done().filter(
            done_date__lte=end_date,
            done_date__gte=start_date,
        ).scalar('_cycle_time')

        cycle_times = [t for t in qs if t is not None]
        median_cycle_time = median(cycle_times)

        if median_cycle_time is not None:
            absolute_deviations = [
                math.fabs(median_cycle_time - c) for c in cycle_times
            ]
            mad = median(absolute_deviations)
        else:
            mad = None

        if mad is None:
            mad = 0

        return int(round(mad))
コード例 #17
0
def _get_time_range(weeks):
    end = make_end_date(
        date=datetime.now()
    )
    start = make_start_date(
        date=end - relativedelta(weeks=weeks)
    )
    return start, end
コード例 #18
0
ファイル: moving_data.py プロジェクト: cmheisel/kardboard
def daily_throughput_average(report_group_slug, stop, weeks=4):
    start = (stop - relativedelta(days=weeks * 7)) + relativedelta(days=1)
    start = make_start_date(date=start)

    query = Kard.objects.filter(done_date__gte=start, done_date__lte=stop)

    kards = list(ReportGroup(report_group_slug, query).queryset)
    return len(kards) / float(weeks * 7)
コード例 #19
0
ファイル: views.py プロジェクト: vdreamakitex/kardboard
def report_efficiency(group="all", months=3):
    state_mappings = app.config.get("EFFICIENCY_MAPPINGS", None)
    if state_mappings is None:
        abort(404)
    stats = teams_service.EfficiencyStats(mapping=state_mappings)

    end = kardboard.util.now()
    months_ranges = month_ranges(end, months)

    start_day = make_start_date(date=months_ranges[0][0])
    end_day = make_end_date(date=end)

    records = FlowReport.objects.filter(date__gte=start_day, date__lte=end_day, group=group)

    incremented_state_counts = []
    for r in records:
        a_record = {"date": r.date}
        a_record.update(r.state_counts)
        incremented_state_counts.append(a_record)

    for group_name in app.config.get("EFFICIENCY_INCREMENTS", ()):
        stats.make_incremental(incremented_state_counts, group_name)

    data = []
    for r in incremented_state_counts:
        efficiency_stats = stats.calculate(r)
        data.append({"date": r["date"], "stats": efficiency_stats})

    chart = {}
    chart["categories"] = [report.date.strftime("%m/%d") for report in records]
    group_names = app.config.get("EFFICIENCY_MAPPINGS_ORDER", state_mappings.keys())
    series = []
    for group_name in group_names:
        seri_data = []
        for d in data:
            seri_data.append(d["stats"][group_name])
        seri = dict(name=group_name, data=seri_data)
        series.append(seri)
    chart["series"] = series

    table_data = []
    for row in data:
        table_row = {"Date": row["date"]}
        for group_name in group_names:
            table_row[group_name] = row["stats"][group_name]
        table_data.append(table_row)

    start_date = records.order_by("date").first().date
    context = {
        "title": "Efficiency",
        "start_date": start_date,
        "chart": chart,
        "table_data": table_data,
        "data_keys": ["Date"] + list(group_names),
        "updated_at": records.order_by("date")[len(records) - 1].date,
        "version": VERSION,
    }
    return render_template("chart-efficiency.html", **context)
コード例 #20
0
ファイル: views.py プロジェクト: vdreamakitex/kardboard
def report_detailed_flow(group="all", months=3, cards_only=False):
    end = kardboard.util.now()
    months_ranges = month_ranges(end, months)

    start_day = make_start_date(date=months_ranges[0][0])
    end_day = make_end_date(date=end)

    if cards_only:
        only_arg = ("state_card_counts", "date", "group")
    else:
        only_arg = ("state_counts", "date", "group")

    reports = FlowReport.objects.filter(date__gte=start_day, date__lte=end_day, group=group).only(*only_arg)
    if not reports:
        abort(404)

    chart = {}
    chart["categories"] = []

    series = []
    for state in States():
        seri = {"name": state, "data": []}
        series.append(seri)

    done_starting_point = 0
    for report in reports:
        chart["categories"].append(report.date.strftime("%m/%d"))
        for seri in series:
            if cards_only:
                daily_seri_data = report.state_card_counts.get(seri["name"], 0)
            else:
                daily_seri_data = report.state_counts.get(seri["name"], 0)

            if seri["name"] == "Done":
                if len(seri["data"]) == 0:
                    done_starting_point = daily_seri_data
                    daily_seri_data = 0
                else:
                    daily_seri_data = daily_seri_data - done_starting_point

            seri["data"].append(daily_seri_data)
    chart["series"] = series

    start_date = reports.order_by("date").first().date
    reports.order_by("-date")
    context = {
        "title": "Detailed Cumulative Flow",
        "reports": reports,
        "months": months,
        "cards_only": cards_only,
        "chart": chart,
        "start_date": start_date,
        "updated_at": reports[0].updated_at,
        "states": States(),
        "version": VERSION,
    }
    return render_template("report-detailed-flow.html", **context)
コード例 #21
0
def started_after_report(team_or_rg_name, start_date):
    start_date = make_start_date(date=start_date)
    cards = _get_cards(team_or_rg_name, start_date)

    columns = (
        'key',
        'team',
        'service_class',
        'type',
        'start_date',
        'done_date',
        'due_date',
        'cycle_time',
        'is_wip',
        'hit_due_date',
        'hit_sla',
        'time_in_otis',
        'time_wait_qa',
        'time_in_qa',
        'time_building',
        'time_elabo',
    )

    Row = namedtuple('Row', ' '.join(columns))
    rows = []
    for c in cards:
        row = Row(
            key=c.key,
            team=c.team,
            service_class=c.service_class['name'],
            type=_card_type(c),
            start_date=_format_date_or_empty(c.start_date),
            done_date=_format_date_or_empty(c.done_date),
            due_date=_format_date_or_empty(c.due_date),
            cycle_time=c.cycle_time or c.current_cycle_time(),
            is_wip=(c.done_date is None),
            hit_due_date=_hit_due_date(c),
            hit_sla=_hit_sla(c),
            time_in_otis=_time_in_otis(c),
            time_wait_qa=_time_wait_qa(c),
            time_in_qa=_time_in_qa(c),
            time_building=_time_building(c),
            time_elabo=_time_elabo(c),
        )
        rows.append(row)

    rows.insert(0, columns)

    report_filename = "%s_%s.csv" % (
        start_date.strftime('%Y-%m-%d'),
        slugify(team_or_rg_name)
    )

    writer = csv.writer(
        open(report_filename, 'w'),
    )
    writer.writerows(rows)
コード例 #22
0
ファイル: f2013.py プロジェクト: pombredanne/kardboard
def find_value_cards(year):
    start = make_start_date(year, 1, 1)
    end = make_end_date(year, 12, 31)

    query = Kard.objects.filter(done_date__gte=start, done_date__lte=end)
    rg = ReportGroup('dev', query)

    cards = [c for c in rg.queryset if c.is_card]
    return cards
コード例 #23
0
ファイル: moving_data.py プロジェクト: vdreamakitex/kardboard
def daily_throughput_average(report_group_slug, stop, weeks=4):
    start = (stop - relativedelta(days=weeks * 7)) + relativedelta(days=1)
    start = make_start_date(date=start)

    query = Kard.objects.filter(
        done_date__gte=start,
        done_date__lte=stop,)

    kards = list(ReportGroup(report_group_slug, query).queryset)
    return len(kards) / float(weeks * 7)
コード例 #24
0
ファイル: teams.py プロジェクト: shaunduncan/kardboard
    def done_in_range(self, start_date, end_date):
        end_date = make_end_date(date=end_date)
        start_date = make_start_date(date=start_date)

        done = Kard.objects.filter(
            team=self.team_name,
            done_date__gte=start_date,
            done_date__lte=end_date,
            _service_class__nin=self.exclude_classes,
        )
        return done
コード例 #25
0
ファイル: teams.py プロジェクト: thepeopleseason/kardboard
    def done_in_range(self, start_date, end_date):
        end_date = make_end_date(date=end_date)
        start_date = make_start_date(date=start_date)

        done = Kard.objects.filter(
            team=self.team_name,
            done_date__gte=start_date,
            done_date__lte=end_date,
            _service_class__nin=self.exclude_classes,
        )

        self._card_info(done)
        return done
コード例 #26
0
def report_cycle(group="all", months=3, year=None, month=None, day=None):
    today = datetime.datetime.today()
    if day:
        end_day = datetime.datetime(year=year, month=month, day=day)
        if end_day > today:
            end_day = today
    else:
        end_day = today

    start_day = end_day - relativedelta.relativedelta(months=months)
    start_day = make_start_date(date=start_day)
    end_day = make_end_date(date=end_day)

    records = DailyRecord.objects.filter(
        date__gte=start_day,
        date__lte=end_day,
        group=group)

    daily_moving_averages = [(r.date, r.moving_cycle_time) for r in records]
    daily_moving_lead = [(r.date, r.moving_lead_time) for r in records]
    daily_mad = [(r.date, r.moving_median_abs_dev) for r in records]

    start_date = daily_moving_averages[0][0]
    chart = {}
    chart['series'] = [
        {
            'name': 'Cycle time',
            'data': [r[1] for r in daily_moving_averages],
        },
        {
            'name': 'Unpredictability',
            'data': [r[1] for r in daily_mad],
        }
    ]
    chart['goal'] = app.config.get('CYCLE_TIME_GOAL', ())

    daily_moving_averages.reverse()  # reverse order for display
    daily_moving_lead.reverse()
    daily_mad.reverse()
    context = {
        'title': "How quick can we do it?",
        'updated_at': datetime.datetime.now(),
        'chart': chart,
        'months': months,
        'start_date': start_date,
        'daily_averages': daily_moving_averages,
        'daily_mad': daily_mad,
        'version': VERSION,
    }

    return render_template('report-cycle.html', **context)
コード例 #27
0
ファイル: views.py プロジェクト: brandonivey/kardboard
def report_service_class(group="all", months=None):
    from kardboard.app import app
    service_class_order = app.config.get('SERVICE_CLASSES', {}).keys()
    service_class_order.sort()
    service_classes = [
        app.config['SERVICE_CLASSES'][k] for k in service_class_order
    ]

    if months is None:
        # We want the current report
        try:
            scr = ServiceClassSnapshot.objects.get(
                group=group,
            )
        except ServiceClassSnapshot.DoesNotExist:
            scr = ServiceClassSnapshot.calculate(
                group=group,
            )
        time_range = 'current'
        start_date = make_start_date(date=datetime.datetime.now())
        end_date = make_end_date(date=datetime.datetime.now())
    else:
        start = now()
        months_ranges = month_ranges(start, months)
        start_date = months_ranges[0][0]
        end_date = months_ranges[-1][1]
        try:
            scr = ServiceClassRecord.objects.get(
                group=group,
                start_date=start_date,
                end_date=end_date,
            )
        except ServiceClassRecord.DoesNotExist:
            scr = ServiceClassRecord.calculate(
                group=group,
                start_date=start_date,
                end_date=end_date,
            )
        time_range = 'past %s months' % months

    context = {
        'title': "Service classes: %s" % time_range,
        'service_classes': service_classes,
        'data': scr.data,
        'start_date': start_date,
        'end_date': end_date,
        'updated_at': scr.updated_at,
        'version': VERSION,
    }

    return render_template('report-service-class.html', **context)
コード例 #28
0
ファイル: views.py プロジェクト: brandonivey/kardboard
def report_cycle(group="all", months=3, year=None, month=None, day=None):
    today = datetime.datetime.today()
    if day:
        end_day = datetime.datetime(year=year, month=month, day=day)
        if end_day > today:
            end_day = today
    else:
        end_day = today

    start_day = end_day - relativedelta.relativedelta(months=months)
    start_day = make_start_date(date=start_day)
    end_day = make_end_date(date=end_day)

    records = DailyRecord.objects.filter(
        date__gte=start_day,
        date__lte=end_day,
        group=group)

    daily_moving_averages = [(r.date, r.moving_cycle_time) for r in records]
    daily_moving_lead = [(r.date, r.moving_lead_time) for r in records]
    daily_mad = [(r.date, r.moving_median_abs_dev) for r in records]

    start_date = daily_moving_averages[0][0]
    chart = {}
    chart['series'] = [
        {
            'name': 'Cycle time',
            'data': [r[1] for r in daily_moving_averages],
        },
        {
            'name': 'Unpredictability',
            'data': [r[1] for r in daily_mad],
        }
    ]
    chart['goal'] = app.config.get('CYCLE_TIME_GOAL', ())

    daily_moving_averages.reverse()  # reverse order for display
    daily_moving_lead.reverse()
    daily_mad.reverse()
    context = {
        'title': "How quick can we do it?",
        'updated_at': datetime.datetime.now(),
        'chart': chart,
        'months': months,
        'start_date': start_date,
        'daily_averages': daily_moving_averages,
        'daily_mad': daily_mad,
        'version': VERSION,
    }

    return render_template('report-cycle.html', **context)
コード例 #29
0
ファイル: views.py プロジェクト: GregMeno/kardboard
def chart_cycle_distribution(group="all", months=3):
    ranges = (
        (0, 4, "< 5 days"),
        (5, 10, "5-10 days"),
        (11, 15, "11-15 days"),
        (16, 20, "16-20 days"),
        (21, 25, "21-25 days"),
        (26, 30, "26-30 days",),
        (31, 9999, "> 30 days"),
    )
    today = datetime.datetime.today()
    start_day = today - relativedelta.relativedelta(months=months)
    start_day = make_start_date(date=start_day)
    end_day = make_end_date(date=today)

    context = {
        'title': "How quick can we do it?",
        'updated_at': datetime.datetime.now(),
        'version': VERSION,
    }

    query = Q(done_date__gte=start_day) & Q(done_date__lte=end_day)
    rg = ReportGroup(group, Kard.objects.filter(query))

    total = rg.queryset.count()
    if total == 0:
        context = {
            'error': "Zero cards were completed in the past %s months" % months
        }
        return render_template('chart-cycle-distro.html', **context)

    distro = []
    for row in ranges:
        lower, upper, label = row
        query = Q(done_date__gte=start_day) & Q(done_date__lte=end_day) & \
            Q(_cycle_time__gte=lower) & Q(_cycle_time__lte=upper)
        pct = ReportGroup(group, Kard.objects.filter(query)).queryset.count() / float(total)
        distro.append((label, pct))

    chart = CycleDistributionChart(700, 400)
    chart.add_data([r[1] for r in distro])
    chart.set_pie_labels([r[0] for r in distro])
    context = {
        'data': distro,
        'chart': chart,
        'title': "How quick can we do it?",
        'updated_at': datetime.datetime.now(),
        'distro': distro,
        'version': VERSION,
    }
    return render_template('chart-cycle-distro.html', **context)
コード例 #30
0
    def _date(self, dtype, date=None, days=0):
        from kardboard.util import make_end_date, make_start_date
        from kardboard.util import now

        if not date:
            date = now()

        if dtype == "start":
            date = make_start_date(date=date)
        elif dtype == "end":
            date = make_end_date(date=date)

        date = date + relativedelta(days=days)
        return date
コード例 #31
0
ファイル: stddev.py プロジェクト: josephjo/kardboard
def year_std_dev(year):
    year_start = make_start_date(date=datetime(year, 1, 1))
    year_end = make_end_date(date=datetime(year, 12, 31))

    rg = ReportGroup('dev', Kard.objects.filter(start_date__gte=year_start, done_date__lte=year_end))

    cards = [c for c in rg.queryset if c.is_card]
    cycle_times = [c.cycle_time for c in cards]

    data = {}
    data['n'] = len(cards)
    data['ave'] = average(cycle_times)
    data['std'] = standard_deviation(cycle_times)
    return data
コード例 #32
0
    def _date(self, dtype, date=None, days=0):
        from kardboard.util import make_end_date, make_start_date
        from kardboard.util import now

        if not date:
            date = now()

        if dtype == 'start':
            date = make_start_date(date=date)
        elif dtype == 'end':
            date = make_end_date(date=date)

        date = date + relativedelta(days=days)
        return date
コード例 #33
0
ファイル: views.py プロジェクト: nthdegreeburns/kardboard
def report_cycle_distribution(group="all", months=3):
    ranges = (
        (0, 4, "Less than 5 days"),
        (5, 10, "5-10 days"),
        (11, 15, "11-15 days"),
        (16, 20, "16-20 days"),
        (21, 25, "21-25 days"),
        (26, 30, "26-30 days"),
        (31, 9999, "> 30 days"),
    )
    today = datetime.datetime.today()
    start_day = today - relativedelta.relativedelta(months=months)
    start_day = make_start_date(date=start_day)
    end_day = make_end_date(date=today)

    context = {"title": "How quick can we do it?", "updated_at": datetime.datetime.now(), "version": VERSION}

    query = Q(done_date__gte=start_day) & Q(done_date__lte=end_day)
    rg = ReportGroup(group, Kard.objects.filter(query))

    total = rg.queryset.count()
    if total == 0:
        context = {"error": "Zero cards were completed in the past %s months" % months}
        return render_template("report-cycle-distro.html", **context)

    distro = []
    for row in ranges:
        lower, upper, label = row
        query = (
            Q(done_date__gte=start_day)
            & Q(done_date__lte=end_day)
            & Q(_cycle_time__gte=lower)
            & Q(_cycle_time__lte=upper)
        )
        pct = ReportGroup(group, Kard.objects.filter(query)).queryset.count() / float(total)
        pct = round(pct, 2)
        distro.append((label, pct))

    chart = {}
    chart["data"] = distro

    context = {
        "data": distro,
        "chart": chart,
        "title": "How quick can we do it?",
        "updated_at": datetime.datetime.now(),
        "version": VERSION,
    }
    return render_template("report-cycle-distro.html", **context)
コード例 #34
0
ファイル: core.py プロジェクト: nthdegreeburns/kardboard
    def _set_up_records(self):
        from kardboard.util import make_start_date
        from kardboard.util import make_end_date

        start_date = datetime.datetime(2011, 1, 1)
        end_date = datetime.datetime(2011, 6, 30)

        start_date = make_start_date(date=start_date)
        end_date = make_end_date(date=end_date)

        current_date = start_date
        while current_date <= end_date:
            r = self.make_record(current_date)
            r.save()
            current_date = current_date + relativedelta(days=1)
コード例 #35
0
    def _set_up_records(self):
        from kardboard.util import make_start_date
        from kardboard.util import make_end_date

        start_date = datetime.datetime(2011, 1, 1)
        end_date = datetime.datetime(2011, 6, 30)

        start_date = make_start_date(date=start_date)
        end_date = make_end_date(date=end_date)

        current_date = start_date
        while current_date <= end_date:
            r = self.make_record(current_date)
            r.save()
            current_date = current_date + relativedelta(days=1)
コード例 #36
0
ファイル: kard.py プロジェクト: cmheisel/kardboard
    def moving_lead_time(self, year=None, month=None, day=None, weeks=4):
        """
        The moving average of lead time for every day in the last N weeks.
        """

        end_date = make_end_date(year, month, day)
        start_date = end_date - relativedelta(weeks=weeks)
        start_date = make_start_date(date=start_date)

        qs = self.done().filter(done_date__lte=end_date, done_date__gte=start_date)

        average = qs.average("_lead_time")
        if math.isnan(average):
            average = 0

        return int(round(average))
コード例 #37
0
def report_service_class(group="all", months=None):
    from kardboard.app import app
    service_class_order = app.config.get('SERVICE_CLASSES', {}).keys()
    service_class_order.sort()
    service_classes = [
        app.config['SERVICE_CLASSES'][k] for k in service_class_order
    ]

    if months is None:
        # We want the current report
        try:
            scr = ServiceClassSnapshot.objects.get(group=group, )
        except ServiceClassSnapshot.DoesNotExist:
            scr = ServiceClassSnapshot.calculate(group=group, )
        time_range = 'current'
        start_date = make_start_date(date=datetime.datetime.now())
        end_date = make_end_date(date=datetime.datetime.now())
    else:
        start = now()
        months_ranges = month_ranges(start, months)
        start_date = months_ranges[0][0]
        end_date = months_ranges[-1][1]
        try:
            scr = ServiceClassRecord.objects.get(
                group=group,
                start_date=start_date,
                end_date=end_date,
            )
        except ServiceClassRecord.DoesNotExist:
            scr = ServiceClassRecord.calculate(
                group=group,
                start_date=start_date,
                end_date=end_date,
            )
        time_range = 'past %s months' % months

    context = {
        'title': "Service classes: %s" % time_range,
        'service_classes': service_classes,
        'data': scr.data,
        'start_date': start_date,
        'end_date': end_date,
        'updated_at': scr.updated_at,
        'version': VERSION,
    }

    return render_template('report-service-class.html', **context)
コード例 #38
0
def card_block(key):
    try:
        card = Kard.objects.get(key=key)
        action = 'block'
        if card.blocked:
            action = 'unblock'
    except Kard.DoesNotExist:
        abort(404)

    now = datetime.datetime.now()
    if action == 'block':
        f = CardBlockForm(request.form, blocked_at=now)
    if action == 'unblock':
        f = CardUnblockForm(request.form, unblocked_at=now)

    if 'cancel' in request.form.keys():
        return True  # redirect
    elif request.method == "POST" and f.validate():
        if action == 'block':
            blocked_at = datetime.datetime.combine(f.blocked_at.data,
                                                   datetime.time())
            blocked_at = make_start_date(date=blocked_at)
            result = card.block(f.reason.data, blocked_at)
            if result:
                card.save()
                flash("%s blocked" % card.key)
                return True  # redirect
        if action == 'unblock':
            unblocked_at = datetime.datetime.combine(f.unblocked_at.data,
                                                     datetime.time())
            unblocked_at = make_end_date(date=unblocked_at)
            result = card.unblock(unblocked_at)
            if result:
                card.save()
                flash("%s unblocked" % card.key)
                return True  # redurect

    context = {
        'title': "%s a card" % (action.capitalize(), ),
        'action': action,
        'card': card,
        'form': f,
        'updated_at': datetime.datetime.now(),
        'version': VERSION,
    }

    return render_template('card-block.html', **context)
コード例 #39
0
ファイル: views.py プロジェクト: GregMeno/kardboard
def card_block(key):
    try:
        card = Kard.objects.get(key=key)
        action = 'block'
        if card.blocked:
            action = 'unblock'
    except Kard.DoesNotExist:
        abort(404)

    now = datetime.datetime.now()
    if action == 'block':
        f = CardBlockForm(request.form, blocked_at=now)
    if action == 'unblock':
        f = CardUnblockForm(request.form, unblocked_at=now)

    if 'cancel' in request.form.keys():
        return True  # redirect
    elif request.method == "POST" and f.validate():
        if action == 'block':
            blocked_at = datetime.datetime.combine(
                f.blocked_at.data, datetime.time())
            blocked_at = make_start_date(date=blocked_at)
            result = card.block(f.reason.data, blocked_at)
            if result:
                card.save()
                flash("%s blocked" % card.key)
                return True  # redirect
        if action == 'unblock':
            unblocked_at = datetime.datetime.combine(
                f.unblocked_at.data, datetime.time())
            unblocked_at = make_end_date(date=unblocked_at)
            result = card.unblock(unblocked_at)
            if result:
                card.save()
                flash("%s unblocked" % card.key)
                return True  # redurect

    context = {
        'title': "%s a card" % (action.capitalize(), ),
        'action': action,
        'card': card,
        'form': f,
        'updated_at': datetime.datetime.now(),
        'version': VERSION,
    }

    return render_template('card-block.html', **context)
コード例 #40
0
def main():
    oldest_card = Kard.objects.all().order_by('+backlog_date')[0]
    start_date = make_start_date(date=oldest_card.backlog_date)
    end_date = make_end_date(date=datetime.datetime.now())

    print "Daily records: %s" % DailyRecord.objects.count()
    print "Creating daily records"
    print "%s --> %s" % (start_date, end_date)

    days = end_date - start_date
    print "Going back %s days" % days.days

    r = queue_daily_record_updates.apply(args=(days.days,))
    r.get()

    print "DONE!"
    print "Daily records: %s" % DailyRecord.objects.count()
コード例 #41
0
def main():
    oldest_card = Kard.objects.all().order_by('+backlog_date')[0]
    start_date = make_start_date(date=oldest_card.backlog_date)
    end_date = make_end_date(date=datetime.datetime.now())

    print "Daily records: %s" % DailyRecord.objects.count()
    print "Creating daily records"
    print "%s --> %s" % (start_date, end_date)

    days = end_date - start_date
    print "Going back %s days" % days.days

    r = queue_daily_record_updates.apply(args=(days.days, ))
    r.get()

    print "DONE!"
    print "Daily records: %s" % DailyRecord.objects.count()
コード例 #42
0
ファイル: views.py プロジェクト: antiface/kardboard
def card_block(key):
    try:
        card = Kard.objects.get(key=key)
        action = "block"
        if card.blocked:
            action = "unblock"
    except Kard.DoesNotExist:
        abort(404)

    now = datetime.datetime.now()
    if action == "block":
        f = CardBlockForm(request.form, blocked_at=now)
    if action == "unblock":
        f = CardUnblockForm(request.form, unblocked_at=now)

    if "cancel" in request.form.keys():
        return True  # redirect
    elif request.method == "POST" and f.validate():
        if action == "block":
            blocked_at = datetime.datetime.combine(f.blocked_at.data, datetime.time())
            blocked_at = make_start_date(date=blocked_at)
            result = card.block(f.reason.data, blocked_at)
            if result:
                card.save()
                flash("%s blocked" % card.key)
                return True  # redirect
        if action == "unblock":
            unblocked_at = datetime.datetime.combine(f.unblocked_at.data, datetime.time())
            unblocked_at = make_end_date(date=unblocked_at)
            result = card.unblock(unblocked_at)
            if result:
                card.save()
                flash("%s unblocked" % card.key)
                return True  # redurect

    context = {
        "title": "%s a card" % (action.capitalize(),),
        "action": action,
        "card": card,
        "form": f,
        "updated_at": datetime.datetime.now(),
        "version": VERSION,
    }

    return render_template("card-block.html", **context)
コード例 #43
0
def report_flow(group="all", months=3):
    end = kardboard.util.now()
    months_ranges = month_ranges(end, months)

    start_day = make_start_date(date=months_ranges[0][0])
    end_day = make_end_date(date=end)

    records = DailyRecord.objects.filter(date__gte=start_day,
                                         date__lte=end_day,
                                         group=group)

    chart = {}
    chart['categories'] = [report.date.strftime("%m/%d") for report in records]
    series = [
        {
            'name': "Planning",
            'data': []
        },
        {
            'name': "Todo",
            'data': []
        },
        {
            'name': "Done",
            'data': []
        },
    ]
    for row in records:
        series[0]['data'].append(row.backlog)
        series[1]['data'].append(row.in_progress)
        series[2]['data'].append(row.done)
    chart['series'] = series

    start_date = records.order_by('date').first().date
    records.order_by('-date')
    context = {
        'title': "Cumulative Flow",
        'updated_at': datetime.datetime.now(),
        'chart': chart,
        'start_date': start_date,
        'flowdata': records,
        'version': VERSION,
    }
    return render_template('chart-flow.html', **context)
コード例 #44
0
    def moving_lead_time(self, year=None, month=None, day=None, weeks=4):
        """
        The moving average of lead time for every day in the last N weeks.
        """

        end_date = make_end_date(year, month, day)
        start_date = end_date - relativedelta(weeks=weeks)
        start_date = make_start_date(date=start_date)

        qs = self.done().filter(
            done_date__lte=end_date,
            done_date__gte=start_date,
        )

        average = qs.average('_lead_time')
        if math.isnan(average):
            average = 0

        return int(round(average))
コード例 #45
0
ファイル: kard.py プロジェクト: cmheisel/kardboard
    def moving_std_dev(self, year=None, month=None, day=None, weeks=4):
        """
        The moving cycle time standard deviation for every day in the last N weeks.
        """

        end_date = make_end_date(year, month, day)
        start_date = end_date - relativedelta(weeks=weeks)
        start_date = make_start_date(date=start_date)

        qs = self.done().filter(done_date__lte=end_date, done_date__gte=start_date).scalar("_cycle_time")

        cycle_times = [t for t in qs if t is not None]
        stdev = standard_deviation(cycle_times)
        if stdev is not None:
            stdev = int(round(stdev))
        else:
            stdev = 0

        return stdev
コード例 #46
0
ファイル: views.py プロジェクト: vdreamakitex/kardboard
def report_cycle(group="all", months=3, year=None, month=None, day=None):
    today = datetime.datetime.today()
    if day:
        end_day = datetime.datetime(year=year, month=month, day=day)
        if end_day > today:
            end_day = today
    else:
        end_day = today

    start_day = end_day - relativedelta.relativedelta(months=months)
    start_day = make_start_date(date=start_day)
    end_day = make_end_date(date=end_day)

    records = DailyRecord.objects.filter(date__gte=start_day, date__lte=end_day, group=group)

    daily_moving_averages = [(r.date, r.moving_cycle_time) for r in records]
    daily_moving_lead = [(r.date, r.moving_lead_time) for r in records]
    daily_mad = [(r.date, r.moving_median_abs_dev) for r in records]

    start_date = daily_moving_averages[0][0]
    chart = {}
    chart["series"] = [
        {"name": "Cycle time", "data": [r[1] for r in daily_moving_averages]},
        {"name": "Unpredictability", "data": [r[1] for r in daily_mad]},
    ]
    chart["goal"] = app.config.get("CYCLE_TIME_GOAL", ())

    daily_moving_averages.reverse()  # reverse order for display
    daily_moving_lead.reverse()
    daily_mad.reverse()
    context = {
        "title": "How quick can we do it?",
        "updated_at": datetime.datetime.now(),
        "chart": chart,
        "months": months,
        "start_date": start_date,
        "daily_averages": daily_moving_averages,
        "daily_mad": daily_mad,
        "version": VERSION,
    }

    return render_template("report-cycle.html", **context)
コード例 #47
0
    def moving_std_dev(self, year=None, month=None, day=None, weeks=4):
        """
        The moving cycle time standard deviation for every day in the last N weeks.
        """

        end_date = make_end_date(year, month, day)
        start_date = end_date - relativedelta(weeks=weeks)
        start_date = make_start_date(date=start_date)

        qs = self.done().filter(
            done_date__lte=end_date,
            done_date__gte=start_date,
        ).scalar('_cycle_time')

        cycle_times = [t for t in qs if t is not None]
        stdev = standard_deviation(cycle_times)
        if stdev is not None:
            stdev = int(round(stdev))
        else:
            stdev = 0

        return stdev
コード例 #48
0
    def moving_cycle_time(self, year=None, month=None, day=None, weeks=4):
        """
        The moving average of cycle time for every day in the last N weeks.
        """

        end_date = make_end_date(year, month, day)
        start_date = end_date - relativedelta(weeks=weeks)
        start_date = make_start_date(date=start_date)

        qs = self.done().filter(
            done_date__lte=end_date,
            done_date__gte=start_date,
        )

        try:
            average = qs.average('_cycle_time')
        except TypeError:
            average = float('nan')

        if math.isnan(average):
            return 0

        return int(round(average))
コード例 #49
0
def _get_time_range(weeks, start=None, end=None):
    if end is None:
        end = datetime.now()
    if start is None:
        start = end - relativedelta(weeks=weeks)
    return make_start_date(date=start), make_end_date(date=end)
コード例 #50
0
def report_efficiency(group="all", months=3):
    state_mappings = app.config.get('EFFICIENCY_MAPPINGS', None)
    if state_mappings is None:
        abort(404)
    stats = teams_service.EfficiencyStats(mapping=state_mappings)

    end = kardboard.util.now()
    months_ranges = month_ranges(end, months)

    start_day = make_start_date(date=months_ranges[0][0])
    end_day = make_end_date(date=end)

    records = FlowReport.objects.filter(date__gte=start_day,
                                        date__lte=end_day,
                                        group=group)

    incremented_state_counts = []
    for r in records:
        a_record = {'date': r.date}
        a_record.update(r.state_counts)
        incremented_state_counts.append(a_record)

    for group_name in app.config.get('EFFICIENCY_INCREMENTS', ()):
        stats.make_incremental(incremented_state_counts, group_name)

    data = []
    for r in incremented_state_counts:
        efficiency_stats = stats.calculate(r)
        data.append({'date': r['date'], 'stats': efficiency_stats})

    chart = {}
    chart['categories'] = [report.date.strftime("%m/%d") for report in records]
    group_names = app.config.get('EFFICIENCY_MAPPINGS_ORDER',
                                 state_mappings.keys())
    series = []
    for group_name in group_names:
        seri_data = []
        for d in data:
            seri_data.append(d['stats'][group_name])
        seri = dict(name=group_name, data=seri_data)
        series.append(seri)
    chart['series'] = series

    table_data = []
    for row in data:
        table_row = {'Date': row['date']}
        for group_name in group_names:
            table_row[group_name] = row['stats'][group_name]
        table_data.append(table_row)

    start_date = records.order_by('date').first().date
    context = {
        'title': "Efficiency",
        'start_date': start_date,
        'chart': chart,
        'table_data': table_data,
        'data_keys': [
            'Date',
        ] + list(group_names),
        'updated_at': records.order_by('date')[len(records) - 1].date,
        'version': VERSION,
    }
    return render_template('chart-efficiency.html', **context)
コード例 #51
0
def report_cycle_distribution(group="all", months=3, limit=None):
    defects_only, cards_only = False, False
    if limit == 'cards':
        cards_only = True
    if limit == 'defects':
        defects_only = True

    ranges = (
        (0, 4, "Less than 5 days"),
        (5, 10, "5-10 days"),
        (11, 15, "11-15 days"),
        (16, 20, "16-20 days"),
        (21, 25, "21-25 days"),
        (
            26,
            30,
            "26-30 days",
        ),
        (31, 9999, "> 30 days"),
    )
    today = datetime.datetime.today()
    start_day = today - relativedelta.relativedelta(months=months)
    start_day = make_start_date(date=start_day)
    end_day = make_end_date(date=today)

    context = {
        'title': "How quick can we do it?",
        'updated_at': datetime.datetime.now(),
        'version': VERSION,
    }

    query = Q(done_date__gte=start_day) & Q(done_date__lte=end_day)
    if defects_only:
        query = query & Q(_type__in=app.config.get('DEFECT_TYPES', []))
    elif cards_only:
        query = query & Q(_type__nin=app.config.get('DEFECT_TYPES', []))
    rg = ReportGroup(group, Kard.objects.filter(query))

    total = rg.queryset.count()
    if total == 0:
        context = {
            'error': "Zero cards were completed in the past %s months" % months
        }
        return render_template('report-cycle-distro.html', **context)

    distro = []
    for row in ranges:
        lower, upper, label = row
        query = Q(done_date__gte=start_day) & Q(done_date__lte=end_day) & \
            Q(_cycle_time__gte=lower) & Q(_cycle_time__lte=upper)
        if defects_only:
            query = query & Q(_type__in=app.config.get('DEFECT_TYPES', []))
        else:
            query = query & Q(_type__nin=app.config.get('DEFECT_TYPES', []))
        pct = ReportGroup(
            group, Kard.objects.filter(query)).queryset.count() / float(total)
        pct = round(pct, 2)
        distro.append((label, pct))

    chart = {}
    chart['data'] = distro

    context = {
        'data': distro,
        'chart': chart,
        'title': "How quick can we do it?",
        'months': months,
        'total': total,
        'updated_at': datetime.datetime.now(),
        'version': VERSION,
    }
    if defects_only:
        context['title'] = "Defects: %s" % (context['title'])
        context['card_type'] = 'defects'
    elif cards_only:
        context['title'] = "Cards: %s" % (context['title'])
        context['card_type'] = 'cards'
    else:
        context['title'] = "All: %s" % (context['title'])
        context['card_type'] = 'cards and defects'

    return render_template('report-cycle-distro.html', **context)
コード例 #52
0
def report_cycle_distribution(group="all", months=3, limit=None):
    from kardboard.services.reports import CycleTimeDistribution

    defects_only, cards_only = False, False
    if limit == 'cards':
        cards_only = True
    if limit == 'defects':
        defects_only = True

    today = datetime.datetime.today()
    start_day = today - relativedelta.relativedelta(months=months)
    start_day = make_start_date(date=start_day)
    end_day = make_end_date(date=today)

    context = {
        'title': "How quick can we do it?",
        'updated_at': datetime.datetime.now(),
        'version': VERSION,
    }

    query = Q(done_date__gte=start_day) & Q(done_date__lte=end_day)
    if defects_only:
        query = query & Q(_type__in=app.config.get('DEFECT_TYPES', []))
    elif cards_only:
        query = query & Q(_type__nin=app.config.get('DEFECT_TYPES', []))
    rg = ReportGroup(group, Kard.objects.filter(query))

    cards = list(rg.queryset)

    total = len(cards)
    if total == 0:
        context = {
            'error':
            "Zero cards were completed in the past %s months" % months,
        }
        return render_template('report-cycle-distro.html', **context)

    cdr = CycleTimeDistribution(cards=cards)

    chart = {}
    chart['categories'] = cdr.days()
    chart['series'] = []

    service_class_series = cdr.service_class_series()
    sclasses = service_class_series.keys()
    sclasses.sort()

    for sclass in sclasses:
        seri = service_class_series[sclass]
        chart['series'].append(dict(name=sclass, data=seri))

    context = {
        'histogram_data': cdr.histogram(),
        'chart': chart,
        'title': "How quick can we do it?",
        'months': months,
        'total': total,
        'updated_at': datetime.datetime.now(),
        'version': VERSION,
    }
    if defects_only:
        context['title'] = "Defects: %s" % (context['title'])
        context['card_type'] = 'defects'
    elif cards_only:
        context['title'] = "Cards: %s" % (context['title'])
        context['card_type'] = 'cards'
    else:
        context['title'] = "All: %s" % (context['title'])
        context['card_type'] = 'cards and defects'

    return render_template('report-cycle-distro.html', **context)