Example #1
0
def _create_known_bugs_table(
    sheet, project: Project, teams: List[Team],
    offset=Pos()) -> Tuple[Dict[Team, CellReference], Region]:
    dev_teams: List[DevTeam] = [team for team in teams if team.is_dev()]

    header_table = _create_known_bugs_table_header(sheet, offset)

    total_cells_by_teams = {}
    cells_offset = header_table.pos_below()
    row = 0
    for team in dev_teams:
        write_row(
            sheet,
            offset=RelPos(cells_offset, row, 1),
            cell_generator=[
                team.name, project.known_bugs_count[team],
                calculate_new_bugs_count_for_project(project, team),
                [
                    f'=SUM('
                    f'{RelPos(cells_offset, row, 2).to_cell()}:{RelPos(cells_offset, row, 3).to_cell()}'
                    f') * {team.bugfix_rate} / 5',
                    formats.bold_total_no_borders_format
                ]
            ],
            cell_format=formats.numeric_format)
        total_cells_by_teams[team] = CellReference(
            RelPos(cells_offset, row, 4, sheet_name=project.name),
            f'{project.name} bugfix')
        row += 1

    return \
        total_cells_by_teams, \
        Region(header_table.offset, header_table.rows + len(dev_teams), header_table.columns)
Example #2
0
def _create_dev_activities_table(
    sheet, project: Project, teams: List[Team],
    offset=Pos()) -> Tuple[Dict[Team, CellReference], Region]:
    dev_owned_issues = [
        x for x in project.issues
        if x.owned_by_team is not None and x.owned_by_team.is_dev()
    ]
    if not dev_owned_issues:
        return dict(), Region(offset, 1, 0)

    header_table = _create_project_table_header(sheet, teams, offset)

    for row in range(0, len(dev_owned_issues)):
        issue = dev_owned_issues[row]
        rel_offset = RelPos(header_table.pos_below(), row)
        write_row(sheet,
                  rel_offset,
                  cell_generator=_create_cells_for_issue(
                      issue, teams, rel_offset),
                  cell_format=formats.numeric_format)

    # totals row
    _add_totals_row(
        sheet,
        Region(header_table.pos_below(), len(dev_owned_issues),
               header_table.columns), 4)

    # adjust column widths
    sheet.set_column(
        offset.column + 1, offset.column + 1,
        max(int(len(x.issue_summary) * 0.75)
            for x in dev_owned_issues) if dev_owned_issues else 10)
    sheet.set_column(
        offset.column, offset.column,
        max(len(x.issue_key)
            for x in dev_owned_issues) if dev_owned_issues else 10)

    # cell references to totals for every team incl dev and qa
    total_cells_by_team = {}
    dev_teams = [x for x in teams if x.is_dev()]
    team_column = header_table.offset.column + 11 + 2 * len(dev_teams)
    for team in dev_teams:
        total_cells_by_team[team] = CellReference(
            RelPos(offset,
                   header_table.pos_below().row + len(dev_owned_issues),
                   team_column, project.name), project.name)
        team_column += 1

    qa_teams = [x for x in teams if x.is_qa()]
    team_column = header_table.offset.column + 12 + 3 * len(dev_teams)
    for team in qa_teams:
        total_cells_by_team[team] = CellReference(
            RelPos(offset,
                   header_table.pos_below().row + len(dev_owned_issues),
                   team_column, project.name), f'{project.name} checks')
        team_column += 1

    return \
        total_cells_by_team, \
        Region(header_table.offset, header_table.rows + len(dev_owned_issues) + 1, header_table.columns)
