92 lines
2.9 KiB
Python
92 lines
2.9 KiB
Python
from __future__ import annotations
|
||
|
||
from dataclasses import dataclass
|
||
from datetime import datetime
|
||
from pathlib import Path
|
||
from typing import Iterable
|
||
|
||
from openpyxl import Workbook
|
||
from openpyxl.styles import Alignment, Font, PatternFill
|
||
from openpyxl.utils import get_column_letter
|
||
|
||
|
||
@dataclass
|
||
class ProtocolRow:
|
||
file_name: str
|
||
status: str
|
||
message: str
|
||
operations_total: int
|
||
rows_written: int
|
||
launcher: str
|
||
processed_at: datetime
|
||
|
||
|
||
def write_protocol(rows: Iterable[ProtocolRow], destination: Path) -> None:
|
||
row_list = list(rows)
|
||
workbook = Workbook()
|
||
details = workbook.active
|
||
details.title = "Протокол"
|
||
details.freeze_panes = "A2"
|
||
|
||
columns = [
|
||
"Имя файла",
|
||
"Статус",
|
||
"Комментарий",
|
||
"Операций",
|
||
"Строк отчета",
|
||
"Запустил",
|
||
"Время обработки",
|
||
]
|
||
_write_header(details, columns)
|
||
for row_index, row in enumerate(row_list, start=2):
|
||
values = [
|
||
row.file_name,
|
||
row.status,
|
||
row.message,
|
||
row.operations_total,
|
||
row.rows_written,
|
||
row.launcher,
|
||
row.processed_at.strftime("%Y-%m-%d %H:%M:%S"),
|
||
]
|
||
for col_index, value in enumerate(values, start=1):
|
||
details.cell(row=row_index, column=col_index, value=value)
|
||
|
||
_auto_width(details, columns)
|
||
_write_summary(workbook, row_list)
|
||
destination.parent.mkdir(parents=True, exist_ok=True)
|
||
workbook.save(destination)
|
||
|
||
|
||
def _write_summary(workbook: Workbook, rows: list[ProtocolRow]) -> None:
|
||
summary = workbook.create_sheet("Итог")
|
||
total = len(rows)
|
||
success = sum(1 for row in rows if row.status == "success")
|
||
partial = sum(1 for row in rows if row.status == "partial")
|
||
errors = sum(1 for row in rows if row.status == "error")
|
||
metrics = [
|
||
("Всего файлов", total),
|
||
("Успешно", success),
|
||
("Частично", partial),
|
||
("Ошибки", errors),
|
||
]
|
||
for index, (name, value) in enumerate(metrics, start=1):
|
||
summary.cell(row=index, column=1, value=name).font = Font(bold=True)
|
||
summary.cell(row=index, column=2, value=value)
|
||
summary.column_dimensions[get_column_letter(1)].width = 24
|
||
summary.column_dimensions[get_column_letter(2)].width = 14
|
||
|
||
|
||
def _write_header(sheet, columns: list[str]) -> None:
|
||
fill = PatternFill(start_color="D9E1F2", end_color="D9E1F2", fill_type="solid")
|
||
for index, name in enumerate(columns, start=1):
|
||
cell = sheet.cell(row=1, column=index, value=name)
|
||
cell.font = Font(bold=True)
|
||
cell.alignment = Alignment(horizontal="center", vertical="center")
|
||
cell.fill = fill
|
||
|
||
|
||
def _auto_width(sheet, columns: list[str]) -> None:
|
||
for index, name in enumerate(columns, start=1):
|
||
width = max(14, min(70, len(name) + 6))
|
||
sheet.column_dimensions[get_column_letter(index)].width = width
|