- synthgen/config.py: Config, load_config (YAML + --set), dump_config, проверки диапазонов §3 - synthgen/rng.py: rng_for (SHA-256 → Random), stable_hash - synthgen/__main__.py: разбор --config/--set/--out/--force, ошибка конфигурации → код 2 - synthgen/examples/default.yaml: все ключи §3 со значениями по умолчанию - копии из synthetic-group/gen (#35): inn, xlsx, ledger, chart (+80.09, 91.09 из seed arm-core) - тесты: config, inn, ledger; conftest с маркерами parser/slow - .gitignore: out/ - спека: решения 15–16 Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>
79 lines
3.0 KiB
Python
79 lines
3.0 KiB
Python
import csv
|
|
import os
|
|
from datetime import date
|
|
from decimal import Decimal
|
|
from pathlib import Path
|
|
|
|
import pytest
|
|
|
|
from synthgen import chart
|
|
from synthgen.ledger import An, Ledger, opening
|
|
|
|
D = Decimal
|
|
|
|
|
|
def test_double_entry():
|
|
lg = Ledger("AGRO")
|
|
lg.post(date(2025, 1, 10), "62.01", An("AGRO"), "90.01", None, D("1200.00"), "продажа")
|
|
lg.post(date(2025, 2, 10), "51", None, "62.01", An("AGRO"), D("200.00"), "оплата")
|
|
opening(lg, date(2025, 1, 1), "51", None, D("500.00"))
|
|
opening(lg, date(2025, 1, 1), "60.01", An("AGRO"), D("-70.00"))
|
|
for d in (date(2025, 1, 1), date(2025, 1, 31), date(2025, 12, 31)):
|
|
assert sum(lg.balance(d).values()) == 0
|
|
|
|
|
|
def test_balance_signs_and_prefix():
|
|
lg = Ledger("X")
|
|
lg.post(date(2025, 1, 10), "62.01", An("AGRO"), "90.01", None, D("1200.00"), "")
|
|
lg.post(date(2025, 2, 10), "51", None, "62.01", An("AGRO"), D("200.00"), "")
|
|
assert lg.balance(date(2025, 3, 31), "62") == {("62.01", An("AGRO")): D("1000.00")}
|
|
assert lg.balance(date(2025, 1, 31), "62") == {("62.01", An("AGRO")): D("1200.00")}
|
|
|
|
|
|
def test_turnover_window():
|
|
lg = Ledger("X")
|
|
lg.post(date(2024, 12, 31), "62.01", An("A"), "90.01", None, D("10.00"), "")
|
|
lg.post(date(2025, 1, 1), "62.01", An("A"), "90.01", None, D("20.00"), "")
|
|
lg.post(date(2025, 3, 31), "51", None, "62.01", An("A"), D("5.00"), "")
|
|
lg.post(date(2025, 4, 1), "62.01", An("A"), "90.01", None, D("40.00"), "")
|
|
t = lg.turnover(date(2025, 1, 1), date(2025, 3, 31), "62")
|
|
assert t == {("62.01", An("A")): (D("20.00"), D("5.00"))}
|
|
|
|
|
|
def test_csv_deterministic(tmp_path):
|
|
def build(p: Path):
|
|
lg = Ledger("X")
|
|
lg.post(date(2025, 1, 10), "62.01", An("A", contract="Д-1"), "90.01", None, D("1.50"), "м")
|
|
lg.to_csv(p)
|
|
return p.read_bytes()
|
|
|
|
a = build(tmp_path / "a.csv")
|
|
assert a == build(tmp_path / "b.csv")
|
|
rows = list(csv.reader(a.decode("utf-8").splitlines(), delimiter=";"))
|
|
assert rows[0] == "day;dt;dt_cp;dt_contract;dt_item;ct;ct_cp;ct_contract;ct_item;amount;memo".split(";")
|
|
assert rows[1][:3] == ["2025-01-10", "62.01", "A"]
|
|
|
|
|
|
def test_rejects_bad_amount():
|
|
lg = Ledger("X")
|
|
with pytest.raises(ValueError):
|
|
lg.post(date(2025, 1, 1), "51", None, "62.01", None, D("0"), "")
|
|
|
|
|
|
def test_chart_helpers():
|
|
assert chart.parent("76.07.1") == "76.07"
|
|
assert chart.parent("76.07") == "76"
|
|
assert chart.parent("58.01") == "58"
|
|
assert chart.is_off_balance("001") and chart.is_off_balance("011")
|
|
assert not chart.is_off_balance("01")
|
|
|
|
|
|
def test_chart_codes_in_core_seed():
|
|
ws = Path(os.environ.get("ARM_KA_WORKSPACE", "/Users/andrey.epifancev/projects/awp-ca"))
|
|
seed = ws / "arm-core/api/seed/core/chart_of_accounts.csv"
|
|
if not seed.exists():
|
|
pytest.skip("нет seed плана счетов")
|
|
codes = {r["code"] for r in csv.DictReader(seed.open(encoding="utf-8"))}
|
|
missing = [c for c in chart.ACCOUNTS if c != "000" and c not in codes]
|
|
assert not missing
|