Andrey Epifancev b2a89394c9 synthgen: словарь компаний, состав группы, выгрузка ЕЦП (#38)
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-11-12 23:39:15 +04:00

106 lines
3.9 KiB
Python
Raw Permalink 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.

from dataclasses import replace
from decimal import Decimal
import pytest
from synthgen import dictionary, inn
from synthgen.config import Config
from synthgen.group import build_group, member_inn, variant_spelling
from synthgen.ecp import write_ecp
from synthgen.rng import stable_hash
@pytest.fixture(scope="module")
def orgs():
return dictionary.load()
def test_group_size_and_head(orgs):
g = build_group(Config(group_size=5), orgs)
assert len(g.members) == 5
assert [m.code for m in g.members] == ["C01", "C02", "C03", "C04", "C05"]
assert g.members[0].is_head and g.members[0].org.form == "АО" and g.members[0].head_share is None
for m in g.members:
assert m.org.form in ("ООО", "АО") and m.org.kind != "банк"
assert not m.is_head or m is g.members[0]
assert g.name == "ГК SYN" and g.gk_id == "SYN-000001"
for m in g.members:
assert m.name == f'{m.org.form} "SYN {m.org.root}"'
assert m.name_1c == f"SYN {m.org.root} {m.org.form}"
assert len(m.kpp) == 9 and inn.is_valid(m.inn)
def test_member_inn_range():
value = member_inn("SYN", 3)
assert inn.is_valid(value)
assert int(value[2:-1]) == 1000000 + 100 * stable_hash("SYN", 90000) + 3
def test_prefixes_do_not_collide(orgs):
a = {m.inn for m in build_group(Config(prefix="SYN"), orgs).members}
b = {m.inn for m in build_group(Config(prefix="DEMO2"), orgs).members}
assert not a & b
assert not (a | b) & {o.inn for o in orgs}
def test_externals_exclude_group_and_banks(orgs):
g = build_group(Config(group_size=8), orgs)
chosen = {m.org.inn for m in g.members}
assert all(o.kind != "банк" for o in g.externals)
assert not chosen & {o.inn for o in g.externals}
assert len(g.externals) == sum(o.kind != "банк" for o in orgs) - 8
assert len(g.banks) == 30 and all(o.kind == "банк" for o in g.banks)
def test_no_inn_selection(orgs):
g = build_group(Config(group_size=5, no_inn_companies=2), orgs)
assert len(g.no_inn) == 2 and "C01" not in g.no_inn
g = build_group(Config(group_size=5, no_inn_companies=4), orgs)
assert len(g.no_inn) == 4 and "C01" not in g.no_inn
g = build_group(Config(group_size=5, no_inn_companies=5), orgs)
assert g.no_inn == frozenset(m.code for m in g.members)
assert build_group(Config(no_inn_companies=0), orgs).no_inn == frozenset()
@pytest.mark.parametrize("size,n", [(2, 2), (5, 2), (5, 5), (10, 3)])
def test_variant_name(orgs, size, n):
g = build_group(Config(group_size=size, no_inn_companies=n), orgs)
by_code = {m.code: m for m in g.members}
assert set(g.variant_name) == set(g.no_inn)
for code, other in g.variant_name.items():
assert other != code and other in by_code
m = by_code[other]
variant = variant_spelling(m)
assert variant not in (m.name_1c, m.name)
assert variant != by_code[code].name_1c
def test_shares(orgs):
for size in (2, 5, 12):
g = build_group(Config(group_size=size), orgs)
children = g.members[1:]
for m in children:
assert Decimal("0.51") <= m.head_share <= Decimal("1.00")
with_min = [m for m in children if m.minority is not None]
assert len(with_min) <= 2
if size > 2:
assert 1 <= len(with_min)
for m in with_min:
assert m.head_share < 1
for m in children:
if m.minority is None:
assert m.head_share == Decimal("1.00")
def test_prefix_cyrillic_and_digits(orgs, tmp_path):
for prefix in ("ДЕМО", "2GK"):
g = build_group(Config(prefix=prefix), orgs)
assert g.gk_id == f"{prefix}-000001"
write_ecp(g, tmp_path / f"ecp-{prefix}.xlsx")
def test_group_deterministic(orgs):
cfg = Config(group_size=7, no_inn_companies=2, seed=5)
assert build_group(cfg, orgs) == build_group(cfg, orgs)
assert build_group(cfg, orgs) != build_group(replace(cfg, seed=6), orgs)