arm-tabular-parser/api/tests/unit/parser/test_osv_flat_form.py
2026-10-19 13:18:23 +04:00

104 lines
4.7 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.

"""Плоская форма ОСВ 1С (#59, change osv-flat-form): стратегия `header_account` и счёт шапки у строк."""
import pytest
from gridbuilder import L, M, sheet_from_rows
from src.contract.result import OsvDocument
from src.parser.deadline import Deadline
from src.parser.osv import OsvParser
from src.parser.rules import Rules, load_rules
TIMEOUT_SECONDS = 60
HEADER_ACCOUNT_CODE = "OSV_HIERARCHY_BY_HEADER_ACCOUNT"
@pytest.fixture(scope="module")
def rules() -> Rules:
return load_rules()
def _table_head() -> list[list[object]]:
return [
["Субконто", M("Сальдо на начало периода", 2), M("Обороты за период", 2), M("Сальдо на конец периода", 2)],
[None, "Дебет", "Кредит", "Дебет", "Кредит", "Дебет", "Кредит"],
]
def _parse(rules: Rules, rows: list[list[object]]) -> tuple[OsvDocument, list[str]]:
result = OsvParser(rules).parse_sheet(sheet_from_rows(rows), Deadline(TIMEOUT_SECONDS))
return result.document, [note.code for note in result.notes]
def test_flat_list_s40(rules: Rules) -> None:
"""Образец s40: счёт «по счету: 76.Н.1», вид «Контрагенты», организация ниже периода, данные без оформления."""
rows: list[list[object]] = [
[],
["Оборотно-сальдовая ведомость по счету: 76.Н.1"],
["Контрагенты"],
["за 2025 г."],
['ООО "Товарное хозяйство"'],
[],
["Единица измерения: рубль (код по ОКЕИ 383)"],
[],
*_table_head(),
["Август - Агро ООО", 1000, None, 500, 300, 1200, None],
["АВИС ООО", None, 200, 100, 400, None, 500],
["Агроаспект ООО", None, None, 50, 50, None, None],
["Итого развернутое", 1000, 200, 650, 750, 1200, 500],
["Итого", 800, None, 650, 750, 700, None],
]
document, codes = _parse(rules, rows)
assert document.status == "done"
assert HEADER_ACCOUNT_CODE in codes
data = [item for item in document.rows if item.group_type != "TOTAL"]
assert [item.row_value for item in data] == ["Август - Агро ООО", "АВИС ООО", "Агроаспект ООО"]
assert all(item.level == 0 and item.parent_row_number is None for item in data)
assert {item.account_code_raw for item in data} == {"76.Н.1"}
assert document.header.organization_name == 'ООО "Товарное хозяйство"'
def test_flat_list_s41(rules: Rules) -> None:
"""Образец s41 (R-10): схема [ACCOUNT, COUNTERPARTY («Организации»)], счёт шапки «60»."""
rows: list[list[object]] = [
[],
["Оборотно-сальдовая ведомость по счету: 60"],
["Организации"],
["за 2 Квартал 2026 г. План счетов ООО Хреновская Нива"],
[],
*_table_head(),
["Автодор-Платные Дороги ООО", 820, None, 5000, 4991, 829, None],
["АГРОПРОФИ ООО", None, 2764, None, None, None, 2764],
["Итого развернутое", 820, 2764, 5000, 4991, 829, 2764],
["Итого", None, 1944, 5000, 4991, None, 1935],
]
document, _ = _parse(rules, rows)
assert document.status == "done"
data = [item for item in document.rows if item.group_type != "TOTAL"]
assert [item.account_code_raw for item in data] == ["60", "60"]
assert [item.group_type for item in data] == ["COUNTERPARTY", "COUNTERPARTY"]
def test_outline_wins_over_header_account_and_rows_inherit_header_code(rules: Rules) -> None:
"""Review Focus 4: счёт в шапке, строк-счетов нет, outline есть — `outline`, но строки наследуют счёт шапки."""
rows: list[list[object]] = [
["ООО Зерновая"],
["Оборотно-сальдовая ведомость по счету 60"],
["Период: 9 месяцев 2025 г."],
[],
*_table_head(),
[L(0), "ООО А", 100, None, 50, 30, 120, None],
[L(1), "Договор 1", 100, None, 50, 30, 120, None],
[L(0), "Итого", 100, None, 50, 30, 120, None],
]
document, codes = _parse(rules, rows)
assert "OSV_HIERARCHY_BY_OUTLINE" in codes
assert HEADER_ACCOUNT_CODE not in codes
data = [item for item in document.rows if item.group_type != "TOTAL"]
assert [item.account_code_raw for item in data] == ["60", "60"]