Одноразовый скрипт api/scripts/convert_chart_1c.py: xlsx выгрузки 1С -> chart_of_accounts.csv (иерархия по структуре кода, kind из «Вид», is_off_balance из «Заб.»). ASSUMPTION(OQ-113): выгрузка считается полным планом счетов. Refs #23 Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com> Claude-Session: cedd7915-2efe-41e5-988c-a9117033598b
74 lines
3.2 KiB
Python
74 lines
3.2 KiB
Python
"""Конвертер плана счетов 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
|