Ejemplo n.º 1
0
def download_report(request, type_, datetime_start, datetime_end, **kwargs):
    ticket_report = get_ticket_report(request, type_, datetime_start, datetime_end, **kwargs)[0]
    business_report = get_business_report(request, type_, datetime_start, datetime_end, **kwargs)[0]
    virtual_resource_report = get_virtual_resource_report(request, type_, datetime_start, datetime_end, **kwargs)[0]
    physical_resource_report = get_physical_resource_report(request, type_, datetime_start, datetime_end, **kwargs)[0]

    wb = Workbook()
    ws = wb.active

    left_align = Alignment(horizontal="left", vertical="center")
    center_align = Alignment(horizontal="center", vertical="center")
    # 自动换行
    wrap_text_center_align = Alignment(wrapText=True, horizontal="left", vertical="center")

    thin_style = borders.Side(border_style=borders.BORDER_THIN, color=colors.BLACK)
    medium_style = borders.Side(border_style=borders.BORDER_MEDIUM, color=colors.BLACK)
    thin_border = borders.Border(top=thin_style, bottom=thin_style, left=thin_style, right=thin_style)

    def set_cell_content(column, row, content, alignment=left_align, border=borders.DEFAULT_BORDER):
        place = "%s%s" % (column, row)
        ws[place] = content
        ws[place].font = Font(name=u"宋体", size=12)
        ws[place].alignment = alignment
        ws[place].border = border

    def set_row_content(row, contents, alignment=left_align, border=borders.DEFAULT_BORDER):
        for c_index, content in enumerate(contents, 1):
            set_cell_content(get_column_letter(c_index), row, content, alignment, border)

    ws.merge_cells("A1:D1")
    if type_ == "day":
        title = datetime_start.strftime(u"%Y-%m-%d 运维日报")
    elif type_ == "week":
        title = u"%s到%s 运维周报" % (datetime_start.strftime("%Y-%m-%d"), datetime_end.strftime("%Y-%m-%d"))
    else:
        title = datetime_start.strftime(u"%Y-%m 运维月报")
    set_cell_content("A", 1, title)
    ws["A1"].font = Font(name=u"宋体", size=16)
    ws["A1"].alignment = center_align

    ws.merge_cells("A2:D2")
    type_pretty = {
        "day": u"日",
        "week": u"周",
        "month": u"月",
    }[type_]
    summary = u"总结:\n"
    summary += u"本%s共%s个工单 ," % (type_pretty, ticket_report["ticket_num"])
    if ticket_report["finish_rate_low_tickets"]:
        summary += u"本%s %s 完成能力弱,请注意处理积压工单。\n" % (
            type_pretty, ",".join(ticket_report["finish_rate_low_tickets"])
        )
    else:
        summary += u"无工单完成能力弱。"
    hlc_dict = physical_resource_report["high_load_cabinet"]
    if hlc_dict["cpu"] or hlc_dict["memory"] or hlc_dict["disk"]:
        summary += u"本周"
        if hlc_dict["cpu"]:
            summary += u"%s CPU使用率为高负载," % ",".join(hlc_dict["cpu"])
        if hlc_dict["memory"]:
            summary += u"%s 内存使用率为高负载," % ",".join(hlc_dict["memory"])
        if hlc_dict["disk"]:
            summary += u"%s 硬盘使用率为高负载," % ",".join(hlc_dict["disk"])
        summary += u"请注意资源使用情况。\n"
    if business_report["high_risk_systems"]:
        summary += u"本%s %s 系统安全风险高,请及时防范。" % (type_, ",".join(business_report["high_risk_systems"]))
    set_cell_content("A", 2, summary, alignment=wrap_text_center_align)

    # 工单情况
    ws.merge_cells("A4:D4")
    set_cell_content("A", 4, u"工单情况", alignment=center_align)
    set_cell_content("A", 5, u"工单数量统计")
    set_row_content(6, [u"工单类型", u"工单数量", u"占比"], border=thin_border)
    current_row = 7
    tickets = ticket_report["ticket"]
    ticket_sum = sum(tickets["totals"])
    for index, ticket_name in enumerate(tickets["names"]):
        ticket_num = tickets["totals"][index]
        set_row_content(
            current_row, [ticket_name, ticket_num, result_precess(ticket_num * 100.0 / ticket_sum)], border=thin_border
        )
        current_row += 1
    current_row += 1
    set_cell_content("A", current_row, u"工单处理能力")
    current_row += 1
    set_row_content(current_row, [u"工单类型", u"完成工单数量", u"工单总量", u"完成率"], border=thin_border)
    current_row += 1
    for index, ticket_name in enumerate(tickets["names"]):
        ticket_num = tickets["totals"][index]
        finish_num = tickets["finish_nums"][index]
        finish_rate = tickets["finish_rates"][index]
        set_row_content(current_row, [ticket_name, finish_num, ticket_num, finish_rate], border=thin_border)
        current_row += 1

    # 资源情况
    current_row += 1
    ws.merge_cells("A%s:D%s" % (current_row, current_row))
    set_cell_content("A", current_row, u"资源情况", alignment=center_align)
    current_row += 1
    set_cell_content("A", current_row, u'机柜资源使用率')
    current_row += 1
    set_row_content(current_row, [u'机柜名称', u'CPU使用率', u'内存使用率', u'硬盘使用率'], border=thin_border)
    current_row += 1
    cur_dict = physical_resource_report["cabinet_use_rate"]
    for index, cabinet_name in enumerate(cur_dict["names"]):
        cpu_use_rate = cur_dict["cpu_use_rates"][index]
        memory_use_rate = cur_dict["memory_use_rates"][index]
        disk_use_rate = cur_dict["disk_use_rates"][index]
        set_row_content(current_row, [cabinet_name, cpu_use_rate, memory_use_rate, disk_use_rate], border=thin_border)
        current_row += 1

    current_row += 1
    set_cell_content("A", current_row, u'虚拟资源变化量')
    current_row += 1
    set_row_content(current_row, [u'虚拟资源类型', u'原总量', u'变化量', u'变化率'], border=thin_border)
    current_row += 1
    change_dict = virtual_resource_report["change"]
    for index, name in enumerate(change_dict["names"]):
        raw_num = change_dict["raw_nums"][index]
        num_change = change_dict["num_changes"][index]
        rate_change = change_dict["rate_changes"][index]
        set_row_content(current_row, [name, raw_num, num_change, rate_change], border=thin_border)
        current_row += 1

    current_row += 1
    set_cell_content("A", current_row, u'物理机负载趋势')
    current_row += 1
    set_row_content(current_row, [u'时间', u'CPU使用率', u'硬盘使用率', u'内存使用率'], border=thin_border)
    current_row += 1
    pm_load_trend = physical_resource_report["load_trend"]
    for index, time_ in enumerate(pm_load_trend["times"]):
        if type_ == "day":
            time_str = datetime.datetime.fromtimestamp(time_).strftime("%Y-%m-%d:%H")
        else:
            time_str = datetime.datetime.fromtimestamp(time_).strftime("%Y-%m-%d")
        cpu_use_rate = pm_load_trend["cpu_use_rates"][index]
        memory_use_rate = pm_load_trend["memory_use_rates"][index]
        disk_use_rate = pm_load_trend["disk_use_rates"][index]
        set_row_content(current_row, [time_str, cpu_use_rate, memory_use_rate, disk_use_rate], border=thin_border)
        current_row += 1

    current_row += 1
    set_cell_content("A", current_row, u'虚拟机负载趋势')
    current_row += 1
    set_row_content(current_row, [u'时间', u'CPU使用率', u'硬盘使用率', u'内存使用率'], border=thin_border)
    current_row += 1
    vm_load_trend = virtual_resource_report["load_trend"]
    for index, time_ in enumerate(vm_load_trend["times"]):
        if type_ == "day":
            time_str = datetime.datetime.fromtimestamp(time_).strftime("%Y-%m-%d:%H")
        else:
            time_str = datetime.datetime.fromtimestamp(time_).strftime("%Y-%m-%d")
        cpu_use_rate = vm_load_trend["cpu_use_rates"][index]
        memory_use_rate = vm_load_trend["memory_use_rates"][index]
        disk_use_rate = vm_load_trend["disk_use_rates"][index]
        set_row_content(current_row, [time_str, cpu_use_rate, memory_use_rate, disk_use_rate], border=thin_border)
        current_row += 1

    # 业务监控情况
    current_row += 1
    ws.merge_cells("A%s:D%s" % (current_row, current_row))
    set_cell_content("A", current_row, u"业务监控情况", alignment=center_align)
    current_row += 1
    systems = business_report["systems"]
    for system in systems:
        ws.merge_cells("A%s:D%s" % (current_row, current_row))
        set_cell_content("A", current_row, system["name"], alignment=center_align)
        current_row += 1
        set_cell_content('A', current_row, u'虚拟机使用')
        current_row += 1
        set_row_content(current_row, [u'运行中虚拟机数量', u'虚拟机总量', u'虚拟机使用率'], border=thin_border)
        current_row += 1
        running_vm_num = system['running_vm_num']
        vm_num = system['vm_num']
        set_row_content(
            current_row,
            [running_vm_num, vm_num, result_precess(running_vm_num * 100.0 / vm_num) if vm_num else "-"],
            border=thin_border
        )
        current_row += 2
        set_cell_content('A', current_row, u'安全状况')
        current_row += 1
        set_row_content(current_row, [u'安全风险类型', u'风险数量'], border=thin_border)
        current_row += 1
        risks = [
            ('os_leak', u'系统漏洞'),
            ('site_leak', u'病毒检测'),
            ('weak_order', u'弱口令'),
            ('horse_file', u'木马文件'),
        ]
        for risk, risk_name in risks:
            set_row_content(current_row, [risk_name, system[risk]], border=thin_border)
            current_row += 1
        current_row += 1
        set_cell_content('A', current_row, u'资源使用')
        current_row += 1
        set_row_content(current_row, [u'虚拟机名称', u'cpu使用率', u'内存使用率', u'硬盘使用率'], border=thin_border)
        current_row += 1
        resource_use = system['resource_use_rate']
        for index, name in enumerate(resource_use["names"]):
            cpu_use_rate = resource_use["cpu_use_rates"][index]
            memory_use_rate = resource_use["memory_use_rates"][index]
            disk_use_rate = resource_use["disk_use_rates"][index]
            set_row_content(current_row, [name, cpu_use_rate, memory_use_rate, disk_use_rate], border=thin_border)
            current_row += 1

    # 调整column宽度
    ws.column_dimensions["A"].width = 19.17
    ws.column_dimensions["B"].width = 24
    ws.column_dimensions["C"].width = 17.50
    ws.column_dimensions["D"].width = 21.50

    # 调整row高度
    ws.row_dimensions[1].height = 19
    ws.row_dimensions[2].height = 98
    for index in range(3, current_row):
        ws.row_dimensions[index].height = 15

    # 大边框
    def change_cell_border(cell, top=None, left=None, right=None, bottom=None):
        border = cell.border.copy()
        if top:
            border.top = top
        if left:
            border.left = left
        if right:
            border.right = right
        if bottom:
            border.bottom = bottom
        cell.border = border

    for column in ('A', 'B', 'C', 'D'):
        change_cell_border(ws['%s%s' % (column, 1)], top=medium_style)
        change_cell_border(ws['%s%s' % (column, current_row - 1)], bottom=medium_style)
    for row in range(1, current_row):
        change_cell_border(ws['A%s' % row], left=medium_style)
        change_cell_border(ws['D%s' % row], right=medium_style)
    # return wb
    return save_virtual_workbook(wb)
