"""Конвертер плана счетов 1С в csv seed (issue #23): иерархия по структуре кода, kind и забалансовость из выгрузки.""" from pathlib import Path import pytest from scripts.convert_chart_1c import ChartRow, convert, read_xlsx, write_csv from scripts.seed import load_seed API_DIR = Path(__file__).resolve().parent.parent SEED_DIR = API_DIR / "seed" CHART_SIZE = 488 XLSX = API_DIR.parent.parent / "fixtures" / "directories" / "chart-of-accounts-1c.xlsx" def _rec(code: str, name: str = "Счёт", kind: str = "АП", off: str = "Нет") -> dict[str, object]: return {"Код счета": code, "Наименование счета": name, "Вид": kind, "Заб.": off} def test_convert_builds_hierarchy_kind_and_row_type() -> None: rows = convert( [_rec("01", kind="А"), _rec("01.К", kind="А"), _rec("76", kind="АП"), _rec("76.07"), _rec("76.07.1", kind="П")] ) assert rows == [ ChartRow("01", "", "Счёт", "A", "account", False), ChartRow("01.К", "01", "Счёт", "A", "subaccount", False), ChartRow("76", "", "Счёт", "AP", "account", False), ChartRow("76.07", "76", "Счёт", "AP", "subaccount", False), ChartRow("76.07.1", "76.07", "Счёт", "P", "analytic", False), ] def test_convert_off_balance_from_column_and_name_whitespace_collapsed() -> None: (row,) = convert([_rec("МЦ", name=" Материальные ценности ", kind="А", off="Да")]) assert row.is_off_balance is True assert row.name == "Материальные ценности" def test_convert_orphan_without_any_ancestor_gets_empty_parent() -> None: rows = convert([_rec("Я68.01"), _rec("Я69.06.5")]) assert [(r.code, r.parent_code, r.row_type) for r in rows] == [ ("Я68.01", "", "subaccount"), ("Я69.06.5", "", "analytic"), ] def test_convert_rejects_gap_in_hierarchy() -> None: with pytest.raises(ValueError, match="более дальний предок"): convert([_rec("76"), _rec("76.07.1")]) @pytest.mark.parametrize( ("records", "message"), [ ([_rec("01"), _rec("01")], "повторяются"), ([_rec("01", kind="Х")], "неизвестный вид"), ([_rec("01", off="да?")], "Да или Нет"), ([_rec("01", name=" ")], "пустое наименование"), ([_rec("01.01.1.1")], "глубина"), ], ) def test_convert_rejects_bad_rows(records: list[dict[str, object]], message: str) -> None: with pytest.raises(ValueError, match=message): convert(records) @pytest.mark.skipif(not XLSX.is_file(), reason="fixtures/directories/chart-of-accounts-1c.xlsx недоступен") def test_repository_seed_matches_1c_export(tmp_path: Path) -> None: """Дрейф: seed/core/chart_of_accounts.csv побайтно равен результату конвертера на выгрузке 1С.""" out = tmp_path / "chart.csv" write_csv(convert(read_xlsx(XLSX)), out) assert out.read_text(encoding="utf-8") == (SEED_DIR / "core" / "chart_of_accounts.csv").read_text(encoding="utf-8") assert len(load_seed(SEED_DIR).accounts) == CHART_SIZE