47 lines
1.7 KiB
Python
47 lines
1.7 KiB
Python
"""Отчётные периоды (спека §5.1): кварталы подряд, каждый — нарастающим итогом с начала года, как выгружает 1С."""
|
||
|
||
from dataclasses import dataclass
|
||
from datetime import date
|
||
|
||
_LABELS = {1: "1 квартал {y} г.", 2: "1 полугодие {y} г.", 3: "9 месяцев {y} г.", 4: "{y} г."}
|
||
_END = {1: (3, 31), 2: (6, 30), 3: (9, 30), 4: (12, 31)}
|
||
|
||
|
||
@dataclass(frozen=True)
|
||
class Period:
|
||
key: str # 2025-Q1, 2025-Q2, 2025-Q3, 2025-FY
|
||
year: int
|
||
quarter: int
|
||
start: date # всегда 1 января (нарастающий итог)
|
||
end: date
|
||
label_1c: str
|
||
|
||
|
||
def _make(year: int, quarter: int) -> Period:
|
||
month, day = _END[quarter]
|
||
key = f"{year}-FY" if quarter == 4 else f"{year}-Q{quarter}"
|
||
return Period(key, year, quarter, date(year, 1, 1), date(year, month, day), _LABELS[quarter].format(y=year))
|
||
|
||
|
||
def build_periods(start: str, n: int) -> list[Period]:
|
||
"""`n` периодов подряд начиная с `start` (`ГГГГ-Qn`); четвёртый квартал — годовой период `ГГГГ-FY`."""
|
||
year_s, q_s = start.split("-Q")
|
||
year, quarter = int(year_s), int(q_s)
|
||
out: list[Period] = []
|
||
for _ in range(n):
|
||
out.append(_make(year, quarter))
|
||
quarter += 1
|
||
if quarter == 5:
|
||
year, quarter = year + 1, 1
|
||
return out
|
||
|
||
|
||
def book_start(ps: list[Period]) -> date:
|
||
"""Дата входящих остатков: 31 декабря года перед первым периодом."""
|
||
return date(ps[0].year - 1, 12, 31)
|
||
|
||
|
||
def book_end(ps: list[Period]) -> date:
|
||
"""Конец книги — конец последнего периода."""
|
||
return ps[-1].end
|