Example #3
0
def _create_team_capacity_table(
    sheet, start_date: date, end_date: date, team: Team, offset: Pos = Pos()
) -> Region:
    sheet.write(offset.row, offset.column, 'People', formats.green_header_format)
    column_count = write_row(
        sheet,
        RelPos(offset, 0, 1),
        cell_generator=(x.strftime(MONTH_FORMAT) for x in get_months_range(start_date, end_date)),
        cell_format=formats.green_header_format
    )

    v_offset = offset.row + 1
    for worker in team.members:
        sheet.write(v_offset, offset.column, worker.name)
        write_row(
            sheet,
            Pos(v_offset, offset.column + 1),
            cell_generator=(worker.efficiency(dt) for dt in get_months_range(start_date, end_date)),
            cell_format=formats.numeric_format
        )
        v_offset += 1

    sheet.write(offset.row + len(team.members) + 1, 0, 'Total', formats.bold_total_format)
    write_row(
        sheet,
        RelPos(offset, len(team.members) + 1, 1),
        cell_func=lambda col, _:
            f'=SUM({RelPos(offset, 1, col).to_cell()}:{RelPos(offset, len(team.members), col).to_cell()})',
        col_count=column_count,
        cell_format=formats.bold_total_format
    )

    return Region(Pos(0, 0), 2 + len(team.members), column_count)
Example #4
0
def save_metadata(sheet, start_date: date, end_date: date,
                  allocations_by_team: Dict[Team, Dict[str, Region]]):
    offset = Pos(0, 0)
    write_row(sheet, offset, cell_generator=[METADATA_HEADER])
    write_row(sheet,
              RelPos(offset, 1),
              cell_generator=[
                  'Period',
                  start_date.isoformat(),
                  end_date.isoformat()
              ])
    write_row(sheet, RelPos(offset, 2), cell_generator=['Team calendars'])
    offset = RelPos(offset, 3)
    row = 0
    for team, allocations in allocations_by_team.items():
        write_row(sheet,
                  RelPos(offset, row),
                  cell_generator=['Team', team.name])
        row += 1
        for item_name, table_pos in allocations.items():
            write_row(sheet,
                      RelPos(offset, row),
                      cell_generator=[
                          'Item', item_name, table_pos.offset.row,
                          table_pos.offset.column, table_pos.rows,
                          table_pos.columns
                      ])
            row += 1
Example #5
0
def _create_known_bugs_table_header(sheet, offset: Pos) -> Region:
    write_row(sheet,
              offset,
              cell_generator=[
                  '', ['Team', formats.centered_header_format], 'Known bugs',
                  'New bugs', 'Time to fix'
              ],
              cell_format=formats.centered_vertical_text_header_format,
              col_width=5)
    return Region(offset, 1, 5)
Example #6
0
def _add_totals_row(sheet, region: Region, skip_columns: int = 0):
    totals = []
    for column in range(0, region.columns):
        if column == 0:
            totals.append('Total')
        elif column >= skip_columns:
            totals.append(
                f'=SUM('
                f'{RelPos(region.offset, column=column).to_cell()}'
                f':{RelPos(region.offset, region.rows - 1, column).to_cell()}'
                f')')
        else:
            totals.append('')
    offset = RelPos(region.offset, region.rows)
    write_row(sheet, offset, totals, cell_format=formats.bold_total_format)
Example #7
0
def _create_qa_activities_table(
        sheet, project: Project, teams: List[Team],
        offset: Pos) -> Tuple[Dict[Team, List[CellReference]], Region]:
    qa_owned_issues = [
        x for x in project.issues
        if x.owned_by_team is not None and x.owned_by_team.is_qa()
    ]
    if not qa_owned_issues:
        return dict(), Region(offset, 1, 0)

    qa_teams = [team for team in teams if team.is_qa()]

    header_table = _create_qa_activities_table_header(sheet, qa_teams, offset)

    total_cells_by_teams = {}
    for row in range(0, len(qa_owned_issues)):
        issue = qa_owned_issues[row]
        rel_offset = RelPos(header_table.pos_below(), row)
        write_row(sheet,
                  rel_offset,
                  cell_generator=_create_cells_for_qa_issue(
                      issue, qa_teams, rel_offset),
                  cell_format=formats.numeric_format)

        col = 2
        for team in qa_teams:
            if team not in total_cells_by_teams:
                total_cells_by_teams[team] = []

            total_cells_by_teams[team].append(
                CellReference(
                    RelPos(rel_offset, column=col, sheet_name=project.name),
                    issue.issue_summary))
            col += 1

    # totals row
    _add_totals_row(
        sheet,
        Region(header_table.pos_below(), len(qa_owned_issues),
               header_table.columns), 2)

    return \
        total_cells_by_teams, \
        Region(header_table.offset, header_table.rows + len(qa_owned_issues) + 1, header_table.columns)