Ejemplo n.º 2
0
def output_excel(categories, count_eval, avg_iou, detection, unnecessary,
                 pre_label_list, recalls, precisions):
    size = len(categories)

    # エクセル作成
    wb = px.Workbook()

    # シート作成
    ws_1 = wb.active
    ws_1 = wb.create_sheet(title='推論結果')

    # セル結合
    ws_1.merge_cells(start_row=1, start_column=1, end_row=3, end_column=1)
    ws_1.merge_cells(start_row=1,
                     start_column=2,
                     end_row=1,
                     end_column=2 + size)
    ws_1.merge_cells(start_row=2, start_column=2, end_row=3, end_column=2)
    ws_1.merge_cells(start_row=1,
                     start_column=3 + size,
                     end_row=1,
                     end_column=4 + size * 2)
    ws_1.merge_cells(start_row=2,
                     start_column=3,
                     end_row=2,
                     end_column=2 + size)
    ws_1.merge_cells(start_row=2,
                     start_column=3 + size,
                     end_row=2,
                     end_column=2 + size * 2)
    ws_1.merge_cells(start_row=2,
                     start_column=3 + size * 2,
                     end_row=3,
                     end_column=3 + size * 2)
    ws_1.merge_cells(start_row=2,
                     start_column=4 + size * 2,
                     end_row=3,
                     end_column=4 + size * 2)
    ws_1.merge_cells(start_row=1,
                     start_column=5 + size * 2,
                     end_row=3,
                     end_column=5 + size * 2)
    ws_1.merge_cells(start_row=1,
                     start_column=6 + size * 2,
                     end_row=3,
                     end_column=6 + size * 2)
    ws_1.merge_cells(start_row=1,
                     start_column=7 + size * 2,
                     end_row=3,
                     end_column=7 + size * 2)
    ws_1.merge_cells(start_row=1,
                     start_column=8 + size * 2,
                     end_row=3,
                     end_column=8 + size * 2)

    # ヘッダーを記述
    ws_1.cell(row=1, column=1).value = 'ラベル名'
    ws_1.cell(row=1, column=2).value = '正解ボックス'
    ws_1.cell(row=1, column=3 + size).value = '推論ボックス'
    ws_1.cell(row=2, column=2).value = '未検出'
    ws_1.cell(row=2, column=3).value = '検出'
    ws_1.cell(row=2, column=3 + size).value = '検出'
    ws_1.cell(row=2, column=3 + size * 2).value = '過検出'
    ws_1.cell(row=2, column=4 + size * 2).value = '不要'
    ws_1.cell(row=1, column=5 + size * 2).value = '平均IOU'
    ws_1.cell(row=1, column=6 + size * 2).value = '再現率(Recall)'
    ws_1.cell(row=1, column=7 + size * 2).value = '適合率(Precision)'
    ws_1.cell(row=1, column=8 + size * 2).value = 'F値(F-measure)'

    # ラベル名を記述
    for i, label in enumerate(categories):
        ws_1.cell(row=4 + i, column=1).value = label
        ws_1.cell(row=3, column=3 + i).value = label
        ws_1.cell(row=3, column=3 + size + i).value = label

    # 評価データを記述
    for i, box in enumerate(count_eval):
        for j, num in enumerate(box):
            ws_1.cell(row=4 + i, column=2 + j).value = num

    # 平均IOUを記述
    for i, iou in enumerate(avg_iou):
        ws_1.cell(row=4 + i, column=5 + size * 2).value = iou

    #再現率、適合率、F値を記述
    for i in range(len(recalls)):
        ws_1.cell(row=4 + i, column=6 + size * 2).value = recalls[i]
        ws_1.cell(row=4 + i, column=7 + size * 2).value = precisions[i]
        if recalls[i] != 0 and precisions[i] != 0:
            fmeasure = 2 * recalls[i] * precisions[i] / (recalls[i] +
                                                         precisions[i])
        else:
            fmeasure = 0
        ws_1.cell(row=4 + i, column=8 + size * 2).value = fmeasure

    # アルファベットのリストを生成
    alphabet_list = [chr(i) for i in range(97, 105 + size * 2)]

    # セル幅を広めに修正
    # for i, c in enumerate(alphabet_list):
    #    ws_1.column_dimensions[c].width = 14

    # 文字位置を変更
    for i in range(1, 9 + size * 2):
        for j in range(1, size + 4):
            ws_1.cell(row = j, column = i).alignment = \
                    Alignment(horizontal = 'center', vertical = 'center')

    # 枠線を生成
    for i in range(1, 9 + size * 2):
        for j in range(1, size + 4):
            ws_1.cell(row = j, column = i).border = \
                borders.Border(top    = borders.Side(style = borders.BORDER_THIN, color = '000000'),
                               left   = borders.Side(style = borders.BORDER_THIN, color = '000000'),
                               right  = borders.Side(style = borders.BORDER_THIN, color = '000000'),
                               bottom = borders.Side(style = borders.BORDER_THIN, color = '000000'))

    # フォントを変更
    font = Font(name='メイリオ')

    for i in range(1, 9 + size * 2):
        for j in range(1, size + 4):
            ws_1.cell(row=j, column=i).font = font

    # シート作成
    ws_2 = wb.create_sheet(title='IOU詳細')

    # セル結合
    ws_2.merge_cells(start_row=1, start_column=7, end_row=2, end_column=7)
    ws_2.merge_cells(start_row=1, start_column=8, end_row=1, end_column=10)
    ws_2.merge_cells(start_row=1, start_column=11, end_row=1, end_column=13)

    # ヘッダーを記述
    ws_2.cell(row=1, column=1).value = '画像'
    ws_2.cell(row=1, column=2).value = '正解ラベル'
    ws_2.cell(row=1, column=3).value = '推論ラベル'
    ws_2.cell(row=1, column=4).value = 'IOU'
    ws_2.cell(row=1, column=5).value = 'スコア'

    ws_2.cell(row=1, column=7).value = 'ラベル名'
    ws_2.cell(row=1, column=8).value = '検出'
    ws_2.cell(row=1, column=11).value = '過検出'

    ws_2.cell(row=2, column=8).value = '0.6未満'
    ws_2.cell(row=2, column=9).value = '0.6以上0.7未満'
    ws_2.cell(row=2, column=10).value = '0.7以上'
    ws_2.cell(row=2, column=11).value = '0.6未満'
    ws_2.cell(row=2, column=12).value = '0.6以上0.7未満'
    ws_2.cell(row=2, column=13).value = '0.7以上'

    # データを記述
    for i, data in enumerate(detection):
        ws_2.cell(row=2 + i, column=1).value = data[0]
        ws_2.cell(row=2 + i, column=2).value = data[1]
        ws_2.cell(row=2 + i, column=3).value = data[2]
        ws_2.cell(row=2 + i, column=4).value = data[5]
        ws_2.cell(row=2 + i, column=5).value = data[6]

    cnt = 0

    for i, x in enumerate(pre_label_list):
        switch = 0

        for j, y in enumerate(detection):
            if (x[0] == y[0] and x[1] == y[2] and x[6] == y[4]
                    and x[7] == y[6]):
                switch = 1

        if (switch == 0):
            ws_2.cell(row=len(detection) + 2 + cnt, column=1).value = x[0]
            ws_2.cell(row=len(detection) + 2 + cnt, column=3).value = x[1]
            ws_2.cell(row=len(detection) + 2 + cnt, column=5).value = x[7]

            cnt += 1

    iou_split = [[0 for i in range(7)] for j in range(len(categories))]

    for i, label in enumerate(categories):
        iou_split[i][0] = label

        for data in detection:
            if (label == data[1] and data[1] == data[2] and data[5] < 0.6):
                iou_split[i][1] += 1

            elif (label == data[1] and data[1] == data[2] and data[5] >= 0.7):
                iou_split[i][3] += 1

            elif (label == data[1] and data[1] == data[2] and data[5] >= 0.6
                  and data[5] < 0.7):
                iou_split[i][2] += 1

            if (label == data[1] and data[1] != data[2] and data[5] < 0.6):
                iou_split[i][4] += 1

            elif (label == data[1] and data[1] != data[2] and data[5] >= 0.7):
                iou_split[i][6] += 1

            elif (label == data[1] and data[1] != data[2] and data[5] >= 0.6
                  and data[5] < 0.7):
                iou_split[i][5] += 1

    # データを記述
    for i, data in enumerate(iou_split):
        ws_2.cell(row=3 + i, column=7).value = data[0]
        ws_2.cell(row=3 + i, column=8).value = data[1]
        ws_2.cell(row=3 + i, column=9).value = data[2]
        ws_2.cell(row=3 + i, column=10).value = data[3]
        ws_2.cell(row=3 + i, column=11).value = data[4]
        ws_2.cell(row=3 + i, column=12).value = data[5]
        ws_2.cell(row=3 + i, column=13).value = data[6]

    # アルファベットのリストを生成
    alphabet_list = [chr(i) for i in range(97, 110)]

    # セル幅を広めに修正
    for i, c in enumerate(alphabet_list):
        ws_2.column_dimensions[c].width = 14

    # 文字位置を変更
    for i in range(1, 6):
        ws_2.cell(row = 1, column = i).alignment = \
            Alignment(horizontal = 'center', vertical = 'center')

    for i in range(6, 14):
        for j in range(1, size + 3):
            ws_2.cell(row = j, column = i).alignment = \
                Alignment(horizontal = 'center', vertical = 'center')

    # 枠線を生成
    for i in range(7, 14):
        for j in range(1, size + 3):
            ws_2.cell(row = j, column = i).border = \
                borders.Border(top    = borders.Side(style = borders.BORDER_THIN, color = '000000'),
                               left   = borders.Side(style = borders.BORDER_THIN, color = '000000'),
                               right  = borders.Side(style = borders.BORDER_THIN, color = '000000'),
                               bottom = borders.Side(style = borders.BORDER_THIN, color = '000000'))

    # フォントを変更
    for i in range(1, 14):
        for j in range(1, len(detection) + 1):
            ws_2.cell(row=j, column=i).font = font

    # シート削除
    wb.remove(wb['Sheet'])

    # エクセル保存
    save_excel_path = os.path.join(args.pre_xml, 'evaluation.xlsx')
    wb.save(save_excel_path)

    print('Successful Completion ({})'.format(save_excel_path))
