Config: Report author name

This commit is contained in:
Кокос Артем Николаевич
2026-01-21 14:00:13 +07:00
committed by Артём Кокос
parent 4a5dee7a14
commit 5a5ee00726
4 changed files with 53 additions and 4 deletions

View File

@@ -2,9 +2,11 @@ import sys
import argparse import argparse
from typing import List, Optional from typing import List, Optional
from redminelib.resources import Issue from redminelib.resources import Issue
from .config import Config from .config import Config
from .client import fetch_issues_with_spent_time from .client import fetch_issues_with_spent_time
from .formatter import format_compact, format_table from .formatter import format_compact, format_table
from .formatter_odt import format_odt
def parse_date_range(date_arg: str) -> tuple[str, str]: def parse_date_range(date_arg: str) -> tuple[str, str]:
@@ -36,6 +38,11 @@ def main(argv: Optional[List[str]] = None) -> int:
"--output", "--output",
help="Path to output .odt file (e.g., report.odt). If omitted, prints to stdout." help="Path to output .odt file (e.g., report.odt). If omitted, prints to stdout."
) )
parser.add_argument(
"--author",
default="",
help="Override author name from .env (REDMINE_AUTHOR)"
)
args = parser.parse_args(argv) args = parser.parse_args(argv)
try: try:
@@ -67,8 +74,8 @@ def main(argv: Optional[List[str]] = None) -> int:
print("❌ Output file must end with .odt", file=sys.stderr) print("❌ Output file must end with .odt", file=sys.stderr)
return 1 return 1
try: try:
from .formatter_odt import format_odt author = Config.get_author(args.author)
doc = format_odt(issue_hours) doc = format_odt(issue_hours, author=author, from_date=from_date, to_date=to_date)
doc.save(args.output) doc.save(args.output)
print(f"✅ Report saved to {args.output}") print(f"✅ Report saved to {args.output}")
except ImportError: except ImportError:

View File

@@ -9,9 +9,19 @@ class Config:
REDMINE_URL = os.getenv("REDMINE_URL", "").rstrip("/") REDMINE_URL = os.getenv("REDMINE_URL", "").rstrip("/")
REDMINE_USER = os.getenv("REDMINE_USER") REDMINE_USER = os.getenv("REDMINE_USER")
REDMINE_PASSWORD = os.getenv("REDMINE_PASSWORD") REDMINE_PASSWORD = os.getenv("REDMINE_PASSWORD")
REDMINE_AUTHOR = os.getenv("REDMINE_AUTHOR")
DEFAULT_FROM_DATE = os.getenv("DEFAULT_FROM_DATE") DEFAULT_FROM_DATE = os.getenv("DEFAULT_FROM_DATE")
DEFAULT_TO_DATE = os.getenv("DEFAULT_TO_DATE") DEFAULT_TO_DATE = os.getenv("DEFAULT_TO_DATE")
@classmethod
def get_author(cls, cli_author: str = "") -> str:
"""Возвращает автора: из CLI если задан, иначе из .env, иначе — заглушку."""
if cli_author:
return cli_author
if cls.REDMINE_AUTHOR:
return cls.REDMINE_AUTHOR
return ""
@classmethod @classmethod
def get_default_date_range(cls) -> str: def get_default_date_range(cls) -> str:
if cls.DEFAULT_FROM_DATE and cls.DEFAULT_TO_DATE: if cls.DEFAULT_FROM_DATE and cls.DEFAULT_TO_DATE:

View File

@@ -6,9 +6,15 @@ from odf.text import P
from odf.table import Table, TableColumn, TableRow, TableCell from odf.table import Table, TableColumn, TableRow, TableCell
from .formatter import get_version, hours_to_human, STATUS_TRANSLATION from .formatter import get_version, hours_to_human, STATUS_TRANSLATION
from .utils import get_month_name_from_range
def format_odt(issue_hours: List[Tuple[Issue, float]]) -> "OpenDocument": def format_odt(
issue_hours: List[Tuple[Issue, float]],
author: str = "",
from_date: str = "",
to_date: str = ""
) -> "OpenDocument":
template_path = "template.odt" template_path = "template.odt"
if not os.path.exists(template_path): if not os.path.exists(template_path):
raise FileNotFoundError("Шаблон template.odt не найден...") raise FileNotFoundError("Шаблон template.odt не найден...")
@@ -17,7 +23,8 @@ def format_odt(issue_hours: List[Tuple[Issue, float]]) -> "OpenDocument":
para_style_name = "Standard" para_style_name = "Standard"
# Заголовок # Заголовок
header_text = "Кокос Артём Николаевич. Отчет за месяц Июль." month_name = get_month_name_from_range(from_date, to_date)
header_text = f"{author}. Отчет за месяц {month_name}."
header_paragraph = P(stylename=para_style_name, text=header_text) header_paragraph = P(stylename=para_style_name, text=header_text)
doc.text.addElement(header_paragraph) doc.text.addElement(header_paragraph)

View File

@@ -1,2 +1,27 @@
from datetime import datetime
def get_month_name_from_range(from_date: str, to_date: str) -> str:
"""Определяет название месяца по диапазону дат.
Если from == to — возвращает месяц этой даты.
Если диапазон охватывает несколько месяцев — возвращает 'период'.
"""
try:
start = datetime.strptime(from_date, "%Y-%m-%d")
end = datetime.strptime(to_date, "%Y-%m-%d")
except ValueError:
return "период"
if start.year == end.year and start.month == end.month:
months = [
"", "Январь", "Февраль", "Март", "Апрель", "Май", "Июнь",
"Июль", "Август", "Сентябрь", "Октябрь", "Ноябрь", "Декабрь"
]
return months[start.month]
else:
return "период"
def get_version(issue) -> str: def get_version(issue) -> str:
return str(getattr(issue, 'fixed_version', '<N/A>')) return str(getattr(issue, 'fixed_version', '<N/A>'))