Example #8
0
def _create_qa_activities_table_header(sheet, qa_teams: List[Team],
                                       offset: Pos) -> Region:
    merge_cells(sheet, RelPos(offset, 0, 0), RelPos(offset, 1, 0), 'Key',
                formats.centered_header_format)
    merge_cells(sheet, RelPos(offset, 0, 1), RelPos(offset, 1, 1), 'Summary',
                formats.centered_header_format)

    rel_offset = RelPos(offset, 0, 2)
    merge_cells(sheet, rel_offset, RelPos(rel_offset, 0, len(qa_teams)),
                'QA effort', formats.centered_header_border_format)

    rel_offset = RelPos(rel_offset, 1, 0)
    write_row(
        sheet,
        rel_offset,
        cell_generator=[[
            qa_teams[i].name, formats.centered_vertical_text_header_format if i
            != 0 else formats.centered_vertical_text_header_left_border_format
        ] for i in range(len(qa_teams))] +
        [['Total', formats.centered_vertical_text_header_right_border_format]],
        cell_format=formats.centered_vertical_text_header_format,
        col_width=5)
    return Region(offset, 2, 3 + len(qa_teams))
Example #9
0
def _create_project_table_header(sheet, teams: List[Team],
                                 offset=Pos()) -> Region:
    dev_teams = [team for team in teams if team.is_dev()]
    qa_teams = [team for team in teams if team.is_qa()]

    column_count = 14 + 3 * len(dev_teams) + len(qa_teams)

    merge_cells(sheet, RelPos(offset, 1, 0), RelPos(offset, 2, 0), 'Key',
                formats.centered_header_format)
    merge_cells(sheet, RelPos(offset, 1, 1), RelPos(offset, 2, 1), 'Summary',
                formats.centered_header_format)

    merge_cells(sheet, RelPos(offset, 1, 2), RelPos(offset, 1, 3),
                'Confidence', formats.centered_header_border_format)

    _, col = merge_cells(sheet,
                         RelPos(offset, 1, 4),
                         RelPos(offset, 2, 4),
                         'Arch design',
                         formats.centered_vertical_text_header_format,
                         width=5)

    merge_cells(sheet, RelPos(offset, 1, 5),
                RelPos(offset, 1, 5 + len(dev_teams)), 'Impl & unit tests',
                formats.centered_header_border_format)

    rel_offset = RelPos(offset, 0, 5 + len(dev_teams) + 1)
    merge_cells(sheet,
                RelPos(rel_offset, 1, 0),
                RelPos(rel_offset, 2, 0),
                'Integration',
                formats.centered_vertical_text_header_format,
                width=5)
    merge_cells(sheet,
                RelPos(rel_offset, 1, 1),
                RelPos(rel_offset, 2, 1),
                'Test automation',
                formats.centered_vertical_text_header_format,
                width=5)
    merge_cells(sheet,
                RelPos(rel_offset, 1, 2),
                RelPos(rel_offset, 2, 2),
                'Stabilization',
                formats.centered_vertical_text_header_format,
                width=5)
    merge_cells(sheet,
                RelPos(rel_offset, 1, 3),
                RelPos(rel_offset, 2, 3),
                'Documentation',
                formats.centered_vertical_text_header_format,
                width=5)
    merge_cells(sheet, RelPos(rel_offset, 1, 4),
                RelPos(rel_offset, 1, 4 + len(dev_teams)), 'Perf engineering',
                formats.centered_header_border_format)
    rel_offset = RelPos(rel_offset, 0, 4 + len(dev_teams) + 1)
    merge_cells(sheet, RelPos(rel_offset, 1, 0),
                RelPos(rel_offset, 1, len(dev_teams)), 'Feature dev subtotal',
                formats.centered_header_border_format)
    rel_offset = RelPos(rel_offset, 0, len(dev_teams) + 1)

    merge_cells(sheet, RelPos(rel_offset, 1, 0),
                RelPos(rel_offset, 1, len(qa_teams)), 'QA effort',
                formats.centered_header_border_format)
    rel_offset = RelPos(rel_offset, 1, len(qa_teams))

    merge_cells(sheet, RelPos(rel_offset, 0, 1), RelPos(rel_offset, 1, 1),
                'Feature total', formats.centered_header_format)

    write_row(
        sheet,
        RelPos(offset, 2, 2),
        cell_generator=[[
            'Reqs', formats.centered_vertical_text_header_left_border_format
        ], [
            'Design', formats.centered_vertical_text_header_right_border_format
        ]],
        col_width=5)

    rel_offset = RelPos(offset, 2, 5)
    columns = write_row(
        sheet,
        rel_offset,
        cell_generator=[[
            dev_teams[i].name,
            formats.centered_vertical_text_header_format if i != 0 else
            formats.centered_vertical_text_header_left_border_format
        ] for i in range(len(dev_teams))] +
        [['Total', formats.centered_vertical_text_header_right_border_format]],
        cell_format=formats.centered_vertical_text_header_format,
        col_width=5)

    rel_offset = RelPos(rel_offset, 0, columns + 4)
    columns = write_row(
        sheet,
        rel_offset,
        cell_generator=[[
            dev_teams[i].name,
            formats.centered_vertical_text_header_format if i != 0 else
            formats.centered_vertical_text_header_left_border_format
        ] for i in range(len(dev_teams))] +
        [['Total', formats.centered_vertical_text_header_right_border_format]],
        cell_format=formats.centered_vertical_text_header_format,
        col_width=5)

    rel_offset = RelPos(rel_offset, 0, columns)
    columns = write_row(
        sheet,
        rel_offset,
        cell_generator=[[
            dev_teams[i].name,
            formats.centered_vertical_text_header_format if i != 0 else
            formats.centered_vertical_text_header_left_border_format
        ] for i in range(len(dev_teams))] +
        [['Total', formats.centered_vertical_text_header_right_border_format]],
        cell_format=formats.centered_vertical_text_header_format,
        col_width=5)

    rel_offset = RelPos(rel_offset, 0, columns)
    write_row(
        sheet,
        rel_offset,
        cell_generator=[[
            qa_teams[i].name, formats.centered_vertical_text_header_format if i
            != 0 else formats.centered_vertical_text_header_left_border_format
        ] for i in range(len(qa_teams))] +
        [['Total', formats.centered_vertical_text_header_right_border_format]],
        cell_format=formats.centered_vertical_text_header_format,
        col_width=5)

    return Region(RelPos(offset), 3, column_count)
