from typing import List, Optional, Dict, Tuple from redminelib import Redmine from redminelib.resources import Issue from .config import Config from .utils import get_version def fetch_issues_with_spent_time( from_date: str, to_date: str ) -> Optional[List[Tuple[Issue, float]]]: """ Fetch unique issues linked to time entries of the current user in given date range, along with total spent hours per issue. Returns list of (issue, total_hours) tuples. """ redmine = Redmine( Config.REDMINE_URL, username=Config.REDMINE_USER, password=Config.REDMINE_PASSWORD, requests={"verify": "/etc/ssl/certs/ca-certificates.crt"}, ) current_user = redmine.user.get("current") time_entries = redmine.time_entry.filter( user_id=current_user.id, from_date=from_date, to_date=to_date ) # Агрегируем часы по issue.id spent_time: Dict[int, float] = {} issue_ids = set() for entry in time_entries: if hasattr(entry, "issue") and entry.issue and hasattr(entry, "hours"): iid = entry.issue.id issue_ids.add(iid) spent_time[iid] = spent_time.get(iid, 0.0) + float(entry.hours) if not issue_ids: return None # Загружаем полные объекты задач issue_list_str = ",".join(str(i) for i in issue_ids) issues = redmine.issue.filter(issue_id=issue_list_str, status_id="*", sort="project:asc") # Сопоставляем задачи с суммарным временем result = [] for issue in issues: total_hours = spent_time.get(issue.id, 0.0) result.append((issue, total_hours)) # Сортируем по (проект, версия) result.sort(key=lambda x: (str(x[0].project), get_version(x[0]))) return result