Andrey Epifancev 004c21041c synthgen: сборка набора, README, детерминированность (#38)
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-11-13 00:37:42 +04:00

72 lines
3.0 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

"""Сборка набора (спека §7): группа → периоды → книги → файлы ЕЦП, ОСВ, ББ и ОФР, config.yaml и README прогона."""
import shutil
from dataclasses import dataclass, field, replace
from pathlib import Path
from synthgen import dictionary, ecp, forms, forms_xlsx, osv, report
from synthgen.config import Config, dump_config
from synthgen.counterparties import OSV_ACCOUNTS, CounterpartyPlan
from synthgen.counterparties import plan as make_plan
from synthgen.group import build_group
from synthgen.intragroup import VgoPair, build
from synthgen.periods import build_periods
@dataclass
class Manifest:
files: list[Path] = field(default_factory=list)
pairs: list[VgoPair] = field(default_factory=list)
capped: bool = False
def default_out(cfg: Config) -> Path:
return cfg.out if cfg.out is not None else Path("out") / cfg.prefix
def _prepare(out: Path, force: bool) -> None:
if out.exists() and any(out.iterdir()):
if not force:
raise FileExistsError(f"каталог результата не пуст: {out} (--force перезапишет)")
for item in out.iterdir():
shutil.rmtree(item) if item.is_dir() and not item.is_symlink() else item.unlink()
out.mkdir(parents=True, exist_ok=True)
def generate(cfg: Config, out: Path, *, force: bool = False) -> Manifest:
"""Строит набор в каталоге `out`; непустой `out` без `force` — FileExistsError."""
_prepare(out, force)
group = build_group(cfg, dictionary.load())
periods = build_periods(cfg.start, cfg.periods)
plan: CounterpartyPlan = make_plan(cfg, group)
books, pairs = build(cfg, group, periods, plan)
manifest = Manifest(pairs=pairs, capped=plan.capped)
def keep(path: Path) -> Path:
manifest.files.append(path)
return path
ecp.write_ecp(group, keep(out / "directories" / f"ecp-{cfg.prefix}.xlsx"))
for member in group.members:
ledger = books[member.code]
with_inn = member.code not in group.no_inn
for period in periods:
for account in OSV_ACCOUNTS:
data = osv.rows(ledger, account, period, member, group)
path = out / "osv" / member.code / period.key / osv.file_name(account, period)
osv.write(path, member, account, period, data, with_inn=with_inn)
keep(path)
for form in (
forms.balance(ledger, member, period, periods, cfg.seed),
forms.income(ledger, member, period, periods, cfg.seed),
):
path = out / "statements" / member.code / period.key / forms_xlsx.file_name(form)
forms_xlsx.write(form, path)
keep(path)
(out / "config.yaml").write_text(dump_config(replace(cfg, out=None)), encoding="utf-8")
keep(out / "config.yaml")
readme = out / "README.md"
manifest.files.append(readme)
readme.write_text(report.render(cfg, group, pairs, plan, manifest), encoding="utf-8")
return manifest