Example #10
0
def _create_team_calendar_table(
    sheet,
    capacity_table: Region,
    start_date: date,
    end_date: date,
    production_calendar: dict,
    projects: List[Project],
    total_cells: List[CellReference]
) -> Dict[str, Region]:

    offset = RelPos(capacity_table.pos_below(), 1)

    sheet.write(offset.row, offset.column, '', formats.green_header_format)
    column_count = write_row(
        sheet,
        RelPos(offset, 0, 1),
        cell_generator=(x.strftime(MONTH_FORMAT) for x in get_months_range(start_date, end_date)),
        cell_format=formats.green_header_format
    )

    sheet.write(offset.row + 1, offset.column, 'People')
    write_row(
        sheet,
        RelPos(offset, 1, 1),
        cell_func=lambda col, _: f'={Pos(capacity_table.pos_below().row - 1, col).to_cell()}',
        col_count=column_count,
        cell_format=formats.numeric_format
    )

    sheet.write(offset.row + 2, offset.column, 'Working days')
    workdays_count = get_month_workdays_count(start_date, end_date, production_calendar)
    write_row(
        sheet,
        RelPos(offset, 2, 1),
        cell_generator=get_months_range(start_date, end_date),
        cell_func=lambda _, d: workdays_count[d],
        col_count=column_count
    )

    sheet.write(offset.row + 3, offset.column, 'Working weeks')
    write_row(
        sheet,
        RelPos(offset, 3, 1),
        cell_func=lambda col, _: f'={Pos(offset.row + 2, col).to_cell()} / 5',
        col_count=column_count
    )

    sheet.write(offset.row + 4, offset.column, 'Man * weeks')
    write_row(
        sheet,
        RelPos(offset, 4, 1),
        cell_func=lambda c, _: f'={Pos(offset.row + 1, c).to_cell()} * {Pos(offset.row + 3, c).to_cell()}',
        col_count=column_count,
        cell_format=formats.numeric_format
    )

    # TODO consider either time of the year or real vacations of people (e.g. create vacation field for worker)
    # TODO or use both at once - when real dates of vacations are not known
    sheet.write(offset.row + 5, offset.column, 'Vacations')
    calendar_table_totals_row = capacity_table.pos_below().row - 1
    write_row(
        sheet,
        RelPos(offset, 5, 1),
        cell_func=lambda c, _: f'={Pos(calendar_table_totals_row, c).to_cell()} * 5 / 12',
        col_count=column_count,
        cell_format=formats.numeric_format
    )

    sheet.write(offset.row + 6, offset.column, 'Support tasks')
    write_row(
        sheet,
        RelPos(offset, 6, 1),
        cell_func=lambda c, _: 1.5,
        col_count=column_count,
        cell_format=formats.numeric_format
    )

    sheet.write(offset.row + 7, offset.column, 'Remaining', formats.bold_total_format)
    write_row(
        sheet,
        RelPos(offset, 7, 1),
        cell_func=lambda c, _:
            f'={Pos(offset.row + 4, c).to_cell()}'
            f'-{Pos(offset.row + 5, c).to_cell()}'
            f'-{Pos(offset.row + 6, c).to_cell()}',
        col_count=column_count,
        cell_format=formats.bold_total_format
    )
    sheet.set_column(0, 0, width=15)

    # allocations region
    offset = RelPos(offset, 8)
    time_allocation_cells_by_item: Dict[str, Region] = {}

    row_count = 0
    for cell_ref in total_cells:
        allocation_pos = RelPos(offset, row_count)
        sheet.write(allocation_pos.row, allocation_pos.column, cell_ref.title)
        time_allocation_cells_by_item[cell_ref.title] = Region(allocation_pos, 1, column_count)
        row_count += 1

    # difference between total available and allocated resources
    offset = RelPos(offset, row_count)
    sheet.write(offset.row, 0, 'Difference', formats.bold_total_format)
    for i in range(1, column_count + 1):
        sheet.write(
            offset.row,
            offset.column + i,
            f'={RelPos(offset, - len(projects) - 1, i).to_cell()}'
            f'-SUM({RelPos(offset, - len(projects), i).to_cell()}:{RelPos(offset, - 1, i).to_cell()})',
            formats.bold_total_format
        )

    # summary by project rows
    offset = RelPos(offset, len(projects))
    write_row(
        sheet, offset, cell_generator=['Item', 'Needed', 'Allocated', 'Diff'], cell_format=formats.green_header_format
    )
    offset = RelPos(offset, 1)
    row_count = 0
    for cell_ref in total_cells:
        row_offset = RelPos(offset, row_count)
        allocation_pos = time_allocation_cells_by_item[cell_ref.title].offset
        write_row(
            sheet,
            row_offset,
            cell_generator=[
                cell_ref.title,
                f'={cell_ref.pos.to_cell()}',
                f'=SUM({allocation_pos.to_cell()}:{RelPos(allocation_pos, column=column_count).to_cell()})',
                f'={RelPos(row_offset, column=2).to_cell()}-{RelPos(row_offset, column=1).to_cell()}'
            ],
            cell_format=formats.numeric_format
        )
        row_count += 1

    return time_allocation_cells_by_item