docs: rewrite README, add user guide, sync CONFIG.md with code
Some checks failed
checks / checks (3.10) (push) Has been cancelled
checks / checks (3.11) (push) Has been cancelled
checks / checks (3.12) (push) Has been cancelled
checks / checks (3.13) (push) Has been cancelled

- README.md: 324 -> 106 lines, clickable TOC, quick start, formats
  table, full check suite + CI; flags/env/YAML reference moved to docs
- docs/USER_GUIDE.md: new user guide (install, periods, users, export,
  email, monthly --commit cycle, 21-flag reference, troubleshooting)
- docs/CONFIG.md: clickable TOC + accuracy fixes verified against code
  (dedup logic was described backwards, missing report section in
  --init-config, conditional STARTTLS, full --config-path role,
  datetime --date ranges, --config override nuance, comment loss on
  --commit, default_to without default_from is ignored)
- client.py: dedup docstring/comment now match actual behavior
This commit is contained in:
Кокос Артем Николаевич
2026-07-17 17:48:52 +07:00
parent 1dc19f8c1a
commit c8df40fe5c
4 changed files with 421 additions and 274 deletions

View File

@@ -275,8 +275,11 @@ def fetch_issues_with_spent_time(
along with total spent hours per issue.
If user_id is None, uses current user.
If by_activity is True, returns per-activity breakdown as third tuple element.
If dedup_before is set, filters out time entries whose created_on AND updated_on
are both before dedup_before (AND logic: both must be < cutoff to exclude).
If dedup_before is set, entries with both fields set are kept only when
created_on AND updated_on are both >= dedup_before; an entry is excluded
if at least one of the fields is before the cutoff (dedup_before).
Entries with both fields missing (None) are kept;
if only one field is set, that field alone decides (>= cutoff keeps the entry).
Returns list of (issue, total_hours, activities) tuples.
Raises RedmineAPIError on API/auth/network failures.
"""
@@ -300,8 +303,11 @@ def fetch_issues_with_spent_time(
raise RedmineAPIError(_format_redmine_error(exc), original=exc) from exc
# Дедупликация: отсекаем записи, которые были учтены в предыдущем отчёте.
# Запись исключается, если BOTH created_on AND updated_on < dedup_before.
# Записи без метаданных (created_on/updated_on == None) не фильтруются.
# Если оба поля заданы, запись сохраняется, только если created_on И updated_on
# оба >= dedup_before; если хотя бы одно из полей < dedup_before,
# запись исключается.
# Если оба поля None — запись сохраняется; если задано только одно поле,
# решает оно (>= dedup_before → запись сохраняется).
if dedup_before is not None:
# Нормализуем cutoff к aware UTC (#58): naive cutoff трактуем как UTC,
# чтобы сравнение с нормализованными created_on/updated_on было корректным.