from typing import List, Tuple from redminelib.resources import Issue from .utils import get_version STATUS_TRANSLATION = { 'Closed': 'Закрыто', 'Re-opened': 'В работе', 'New': 'В работе', 'Resolved': 'Решена', 'Pending': 'Ожидание', 'Feedback': 'В работе', 'In Progress': 'В работе', 'Rejected': 'Закрыто', 'Confirming': 'Ожидание', } def hours_to_human(hours: float) -> str: if hours <= 0: return "0ч" total_minutes = round(hours * 60) h = total_minutes // 60 m = total_minutes % 60 parts = [] if h: parts.append(f"{h}ч") if m: parts.append(f"{m}м") return " ".join(parts) if parts else "0ч" def format_compact(issue_hours: List[Tuple[Issue, float]]) -> str: lines = [] prev_project = None prev_version = None for issue, hours in issue_hours: project = str(issue.project) version = get_version(issue) status = str(issue.status) display_project = project if project != prev_project else "" display_version = version if (project != prev_project or version != prev_version) else "" lines.append(f"{display_project} | {display_version} | {issue.id}. {issue.subject} | {status} | {hours_to_human(hours)}") prev_project = project prev_version = version return "\n".join(lines) def format_table(issue_hours: List[Tuple[Issue, float]]) -> str: from tabulate import tabulate rows = [['Проект', 'Версия', 'Задача', 'Статус', 'Затрачено']] prev_project = None prev_version = None for issue, hours in issue_hours: project = str(issue.project) version = get_version(issue) status_en = str(issue.status) status_ru = STATUS_TRANSLATION.get(status_en, status_en) display_project = project if project != prev_project else "" display_version = version if (project != prev_project or version != prev_version) else "" rows.append([ display_project, display_version, f"{issue.id}. {issue.subject}", status_ru, hours_to_human(hours) ]) prev_project = project prev_version = version return tabulate(rows, headers="firstrow", tablefmt="fancy_grid")