Ejemplo n.º 3
0
from openpyxl.styles import PatternFill, Alignment, Font

# colorcodes
BLUECOLORCODE = 'FF61D2FF'
GREENCOLORCODE = 'FF6DE992'
YELLOWCOLORCODE = 'FFFFFF52'
PURPLECOLORCODE = 'FFE057FF'
GRAYCOLORCODE = 'FFC8C8C8'

thin_border = xlborders.Border(left=xlborders.Side(style='thin',
                                                   color=GRAYCOLORCODE),
                               right=xlborders.Side(style='thin',
                                                    color=GRAYCOLORCODE),
                               top=xlborders.Side(style='thin',
                                                  color=GRAYCOLORCODE),
                               bottom=xlborders.Side(style='thin',
                                                     color=GRAYCOLORCODE),
                               vertical=xlborders.Side(style='thin',
                                                       color=GRAYCOLORCODE),
                               horizontal=xlborders.Side(style='thin',
                                                         color=GRAYCOLORCODE))


# %% create excelfile
def createProfitExcel(coinList,
                      path,
                      minDate,
                      maxDate,
                      currency='EUR',
                      taxyearlimit=1,
                      useWalletTaxYearLimit=True,
Ejemplo n.º 4
0
class Command(BaseCommand):
    TEMPLATE = 'templates/ecommerce/template.xlsx'
    NAME = 'pricelist.xlsx'
    SHEET_TITLE = 'Прайс Shopelectro'
    CATEGORY_FILL = openpyxl.styles.PatternFill(
        start_color='F4FEFD',
        end_color='F4FEFD',
        fill_type='solid'
    )
    BUY_FILL = openpyxl.styles.PatternFill(
        start_color='FEFEF0',
        end_color='FEFEF0',
        fill_type='solid'
    )
    THIN_BORDER = borders.Border(
        top=borders.Side(style='thin'),
        right=borders.Side(style='thin'),
        bottom=borders.Side(style='thin'),
        left=borders.Side(style='thin')
    )
    CURRENT_ROW = '9'  # Start of catalog section in file.
    cell = namedtuple('cell', ['row', 'col'])
    BAD_STYLED_CELLS = ['D5', 'E5', 'D6', 'G8']

    def __init__(self, *args, **kwargs):
        super(Command, self).__init__(*args, **kwargs)
        self.file, self.sheet = self.load_file_and_sheet()

    def handle(self, *args, **options):
        """Open template's file and start proceeding it."""
        self.set_collapse_controls()
        self.fill_header()
        self.write_catalog()
        self.hide_formulas()
        self.set_styles()
        base_dir = settings.ASSETS_DIR
        self.file.save(os.path.join(base_dir, self.NAME))

    def set_styles(self):
        for cell in self.BAD_STYLED_CELLS:
            self.sheet[cell].border = self.THIN_BORDER

    def set_collapse_controls(self):
        """
        Place collapse buttons above rows.

        Collapse controls looks like this: http://prntscr.com/clf9xh. # Ignore InvalidLinkBear
        Doc link: https://goo.gl/nR5pLO
        """
        self.sheet.sheet_properties.outlinePr.summaryBelow = False

    def increase_row(self):
        self.CURRENT_ROW = str(int(self.CURRENT_ROW) + 1)
        return self.CURRENT_ROW

    def get_row(self, row_number):
        return self.sheet.row_dimensions[int(row_number)]

    def load_file_and_sheet(self):
        """
        Load template file into openpyxl.

        Return tuple with opened openpyxl file's object and active price sheet.
        """
        file = openpyxl.load_workbook(os.path.join(
            settings.BASE_DIR, self.TEMPLATE))
        return file, file.get_sheet_by_name('Прайслист')

    def fill_header(self):
        """Fill header of a sheet with date and title."""
        date_cell = 'C5'
        self.sheet.title = self.SHEET_TITLE
        self.sheet[date_cell] = datetime.date.strftime(
            datetime.date.today(), '%d.%m.%Y')

    def hide_formulas(self):
        """Hide formulas for calculating totals."""
        self.sheet.column_dimensions.group('H', 'K', hidden=True, outline_level=0)

    def write_catalog(self):
        """Write categories and products to sheet."""
        categories = Category.objects.active().order_by('name').filter(children=None)
        for category in categories.iterator():
            self.write_category_with_products(category)

    def write_category_with_products(self, category):
        """Write category line and beside that - all of products in this category."""
        def hide_row(row):
            row.hidden = True
            row.outlineLevel = 1

        def collapse_row(row):
            row.collapsed = True

        def write_product_rows():
            """Write products lines."""
            sheet = self.sheet
            products = Product.objects.filter(category=category, page__is_active=True)
            for product in products.iterator():
                product_start = 'A' + self.CURRENT_ROW
                sheet[product_start] = product.name
                sheet[product_start].font = Font(color=colors.BLUE)
                sheet[product_start].hyperlink = settings.BASE_URL + product.url
                sheet[product_start].border = self.THIN_BORDER
                prices = [
                    product.price,
                    product.wholesale_small,
                    product.wholesale_medium,
                    product.wholesale_large,
                ]
                for price, total in zip('CDEF', 'HIJK'):
                    sheet[price + self.CURRENT_ROW] = prices.pop(0)
                    sheet[total + self.CURRENT_ROW] = (
                        '={0}{1}*G{1}'.format(price, self.CURRENT_ROW)
                    )

                    sheet[price + self.CURRENT_ROW].border = self.THIN_BORDER

                sheet['G' + self.CURRENT_ROW].fill = self.BUY_FILL
                sheet['G' + self.CURRENT_ROW].border = self.THIN_BORDER

                hide_row(self.get_row(self.CURRENT_ROW))
                self.increase_row()

        def write_category_row():
            """Merge category line into one cell and write to it."""
            sheet = self.sheet
            collapse_row(self.get_row(self.CURRENT_ROW))

            category_start = 'A' + self.CURRENT_ROW
            category_line = '{}:{}'.format(
                category_start, 'G' + self.CURRENT_ROW)
            sheet.merge_cells(category_line)
            sheet[category_start] = category.name
            sheet[category_start].fill = self.CATEGORY_FILL

            self.increase_row()

        write_category_row()
        write_product_rows()