From 096d53b10c63649cac67ec36c3b71e22cbe2b042 Mon Sep 17 00:00:00 2001 From: Andrey Epifancev Date: Tue, 6 Oct 2026 12:57:20 +0400 Subject: [PATCH] =?UTF-8?q?feat(seed):=20=D0=BF=D0=BE=D0=BB=D0=BD=D1=8B?= =?UTF-8?q?=D0=B9=20=D0=BF=D0=BB=D0=B0=D0=BD=20=D1=81=D1=87=D0=B5=D1=82?= =?UTF-8?q?=D0=BE=D0=B2=201=D0=A1=20=D0=B2=20seed=20(488=20=D1=81=D1=82?= =?UTF-8?q?=D1=80=D0=BE=D0=BA)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Seed chart_of_accounts.csv заменён выгрузкой 1С: буквенные субсчета (01.К, 62.ОТ, 76.АВ), забалансовые 001–012 и буквенные корни (МЦ, ГТД…), «Я…». Валидатор seed принимает буквенные коды, 000 и 012, сирот выгрузки («Я68.01» без «Я68») с пустым parent_code; kind — из «Вида» 1С. 18 из 19 кодов реальных ОСВ теперь получают account_id (60.АВ — только в синтетике, в 1С нет). ASSUMPTION(OQ-113): выгрузка считается полной. Closes #23 Co-Authored-By: Claude Sonnet 4.5 Claude-Session: cedd7915-2efe-41e5-988c-a9117033598b --- api/scripts/seed_lib/loaders.py | 40 +- api/seed/core/chart_of_accounts.csv | 446 +++++++++++++++++++-- api/tests/test_domain_osv_mapping.py | 2 +- api/tests/test_mapping_golden.py | 4 +- api/tests/test_seed_chart.py | 116 +++++- openspec/specs/reference-data-seed/spec.md | 12 +- 6 files changed, 547 insertions(+), 73 deletions(-) diff --git a/api/scripts/seed_lib/loaders.py b/api/scripts/seed_lib/loaders.py index 4f483f6..009d401 100644 --- a/api/scripts/seed_lib/loaders.py +++ b/api/scripts/seed_lib/loaders.py @@ -144,22 +144,36 @@ def _load_role_permissions( CHART_COLUMNS = ["code", "parent_code", "name", "kind", "row_type", "is_off_balance"] -#: нормализованный код: NN или NNN (забалансовый), NN.MM, NN.MM.K (K без ведущего нуля: 76.07.1, как в ТЗ; 60.1 — нет) -_ACCOUNT_CODE = re.compile(r"^\d{2,3}(\.\d{2}(\.[1-9]\d?)?)?$") +#: нормализованный код. Цифровые: NN, NNN, NN.MM, NN.MM.K (K без ведущего нуля: 76.07.1, как в ТЗ; 60.1 — нет), +#: буквенные субсчета: 01.К, 76.АВ, 62.ОТ.1, 99.02.И, 004.К. Буквенные корни плана 1С: МЦ, НЕ, ГТД, РВ.1, Я68.01 — +#: буквы кириллицей, как в выгрузке 1С (issue #23, ASSUMPTION(OQ-113): выгрузка полна). +_LETTER = "[А-ЯЁ]" +_ANALYTIC = rf"(?:\.[1-9]\d?|\.{_LETTER})" +_ACCOUNT_CODE = re.compile( + rf"^(?:\d{{2,3}}(?:\.(?:\d{{2}}|{_LETTER}{{1,2}}){_ANALYTIC}?)?" + rf"|(?:{_LETTER}{{2,3}}|Я\d{{2}})(?:\.(?:\d{{1,2}}|{_LETTER}{{1,2}}){_ANALYTIC}?)?)$" +) _ROW_TYPE_BY_DEPTH = (AccountRowType.account, AccountRowType.subaccount, AccountRowType.analytic) -_OFF_BALANCE_ROOTS = {f"{n:03d}" for n in range(1, 12)} -_OFF_BALANCE_CODE_LENGTH = 3 # забалансовые счета — трёхзначные (001–011), балансовые синтетические — двузначные +#: забалансовые счета 1С: 001–012 и буквенные корни (МЦ, НЕ, ГТД, ИНВ, КВ, ОТ, РВ, УСН); 000 и «Я…» — балансовые +_OFF_BALANCE_DIGIT_ROOTS = {f"{n:03d}" for n in range(1, 13)} +_LETTER_ROOT = re.compile(rf"^{_LETTER}{{2,3}}$") +_THREE_DIGIT_ROOTS = {f"{n:03d}" for n in range(0, 13)} +_OFF_BALANCE_CODE_LENGTH = 3 # трёхзначные корни — 000–012, балансовые синтетические — двузначные + + +def _is_off_balance_root(root: str) -> bool: + return root in _OFF_BALANCE_DIGIT_ROOTS or _LETTER_ROOT.match(root) is not None def _chart_row(row: dict[str | None, Any], where: str, code: str) -> AccountSeed: """Проверка одной строки плана счетов, не требующая других строк.""" where = f"{where} ({code})" if not _ACCOUNT_CODE.match(code): - raise SeedError(f"{where}: код не нормализован, ожидается вид 60, 001, 60.01 или 76.07.1") + raise SeedError(f"{where}: код не нормализован, ожидается вид 60, 001, 60.01, 76.07.1, 01.К или МЦ.04") root = code.split(".", maxsplit=1)[0] - off_balance_root = len(root) == _OFF_BALANCE_CODE_LENGTH - if off_balance_root and root not in _OFF_BALANCE_ROOTS: - raise SeedError(f"{where}: трёхзначные коды допустимы только для 001–011") + if len(root) == _OFF_BALANCE_CODE_LENGTH and root.isdigit() and root not in _THREE_DIGIT_ROOTS: + raise SeedError(f"{where}: трёхзначные коды допустимы только для 000–012") + off_balance_root = _is_off_balance_root(root) if root == "00": raise SeedError(f"{where}: счёта 00 не существует") kind_text = str(row["kind"]).strip() @@ -186,7 +200,7 @@ def _chart_row(row: dict[str | None, Any], where: str, code: str) -> AccountSeed if off_balance_root and not is_off_balance: raise SeedError(f"{where}: забалансовый счёт должен иметь is_off_balance=true") if not off_balance_root and is_off_balance: - raise SeedError(f"{where}: is_off_balance=true допустим только для счетов 001–011") + raise SeedError(f"{where}: is_off_balance=true допустим только для счетов 001–012 и буквенных (МЦ, НЕ, ГТД…)") if row_type is AccountRowType.account and kind is None: raise SeedError(f"{where}: у синтетического счёта должен быть задан kind") name = str(row["name"]).strip() @@ -196,6 +210,12 @@ def _chart_row(row: dict[str | None, Any], where: str, code: str) -> AccountSeed return AccountSeed(code, parent_text or None, name, kind, row_type, is_off_balance) +def _has_ancestor(code: str, accounts: dict[str, AccountSeed]) -> bool: + """Есть ли в плане хотя бы один код-предок (по префиксу сегментов).""" + parts = code.split(".") + return any(".".join(parts[:n]) in accounts for n in range(1, len(parts))) + + def load_chart_of_accounts(core: Path, seed_dir: Path) -> dict[str, AccountSeed]: """План счетов из `chart_of_accounts.csv` (UTF-8): проверка до записи, порядок файла сохраняется.""" path = core / "chart_of_accounts.csv" @@ -226,6 +246,8 @@ def load_chart_of_accounts(core: Path, seed_dir: Path) -> dict[str, AccountSeed] if account.parent_code != expected_parent: if expected_parent is None: raise SeedError(f"{where}: у синтетического счёта parent_code должен быть пустым") + if account.parent_code is None and not _has_ancestor(code, accounts): + continue # сирота выгрузки 1С («Я68.01» без «Я68»): родителей не выдумываем raise SeedError(f"{where}: родитель должен быть «{expected_parent}», указан «{account.parent_code or ''}»") if account.parent_code is not None and account.parent_code not in accounts: raise SeedError(f"{where}: родитель «{account.parent_code}» не найден в файле") diff --git a/api/seed/core/chart_of_accounts.csv b/api/seed/core/chart_of_accounts.csv index f41fdd2..2106867 100644 --- a/api/seed/core/chart_of_accounts.csv +++ b/api/seed/core/chart_of_accounts.csv @@ -1,123 +1,489 @@ code,parent_code,name,kind,row_type,is_off_balance +000,,Вспомогательный счет,AP,account,false 01,,Основные средства,A,account,false +01.01,01,Основные средства в организации,A,subaccount,false +01.03,01,Арендованное имущество,A,subaccount,false +01.05,01,Затраты на ремонт основных средств,A,subaccount,false +01.08,01,"Объекты недвижимости, права собственности на которые не зарегистрированы",A,subaccount,false +01.09,01,Выбытие основных средств,A,subaccount,false +01.11,01,Групповые объекты основных средств,A,subaccount,false +01.К,01,Корректировка стоимости арендованного имущества,A,subaccount,false 02,,Амортизация основных средств,P,account,false +02.01,02,"Амортизация основных средств, учитываемых на счете 01",P,subaccount,false +02.02,02,"Амортизация основных средств, учитываемых на счете 03",P,subaccount,false +02.03,02,Амортизация арендованного имущества,P,subaccount,false +02.04,02,"Обесценение основных средств, учитываемых на счете 01",P,subaccount,false +02.05,02,Амортизация затрат на ремонт основных средств,P,subaccount,false +02.11,02,Амортизация групповых объектов основных средств,P,subaccount,false 03,,Доходные вложения в материальные ценности,A,account,false +03.01,03,Материальные ценности в организации,A,subaccount,false +03.02,03,Материальные ценности предоставленные во временное владение и пользование,A,subaccount,false +03.03,03,Материальные ценности предоставленные во временное пользование,A,subaccount,false +03.04,03,Прочие доходные вложения,A,subaccount,false +03.09,03,Выбытие материальных ценностей,A,subaccount,false 04,,Нематериальные активы,A,account,false +04.01,04,Нематериальные активы организации,A,subaccount,false +04.02,04,"Расходы на научно-исследовательские, опытно-конструкторские и технологические работы",A,subaccount,false +04.09,04,Выбытие нематериальных активов,A,subaccount,false 05,,Амортизация нематериальных активов,P,account,false +05.01,05,Амортизация нематериальных активов,P,subaccount,false +05.02,05,Обесценение нематериальных активов,P,subaccount,false 07,,Оборудование к установке,A,account,false 08,,Вложения во внеоборотные активы,A,account,false +08.01,08,Приобретение земельных участков,A,subaccount,false +08.01.1,08.01,Приобретение земельных участков с доп. расходами,A,analytic,false +08.01.2,08.01,Приобретение земельных участков без доп. расходов,A,analytic,false +08.02,08,Приобретение объектов природопользования,A,subaccount,false +08.03,08,Строительство объектов основных средств,A,subaccount,false +08.04,08,Приобретение объектов основных средств,A,subaccount,false +08.04.1,08.04,Приобретение компонентов основных средств,A,analytic,false +08.04.2,08.04,Приобретение основных средств,A,analytic,false +08.04.5,08.04,Вложения в ремонты основных средств,A,analytic,false +08.05,08,Приобретение нематериальных активов,A,subaccount,false +08.06,08,Перевод молодняка животных в основное стадо,A,subaccount,false +08.07,08,Приобретение взрослых животных,A,subaccount,false +08.08,08,"Выполнение научно-исследовательских, опытно-конструкторских и технологических работ",A,subaccount,false +08.11,08,Нематериальные поисковые активы,A,subaccount,false +08.12,08,Материальные поисковые активы,A,subaccount,false 09,,Отложенные налоговые активы,A,account,false 10,,Материалы,A,account,false +10.01,10,Сырье и материалы,A,subaccount,false +10.02,10,"Покупные полуфабрикаты и комплектующие изделия, конструкции и детали",A,subaccount,false +10.03,10,Топливо,A,subaccount,false +10.03.1,10.03,Топливо на складе,A,analytic,false +10.03.2,10.03,Топливо в баке,A,analytic,false +10.04,10,Тара и тарные материалы,A,subaccount,false +10.05,10,Запасные части,A,subaccount,false +10.06,10,Прочие материалы,A,subaccount,false +10.07,10,"Материалы, переданные в переработку на сторону",A,subaccount,false +10.08,10,Строительные материалы,A,subaccount,false +10.09,10,Инвентарь и хозяйственные принадлежности,A,subaccount,false +10.10,10,Специальная оснастка и специальная одежда на складе,A,subaccount,false +10.11,10,Специальная оснастка и специальная одежда в эксплуатации,A,subaccount,false +10.11.1,10.11,Специальная одежда в эксплуатации,A,analytic,false +10.11.2,10.11,Специальная оснастка в эксплуатации,A,analytic,false +10.21,10,Малоценное оборудование и запасы,A,subaccount,false +10.21.1,10.21,Приобретение малоценного оборудования и запасов,A,analytic,false +10.21.2,10.21,Выбытие малоценного оборудования и запасов,P,analytic,false 11,,Животные на выращивании и откорме,A,account,false 14,,Резервы под снижение стоимости материальных ценностей,P,account,false +14.01,14,Резервы под снижение стоимости материалов,P,subaccount,false +14.02,14,Резервы под снижение стоимости товаров,P,subaccount,false +14.03,14,Резервы под снижение стоимости готовой продукции,P,subaccount,false +14.04,14,Резервы под снижение стоимости незавершенного производства,P,subaccount,false 15,,Заготовление и приобретение материальных ценностей,A,account,false +15.01,15,Заготовление и приобретение материалов,A,subaccount,false +15.02,15,Приобретение товаров,A,subaccount,false 16,,Отклонение в стоимости материальных ценностей,AP,account,false -19,,Налог на добавленную стоимость по приобретенным ценностям,A,account,false +16.01,16,Отклонение в стоимости материалов,AP,subaccount,false +16.02,16,Отклонение в стоимости товаров,AP,subaccount,false +19,,НДС по приобретенным ценностям,A,account,false +19.01,19,НДС при приобретении основных средств,A,subaccount,false +19.02,19,НДС по приобретенным нематериальным активам,A,subaccount,false +19.03,19,НДС по приобретенным материально-производственным запасам,A,subaccount,false +19.04,19,НДС по приобретенным услугам,A,subaccount,false +19.05,19,"НДС, уплаченный при ввозе товаров на территорию Российской Федерации",A,subaccount,false +19.06,19,Акцизы по оплаченным материальным ценностям,A,subaccount,false +19.07,19,"НДС по товарам, реализованным по ставке 0% (экспорт)",A,subaccount,false +19.08,19,НДС при строительстве основных средств,A,subaccount,false +19.09,19,НДС по уменьшению стоимости реализации,A,subaccount,false +19.10,19,"НДС, уплачиваемый при импорте из Таможенного союза",A,subaccount,false 20,,Основное производство,A,account,false +20.01,20,Основное производство,A,subaccount,false +20.02,20,Производство продукции из давальческого сырья,A,subaccount,false +20.04,20,Собственные исследования и разработки,A,subaccount,false 21,,Полуфабрикаты собственного производства,A,account,false 23,,Вспомогательные производства,A,account,false +23.01,23,Вспомогательные производства,A,subaccount,false +23.05,23,Выполнение ремонтов основных средств,A,subaccount,false 25,,Общепроизводственные расходы,A,account,false 26,,Общехозяйственные расходы,A,account,false 28,,Брак в производстве,A,account,false 29,,Обслуживающие производства и хозяйства,A,account,false 40,,"Выпуск продукции (работ, услуг)",AP,account,false 41,,Товары,A,account,false +41.01,41,Товары на складах,A,subaccount,false +41.02,41,Товары в розничной торговле (по покупной стоимости),A,subaccount,false +41.03,41,Тара под товаром и порожняя,A,subaccount,false +41.04,41,Покупные изделия,A,subaccount,false +41.11,41,Товары в розничной торговле (в АТТ по продажной стоимости),A,subaccount,false +41.12,41,Товары в розничной торговле (в НТТ по продажной стоимости),A,subaccount,false +41.К,41,Корректировка товаров прошлого периода,A,subaccount,false 42,,Торговая наценка,P,account,false +42.01,42,Торговая наценка в автоматизированных торговых точках,P,subaccount,false +42.02,42,Торговая наценка в неавтоматизированных торговых точках,P,subaccount,false 43,,Готовая продукция,A,account,false 44,,Расходы на продажу,A,account,false +44.01,44,"Издержки обращения в организациях, осуществляющих торговую деятельность",A,subaccount,false +44.02,44,"Коммерческие расходы в организациях, осуществляющих промышленную и иную производственную деятельность",A,subaccount,false 45,,Товары отгруженные,A,account,false +45.01,45,Покупные товары отгруженные,A,subaccount,false +45.02,45,Готовая продукция отгруженная,A,subaccount,false +45.03,45,Прочие товары отгруженные,A,subaccount,false +45.04,45,Переданные объекты недвижимости,A,subaccount,false 46,,Выполненные этапы по незавершенным работам,A,account,false 50,,Касса,A,account,false +50.01,50,Касса организации,A,subaccount,false +50.02,50,Операционная касса,A,subaccount,false +50.03,50,Денежные документы,A,subaccount,false +50.04,50,Касса по деятельности платежного агента,A,subaccount,false +50.21,50,Касса организации (в валюте),A,subaccount,false +50.23,50,Денежные документы (в валюте),A,subaccount,false 51,,Расчетные счета,A,account,false 52,,Валютные счета,A,account,false +53,,Счет цифрового рубля,A,account,false 55,,Специальные счета в банках,A,account,false +55.01,55,Аккредитивы,A,subaccount,false +55.02,55,Чековые книжки,A,subaccount,false +55.03,55,Депозитные счета,A,subaccount,false +55.04,55,Прочие специальные счета,A,subaccount,false +55.21,55,Аккредитивы (в валюте),A,subaccount,false +55.23,55,Депозитные счета (в валюте),A,subaccount,false +55.24,55,Прочие специальные счета (в валюте),A,subaccount,false 57,,Переводы в пути,A,account,false +57.01,57,Переводы в пути,A,subaccount,false +57.02,57,Приобретение иностранной валюты,A,subaccount,false +57.03,57,Продажи по платежным картам,A,subaccount,false +57.21,57,Переводы в пути (в валюте),A,subaccount,false +57.22,57,Реализация иностранной валюты,A,subaccount,false 58,,Финансовые вложения,A,account,false 58.01,58,Паи и акции,A,subaccount,false +58.01.1,58.01,Паи,A,analytic,false +58.01.2,58.01,Акции,A,analytic,false +58.02,58,Долговые ценные бумаги,A,subaccount,false 58.03,58,Предоставленные займы,A,subaccount,false +58.04,58,Вклады по договору простого товарищества,A,subaccount,false +58.05,58,Приобретенные права в рамках оказания финансовых услуг,A,subaccount,false 59,,Резервы под обесценение финансовых вложений,P,account,false 60,,Расчеты с поставщиками и подрядчиками,AP,account,false -60.01,60,Расчеты с поставщиками и подрядчиками,AP,subaccount,false -60.02,60,Расчеты по авансам выданным,AP,subaccount,false -60.03,60,Расчеты по векселям выданным,AP,subaccount,false -60.21,60,Расчеты с поставщиками и подрядчиками (в валюте),AP,subaccount,false -60.22,60,Расчеты по авансам выданным (в валюте),AP,subaccount,false -60.31,60,Расчеты с поставщиками и подрядчиками (в условных единицах),AP,subaccount,false -60.32,60,Расчеты по авансам выданным (в условных единицах),AP,subaccount,false +60.01,60,Расчеты с поставщиками и подрядчиками,P,subaccount,false +60.02,60,Расчеты по авансам выданным,A,subaccount,false +60.03,60,Векселя выданные,P,subaccount,false +60.21,60,Расчеты с поставщиками и подрядчиками (в валюте),P,subaccount,false +60.22,60,Расчеты по авансам выданным (в валюте),A,subaccount,false +60.31,60,Расчеты с поставщиками и подрядчиками (в у.е.),P,subaccount,false +60.32,60,Расчеты по авансам выданным (в у.е.),A,subaccount,false 62,,Расчеты с покупателями и заказчиками,AP,account,false -62.01,62,Расчеты с покупателями и заказчиками,AP,subaccount,false -62.02,62,Расчеты по авансам полученным,AP,subaccount,false -62.03,62,Расчеты по векселям полученным,AP,subaccount,false -62.21,62,Расчеты с покупателями и заказчиками (в валюте),AP,subaccount,false -62.22,62,Расчеты по авансам полученным (в валюте),AP,subaccount,false -62.31,62,Расчеты с покупателями и заказчиками (в условных единицах),AP,subaccount,false -62.32,62,Расчеты по авансам полученным (в условных единицах),AP,subaccount,false +62.01,62,Расчеты с покупателями и заказчиками,A,subaccount,false +62.02,62,Расчеты по авансам полученным,P,subaccount,false +62.03,62,Векселя полученные,A,subaccount,false +62.21,62,Расчеты с покупателями и заказчиками (в валюте),A,subaccount,false +62.22,62,Расчеты по авансам полученным (в валюте),P,subaccount,false +62.31,62,Расчеты с покупателями и заказчиками (в у.е.),A,subaccount,false +62.32,62,Расчеты по авансам полученным (в у.е.),P,subaccount,false +62.ОТ,62,Расчеты по авансам полученным в счет отгрузки,P,subaccount,false +62.ОТ.1,62.ОТ,Расчеты по авансам полученным в счет отгрузки,P,analytic,false +62.ОТ.2,62.ОТ,Расчеты по авансам полученным (в валюте) в счет отгрузки,P,analytic,false +62.ОТ.3,62.ОТ,Расчеты по авансам полученным (в у.е.) в счет отгрузки,P,analytic,false +62.Р,62,Расчеты с розничными покупателями,A,subaccount,false 63,,Резервы по сомнительным долгам,P,account,false 66,,Расчеты по краткосрочным кредитам и займам,P,account,false +66.01,66,Краткосрочные кредиты,P,subaccount,false 66.02,66,Проценты по краткосрочным кредитам,P,subaccount,false 66.03,66,Краткосрочные займы,P,subaccount,false 66.04,66,Проценты по краткосрочным займам,P,subaccount,false -66.06,66,Проценты по краткосрочным кредитам и займам (субсчет 06),P,subaccount,false -66.22,66,Проценты по краткосрочным кредитам и займам (субсчет 22),P,subaccount,false -66.24,66,Проценты по краткосрочным кредитам и займам (субсчет 24),P,subaccount,false -66.26,66,Проценты по краткосрочным кредитам и займам (субсчет 26),P,subaccount,false +66.05,66,Краткосрочные долговые ценные бумаги,P,subaccount,false +66.06,66,Проценты по краткосрочным долговым ценным бумагам,P,subaccount,false +66.21,66,Краткосрочные кредиты (в валюте),P,subaccount,false +66.22,66,Проценты по краткосрочным кредитам (в валюте),P,subaccount,false +66.23,66,Краткосрочные займы (в валюте),P,subaccount,false +66.24,66,Проценты по краткосрочным займам (в валюте),P,subaccount,false +66.25,66,Краткосрочные долговые ценные бумаги (в валюте),P,subaccount,false +66.26,66,Проценты по краткосрочным долговым ценным бумагам (в валюте),P,subaccount,false 67,,Расчеты по долгосрочным кредитам и займам,P,account,false +67.01,67,Долгосрочные кредиты,P,subaccount,false 67.02,67,Проценты по долгосрочным кредитам,P,subaccount,false 67.03,67,Долгосрочные займы,P,subaccount,false 67.04,67,Проценты по долгосрочным займам,P,subaccount,false -67.06,67,Проценты по долгосрочным кредитам и займам (субсчет 06),P,subaccount,false -67.22,67,Проценты по долгосрочным кредитам и займам (субсчет 22),P,subaccount,false -67.24,67,Проценты по долгосрочным кредитам и займам (субсчет 24),P,subaccount,false -67.26,67,Проценты по долгосрочным кредитам и займам (субсчет 26),P,subaccount,false +67.05,67,Долгосрочные долговые ценные бумаги,P,subaccount,false +67.06,67,Проценты по долгосрочным долговым ценным бумагам,P,subaccount,false +67.21,67,Долгосрочные кредиты (в валюте),P,subaccount,false +67.22,67,Проценты по долгосрочным кредитам (в валюте),P,subaccount,false +67.23,67,Долгосрочные займы (в валюте),P,subaccount,false +67.24,67,Проценты по долгосрочным займам (в валюте),P,subaccount,false +67.25,67,Долгосрочные долговые ценные бумаги (в валюте),P,subaccount,false +67.26,67,Проценты по долгосрочным долговым ценным бумагам (в валюте),P,subaccount,false 68,,Расчеты по налогам и сборам,AP,account,false +Я68.01,,(Не используется) НДФЛ при исполнении обязанностей налогового агента,AP,subaccount,false +68.01,68,НДФЛ исчисленный налоговым агентом,AP,subaccount,false +68.02,68,Налог на добавленную стоимость,AP,subaccount,false +68.03,68,Акцизы,AP,subaccount,false +68.04,68,Налог на прибыль,AP,subaccount,false +68.04.1,68.04,Расчеты с бюджетом,AP,analytic,false +68.04.2,68.04,Расчет налога на прибыль,AP,analytic,false +68.06,68,Земельный налог,AP,subaccount,false +68.07,68,Транспортный налог,AP,subaccount,false +68.08,68,Налог на имущество,AP,subaccount,false +68.09,68,Налог на рекламу,AP,subaccount,false +68.10,68,Прочие налоги и сборы,AP,subaccount,false +68.11,68,Единый налог на вмененный доход,AP,subaccount,false +68.12,68,Налог при упрощенной системе налогообложения,AP,subaccount,false +68.13,68,Торговый сбор,AP,subaccount,false +68.14,68,Налог при патентной системе налогообложения,AP,subaccount,false +68.15,68,Налог при Автоматизированной упрощенной системе налогообложения,AP,subaccount,false +68.16,68,Налог на профессиональный доход,AP,subaccount,false +68.17,68,Туристический налог,AP,subaccount,false +68.21,68,НДФЛ индивидуального предпринимателя,AP,subaccount,false +68.22,68,НДС по экспорту к возмещению,A,subaccount,false +68.32,68,НДС при исполнении обязанностей налогового агента,P,subaccount,false +68.34,68,Налог на прибыль при исполнении обязанностей налогового агента,AP,subaccount,false +68.42,68,НДС при импорте товаров из Таможенного союза,P,subaccount,false +68.52,68,НДС налогового агента по отдельным видам товаров,AP,subaccount,false +68.90,68,Единый налоговый счет,AP,subaccount,false 69,,Расчеты по социальному страхованию и обеспечению,AP,account,false -70,,Расчеты с персоналом по оплате труда,P,account,false +69.01,69,Расчеты по социальному страхованию,AP,subaccount,false +69.02,69,Расчеты по пенсионному обеспечению,AP,subaccount,false +69.02.1,69.02,Страховая часть трудовой пенсии,AP,analytic,false +69.02.2,69.02,Накопительная часть трудовой пенсии,AP,analytic,false +69.02.3,69.02,Взносы на доплату к пенсии членам летных экипажей,AP,analytic,false +69.02.4,69.02,Взносы на доплату к пенсии работникам организаций угольной промышленности,AP,analytic,false +69.02.5,69.02,"Дополнительные взносы на страховую часть пенсии работникам, занятым на работах с вредными условиями труда",AP,analytic,false +69.02.6,69.02,"Дополнительные взносы на страховую часть пенсии работникам, занятым на работах с тяжелыми условиями труда",AP,analytic,false +69.02.7,69.02,Обязательное пенсионное страхование,AP,analytic,false +69.03,69,Расчеты по обязательному медицинскому страхованию,AP,subaccount,false +69.03.1,69.03,Федеральный фонд ОМС,AP,analytic,false +69.03.2,69.03,Территориальный фонд ОМС,AP,analytic,false +69.04,69,"ЕСН в части, перечисляемой в Федеральный бюджет",AP,subaccount,false +69.05,69,Добровольные взносы на накопительную часть трудовой пенсии,AP,subaccount,false +69.05.1,69.05,Взносы за счет работодателя,AP,analytic,false +69.05.2,69.05,"Взносы, удерживаемые из доходов работника",AP,analytic,false +69.06,69,"Расчеты по страховым взносам, уплачиваемым исходя из стоимости страхового года",AP,subaccount,false +69.06.1,69.06,Взносы в ПФР (страховая часть),AP,analytic,false +69.06.2,69.06,Взносы в ПФР (накопительная часть),AP,analytic,false +69.06.3,69.06,Взносы в ФОМС,AP,analytic,false +69.06.4,69.06,Взносы в ФСС,AP,analytic,false +69.06.5,69.06,Обязательное пенсионное страхование предпринимателя,AP,analytic,false +69.06.6,69.06,Страховые взносы единый тариф ИП,AP,analytic,false +69.09,69,Страховые взносы по единому тарифу,AP,subaccount,false +69.11,69,Расчеты по обязательному социальному страхованию от несчастных случаев на производстве и профессиональных заболеваний,AP,subaccount,false +69.12,69,Расчеты по добровольным взносам в ФСС на страхование работников на случай временной нетрудоспособности,AP,subaccount,false +69.13,69,"Расчеты по средствам ФСС для страхователей, применяющих специальные режимы налогообложения",AP,subaccount,false +69.13.1,69.13,"Расчеты по средствам ФСС для страхователей, уплачивающих ЕНВД",AP,analytic,false +69.13.2,69.13,"Расчеты по средствам ФСС для страхователей, применяющих УСН",AP,analytic,false +70,,Расчеты с персоналом по оплате труда,AP,account,false 71,,Расчеты с подотчетными лицами,AP,account,false +71.01,71,Расчеты с подотчетными лицами,AP,subaccount,false +71.21,71,Расчеты с подотчетными лицами (в валюте),AP,subaccount,false 73,,Расчеты с персоналом по прочим операциям,AP,account,false +73.01,73,Расчеты по предоставленным займам,A,subaccount,false +73.02,73,Расчеты по возмещению материального ущерба,A,subaccount,false +73.03,73,Расчеты по прочим операциям,AP,subaccount,false 75,,Расчеты с учредителями,AP,account,false +75.01,75,Расчеты по вкладам в уставный (складочный) капитал,A,subaccount,false +75.02,75,Расчеты по выплате доходов,P,subaccount,false 76,,Расчеты с разными дебиторами и кредиторами,AP,account,false +76.01,76,"Расчеты по имущественному, личному и добровольному страхованию",AP,subaccount,false +76.01.1,76.01,Расчеты по имущественному и личному страхованию,AP,analytic,false +76.01.2,76.01,Платежи (взносы) по добровольному страхованию на случай смерти и причинения вреда здоровью,A,analytic,false +76.01.9,76.01,Платежи (взносы) по прочим видам страхования,A,analytic,false +76.02,76,Расчеты по претензиям,A,subaccount,false 76.03,76,Расчеты по причитающимся дивидендам и другим доходам,AP,subaccount,false +76.04,76,Расчеты по депонированным суммам,P,subaccount,false 76.05,76,Расчеты с прочими поставщиками и подрядчиками,AP,subaccount,false -76.07,76,Расчеты по лизингу,AP,subaccount,false -76.07.1,76.07,Обязательства по лизингу,AP,analytic,false -76.07.2,76.07,Прочие расчеты по лизингу (подсубсчет 2),AP,analytic,false -76.07.5,76.07,Проценты по лизингу,AP,analytic,false -76.07.9,76.07,Активы по лизингу,AP,analytic,false -76.08,76,Расчеты по процентам,AP,subaccount,false +76.06,76,Расчеты с прочими покупателями и заказчиками,AP,subaccount,false +76.07,76,Расчеты по аренде,AP,subaccount,false +76.07.1,76.07,Арендные обязательства,P,analytic,false +76.07.2,76.07,Задолженность по арендным платежам,AP,analytic,false +76.07.5,76.07,Проценты по аренде,A,analytic,false +76.07.9,76.07,НДС по арендным обязательствам,A,analytic,false +76.08,76,Проценты по рассрочке,A,subaccount,false 76.09,76,Прочие расчеты с разными дебиторами и кредиторами,AP,subaccount,false -76.28,76,Расчеты по процентам (в валюте),AP,subaccount,false -76.38,76,Расчеты по процентам (в условных единицах),AP,subaccount,false +76.10,76,Прочие расчеты с физическими лицами,AP,subaccount,false +76.13,76,Расчеты с факторинговыми компаниями,A,subaccount,false +76.14,76,Приобретение билетов для командировок,A,subaccount,false +76.15,76,Приобретение по топливным картам,P,subaccount,false +76.16,76,Расчеты с самозанятыми по реестрам выплат,P,subaccount,false +76.17,76,Расчеты по налогам с третьими лицами,AP,subaccount,false +76.18,76,Приобретение прав на использование результатов интеллектуальной деятельности,A,subaccount,false +76.21,76,Расчеты по имущественному и личному страхованию (в валюте),AP,subaccount,false +76.22,76,Расчеты по претензиям (в валюте),A,subaccount,false +76.25,76,Расчеты с прочими поставщиками и подрядчиками (в валюте),AP,subaccount,false +76.26,76,Расчеты с прочими покупателями и заказчиками (в валюте),AP,subaccount,false +76.27,76,Расчеты по аренде (в валюте),AP,subaccount,false +76.27.1,76.27,Арендные обязательства (в валюте),P,analytic,false +76.27.2,76.27,Задолженность по арендным платежам (в валюте),AP,analytic,false +76.27.5,76.27,Проценты по аренде (в валюте),A,analytic,false +76.27.9,76.27,НДС по арендным обязательствам (в валюте),A,analytic,false +76.28,76,Проценты по рассрочке (в валюте),A,subaccount,false +76.29,76,Прочие расчеты с разными дебиторами и кредиторами (в валюте),AP,subaccount,false +76.32,76,Расчеты по претензиям (в у.е.),A,subaccount,false +76.35,76,Расчеты с прочими поставщиками и подрядчиками (в у.е.),AP,subaccount,false +76.36,76,Расчеты с прочими покупателями и заказчиками (в у.е.),AP,subaccount,false +76.37,76,Расчеты по аренде (в у.е.),AP,subaccount,false +76.37.1,76.37,Арендные обязательства (в у.е.),P,analytic,false +76.37.2,76.37,Задолженность по арендным платежам (в у.е.),AP,analytic,false +76.37.5,76.37,Проценты по аренде (в у.е.),A,analytic,false +76.37.9,76.37,НДС по арендным обязательствам (в у.е.),A,analytic,false +76.38,76,Проценты по рассрочке (в у.е.),A,subaccount,false +76.39,76,Прочие расчеты с разными дебиторами и кредиторами (в у.е.),AP,subaccount,false +76.41,76,Расчеты по исполнительным документам работников,AP,subaccount,false +76.49,76,Расчеты по прочим удержаниям из заработной платы работников,AP,subaccount,false +76.АВ,76,НДС по авансам и предоплатам,A,subaccount,false +76.ВА,76,НДС по авансам и предоплатам выданным,P,subaccount,false +76.К,76,Корректировка расчетов прошлого периода,AP,subaccount,false +76.Н,76,"Расчеты по НДС, отложенному для уплаты в бюджет",P,subaccount,false +76.НА,76,Расчеты по НДС при исполнении обязанностей налогового агента,AP,subaccount,false +76.ОТ,76,"НДС, начисленный по отгрузке",A,subaccount,false 77,,Отложенные налоговые обязательства,P,account,false 79,,Внутрихозяйственные расчеты,AP,account,false +79.01,79,Расчеты по выделенному имуществу,AP,subaccount,false +79.02,79,Расчеты по текущим операциям,AP,subaccount,false +79.03,79,Расчеты по договору доверительного управления имуществом,AP,subaccount,false 80,,Уставный капитал,P,account,false +80.01,80,Обыкновенные акции,P,subaccount,false +80.02,80,Привилегированные акции,P,subaccount,false +80.09,80,Прочий капитал,P,subaccount,false 81,,Собственные акции (доли),A,account,false +81.01,81,Обыкновенные акции,A,subaccount,false +81.02,81,Привилегированные акции,A,subaccount,false +81.09,81,Прочий капитал,A,subaccount,false 82,,Резервный капитал,P,account,false +82.01,82,"Резервы, образованные в соответствии с законодательством",P,subaccount,false +82.02,82,"Резервы, образованные в соответствии с учредительными документами",P,subaccount,false 83,,Добавочный капитал,P,account,false +83.01,83,Прирост стоимости внеоборотных активов по переоценке,P,subaccount,false +83.01.1,83.01,Прирост стоимости основных средств,P,analytic,false +83.01.2,83.01,Прирост стоимости нематериальных активов,P,analytic,false +83.01.3,83.01,Прирост стоимости прочих внеоборотных активов,P,analytic,false +83.02,83,Эмиссионный доход от выпуска обыкновенных акций,P,subaccount,false +83.03,83,Эмиссионный доход от выпуска привилегированных акций,P,subaccount,false +83.09,83,Другие источники,P,subaccount,false 84,,Нераспределенная прибыль (непокрытый убыток),AP,account,false +84.01,84,"Прибыль, подлежащая распределению",P,subaccount,false +84.02,84,"Убыток, подлежащий покрытию",A,subaccount,false +84.03,84,Нераспределенная прибыль в обращении,P,subaccount,false +84.04,84,Нераспределенная прибыль использованная,P,subaccount,false 86,,Целевое финансирование,P,account,false +86.01,86,Целевое финансирование из бюджета,P,subaccount,false +86.02,86,Прочее целевое финансирование и поступления,P,subaccount,false 90,,Продажи,AP,account,false -90.01,90,Выручка,AP,subaccount,false -90.02,90,Себестоимость продаж,AP,subaccount,false -90.03,90,Налог на добавленную стоимость,AP,subaccount,false -90.04,90,Акцизы,AP,subaccount,false -90.09,90,Прибыль (убыток) от продаж,AP,subaccount,false +90.01,90,Выручка,P,subaccount,false +90.01.1,90.01,Выручка по деятельности с основной системой налогообложения,P,analytic,false +90.01.2,90.01,Выручка по отдельным видам деятельности с особым порядком налогообложения,P,analytic,false +90.02,90,Себестоимость продаж,A,subaccount,false +90.02.1,90.02,Себестоимость продаж по деятельности с основной системой налогообложения,A,analytic,false +90.02.2,90.02,Себестоимость продаж по отдельным видам деятельности с особым порядком налогообложения,A,analytic,false +90.03,90,Налог на добавленную стоимость,A,subaccount,false +90.04,90,Акцизы,A,subaccount,false +90.05,90,Экспортные пошлины,A,subaccount,false +90.07,90,Расходы на продажу,A,subaccount,false +90.07.1,90.07,Расходы на продажу по деятельности с основной системой налогообложения,A,analytic,false +90.07.2,90.07,Расходы на продажу по отдельным видам деятельности с особым порядком налогообложения,A,analytic,false +90.08,90,Управленческие расходы,A,subaccount,false +90.08.1,90.08,Управленческие расходы по деятельности с основной системой налогообложения,A,analytic,false +90.08.2,90.08,Управленческие расходы по отдельным видам деятельности с особым порядком налогообложения,A,analytic,false +90.09,90,Прибыль / убыток от продаж,AP,subaccount,false 91,,Прочие доходы и расходы,AP,account,false -91.01,91,Прочие доходы,AP,subaccount,false -91.02,91,Прочие расходы,AP,subaccount,false +91.01,91,Прочие доходы,P,subaccount,false +91.02,91,Прочие расходы,A,subaccount,false 91.09,91,Сальдо прочих доходов и расходов,AP,subaccount,false 94,,Недостачи и потери от порчи ценностей,A,account,false -96,,Резервы предстоящих расходов,P,account,false +96,,Резервы предстоящих расходов,AP,account,false +96.01,96,Оценочные обязательства по вознаграждениям работникам,P,subaccount,false +96.01.1,96.01,Оценочные обязательства по вознаграждениям,P,analytic,false +96.01.2,96.01,Оценочные обязательства по страховым взносам,P,analytic,false +96.09,96,Резервы предстоящих расходов прочие,AP,subaccount,false 97,,Расходы будущих периодов,A,account,false +97.01,97,Расходы на оплату труда будущих периодов,A,subaccount,false +97.02,97,Расходы будущих периодов на добровольное страхование работников,A,subaccount,false +97.11,97,Убытки прошлых лет по налогу на прибыль,A,subaccount,false +97.12,97,Убытки от реализации основных средств,A,subaccount,false +97.21,97,Прочие расходы будущих периодов,A,subaccount,false +97.КР,97,Отложенные расходы по курсовым разницам,A,subaccount,false 98,,Доходы будущих периодов,P,account,false +98.01,98,"Доходы, полученные в счет будущих периодов",P,subaccount,false +98.02,98,Безвозмездные поступления,P,subaccount,false +98.03,98,"Предстоящие поступления по недостачам, выявленным за прошлые годы",P,subaccount,false +98.04,98,"Разница между суммой, подлежащей взысканию с виновных лиц, и балансовой стоимостью по недостачам ценностей",P,subaccount,false +98.КР,98,Отложенные доходы по курсовым разницам,P,subaccount,false 99,,Прибыли и убытки,AP,account,false +99.01,99,Прибыли и убытки от хозяйственной деятельности (за исключением налога на прибыль),AP,subaccount,false +99.01.1,99.01,Прибыли и убытки по деятельности с основной системой налогообложения,AP,analytic,false +99.01.2,99.01,Прибыли и убытки по отдельным видам деятельности с особым порядком налогообложения,AP,analytic,false +99.02,99,Налог на прибыль,AP,subaccount,false +99.02.1,99.02,Условный расход по налогу на прибыль,A,analytic,false +99.02.2,99.02,Условный доход по налогу на прибыль,P,analytic,false +99.02.3,99.02,Постоянный налоговый расход (доход),AP,analytic,false +99.02.4,99.02,Пересчет отложенных налоговых активов и обязательств,AP,analytic,false +99.02.И,99.02,Инвестиционный вычет по налогу на прибыль,P,analytic,false +99.02.О,99.02,Отложенный налог на прибыль,AP,analytic,false +99.02.Т,99.02,Текущий налог на прибыль,A,analytic,false +99.09,99,Прочие прибыли и убытки,AP,subaccount,false 001,,Арендованные основные средства,A,account,true 002,,"Товарно-материальные ценности, принятые на ответственное хранение",A,account,true 003,,"Материалы, принятые в переработку",A,account,true +003.01,003,Материалы на складе,A,subaccount,true +003.02,003,"Материалы, переданные в производство",A,subaccount,true 004,,"Товары, принятые на комиссию",A,account,true +004.01,004,Товары на складе,A,subaccount,true +004.02,004,"Товары, переданные на комиссию",A,subaccount,true +004.К,004,Корректировка комиссионных товаров прошлого периода,A,subaccount,true 005,,"Оборудование, принятое для монтажа",A,account,true 006,,Бланки строгой отчетности,A,account,true 007,,Списанная в убыток задолженность неплатежеспособных дебиторов,A,account,true 008,,Обеспечения обязательств и платежей полученные,A,account,true +008.01,008,Обеспечения обязательств и платежей полученные,A,subaccount,true +008.21,008,Обеспечения обязательств и платежей полученные (в валюте),A,subaccount,true 009,,Обеспечения обязательств и платежей выданные,A,account,true +009.01,009,Обеспечения обязательств и платежей выданные,A,subaccount,true +009.21,009,Обеспечения обязательств и платежей выданные (в валюте),A,subaccount,true 010,,Износ основных средств,A,account,true 011,,"Основные средства, сданные в аренду",A,account,true +012,,Возвратная тара,A,account,true +012.01,012,Возвратная тара на складе,A,subaccount,true +012.02,012,Возвратная тара у покупателя,A,subaccount,true +ГТД,,Учет импортных товаров по номерам ГТД,A,account,true +ИНВ,,Инвестиционный налоговый вычет,A,account,true +ИНВ.Ф,ИНВ,Федеральный инвестиционный налоговый вычет,A,subaccount,true +КВ,,Амортизационная премия,A,account,true +МЦ,,Материальные ценности в эксплуатации,A,account,true +МЦ.02,МЦ,Спецодежда в эксплуатации,A,subaccount,true +МЦ.03,МЦ,Спецоснастка в эксплуатации,A,subaccount,true +МЦ.04,МЦ,Инвентарь и хозяйственные принадлежности в эксплуатации,A,subaccount,true +НЕ,,"Доходы и расходы, не учитываемые в целях налогообложения",AP,account,true +НЕ.01,НЕ,"Расходы, которые не учтены на основании пунктов 1 - 48 статьи 270 НК",AP,subaccount,true +НЕ.01.1,НЕ.01,Выплаты в пользу физических лиц,AP,analytic,true +НЕ.01.9,НЕ.01,Другие выплаты,AP,analytic,true +НЕ.02,НЕ,"Расходы, которые не учтены на основании пункта 49 статьи 270 НК",AP,subaccount,true +НЕ.02.1,НЕ.02,Выплаты в пользу физических лиц,AP,analytic,true +НЕ.02.9,НЕ.02,Другие выплаты,AP,analytic,true +НЕ.03,НЕ,"Внереализационные расходы, не учитываемые в целях налогообложения",AP,subaccount,true +НЕ.04,НЕ,"Доходы, не учитываемые в целях налогообложения",AP,subaccount,true +ОТ,,"Расчеты для целей НДС по товарам, отгруженным без перехода права собственности",A,account,true +ОТ.01,ОТ,"Расчеты для целей НДС по товарам, отгруженным без перехода права собственности",A,subaccount,true +ОТ.02,ОТ,"Расчеты для целей НДС по товарам (в валюте), отгруженным без перехода права собственности",A,subaccount,true +ОТ.03,ОТ,"Расчеты для целей НДС по товарам (в у.е.), отгруженным без перехода права собственности",A,subaccount,true +РВ,,Розничная выручка,A,account,true +РВ.1,РВ,Наличная нераспределенная розничная выручка,A,subaccount,true +РВ.2,РВ,НДС в наличной нераспределенной розничной выручке,A,subaccount,true +РВ.3,РВ,Безналичная нераспределенная розничная выручка,A,subaccount,true +РВ.4,РВ,НДС в безналичной нераспределенной розничной выручке,A,subaccount,true +УСН,,Вспомогательные счета по упрощенной системе налогообложения,AP,account,true +УСН.01,УСН,Расчеты с покупателями по деятельности ЕНВД,AP,subaccount,true +УСН.02,УСН,Расчеты с покупателями за товары комитента,AP,subaccount,true +УСН.03,УСН,Расчеты с покупателями по деятельности на патенте,AP,subaccount,true +УСН.04,УСН,Расчеты с покупателями по деятельности на торговом сборе,AP,subaccount,true +УСН.21,УСН,Расчеты с покупателями в валюте по деятельности ЕНВД,AP,subaccount,true +УСН.22,УСН,Расчеты с покупателями в валюте за товары комитента,AP,subaccount,true +УСН.23,УСН,Расчеты с покупателями в валюте по деятельности на патенте,AP,subaccount,true +УСН.24,УСН,Расчеты с покупателями в валюте по деятельности на торговом сборе,AP,subaccount,true +Я68.01.2,Я68.01,"(Не используется) НДФЛ с доходов свыше предельной величины, исчисленный налоговым агентом",AP,analytic,false +Я68.21,,(Не используется) НДФЛ предпринимателя,AP,subaccount,false +Я68.21.2,Я68.21,(Не используется) НДФЛ индивидуального предпринимателя свыше предельной величины,AP,analytic,false +Я01.К,,не используется,A,subaccount,false +Я69.06.5,,(не используется) Обязательное пенсионное страхование предпринимателя,AP,analytic,false +Я96.01,Я96,не используется,P,subaccount,false +Я96,,не используется,P,account,false +Я81.01,Я81,(Не используется) Обыкновенные акции,A,subaccount,false +Я81.09,Я81,(Не используется) Прочий капитал,A,subaccount,false +Я81.02,Я81,(Не используется) Привилегированные акции,A,subaccount,false +Я75.01,Я75,(Не используется) Расчеты по вкладам в уставный (складочный) капитал,A,subaccount,false +Я75.02,Я75,(Не используется) Расчеты по выплате доходов,P,subaccount,false +Я80.09,Я80,(Не используется) Прочий капитал,P,subaccount,false +Я80.02,Я80,(Не используется) Привилегированные акции,P,subaccount,false +Я80.01,Я80,(Не используется) Обыкновенные акции,P,subaccount,false +Я68.32,,(Не используется) НДС при исполнении обязанностей налогового агента,P,subaccount,false +Я68.42,,(Не используется) НДС при импорте товаров из Таможенного союза,P,subaccount,false +Я75,,(Не используется) Расчеты с учредителями,AP,account,false +Я80,,(Не используется) Уставный капитал,P,account,false +Я81,,(Не используется) Собственные акции (доли),A,account,false diff --git a/api/tests/test_domain_osv_mapping.py b/api/tests/test_domain_osv_mapping.py index bdfd687..92339b5 100644 --- a/api/tests/test_domain_osv_mapping.py +++ b/api/tests/test_domain_osv_mapping.py @@ -193,7 +193,7 @@ def test_build_entries_on_golden_osv_66(fixtures_dir: Path) -> None: assert by_id[first.parent_id].row_value == "66.03" assert first.account_root == "66" assert first.account_id == chart["66.03"] - assert by_number[13].account_id is None # 66.01 нет в seed-плане счетов + assert by_number[13].account_id == chart["66.01"] # 66.01 в плане счетов seed с выгрузкой 1С (issue #23) for entry in sheet.entries: assert (entry.level == 0) == (entry.parent_id is None) assert len(entry.sums) == SUM_COUNT diff --git a/api/tests/test_mapping_golden.py b/api/tests/test_mapping_golden.py index 13a2df9..d94e47d 100644 --- a/api/tests/test_mapping_golden.py +++ b/api/tests/test_mapping_golden.py @@ -9,7 +9,7 @@ Инварианты: строк `osv_entry` = строк результата без `TOTAL`; у каждой строки уровня > 0 есть родитель (строка того же документа с `row_number = parent_row_number`); шесть сумм равны снимку; `account_id` = строка плана счетов seed для -нормализованного кода, а для кодов вне плана — NULL (часть кодов golden в плане seed отсутствует — это норма). +нормализованного кода, а для кодов вне плана — NULL (вне плана 1С остаётся только «60.АВ» синтетического снимка). """ import json @@ -157,6 +157,8 @@ async def test_all_golden_snapshots_mapped(seeded: AsyncSession, fixtures_dir: P f"{sorted(missing_codes)}" ) assert problems == [] + # план счетов seed = выгрузка 1С (issue #23): вне плана остаётся только «60.АВ» синтетического снимка s09 + assert missing_codes <= {"60.АВ"} assert with_kind > 0 # есть сопоставленные строки: проверка «kind ⇔ counterparty_id» не вырождена assert with_account > 0 # строки со счётом плана счетов есть — сверка account_id не вырождена assert mapping_seconds <= TIME_BUDGET_SECONDS diff --git a/api/tests/test_seed_chart.py b/api/tests/test_seed_chart.py index 850e1e1..f91532a 100644 --- a/api/tests/test_seed_chart.py +++ b/api/tests/test_seed_chart.py @@ -1,5 +1,6 @@ """Seed плана счетов (spec reference-data-seed, задача 13; design D-9, OQ-47). +План счетов — полная выгрузка 1С заказчика (issue #23, ASSUMPTION(OQ-113): выгрузка полна, 488 строк). Перечень счетов из §4/§6 правил (`docs/context/05-domain-rules.md`) переписан в тест заново, независимо от `seed/core/chart_of_accounts.csv` и от yaml правил (он появится в задаче 14). """ @@ -47,7 +48,16 @@ SYNTHETIC_94N = { } # fmt: skip SYNTHETIC_94N_COUNT = 62 MAX_CODE_DOTS = 2 # NN.MM.K -OFF_BALANCE = {f"{n:03d}" for n in range(1, 12)} +OFF_BALANCE = {f"{n:03d}" for n in range(1, 13)} # 001–012 +OFF_BALANCE_LETTER = {"ГТД", "ИНВ", "КВ", "МЦ", "НЕ", "ОТ", "РВ", "УСН"} # буквенные забалансовые корни 1С +# Балансовые корни выгрузки 1С вне Плана счетов 94н: вспомогательный 000, 53 (в 94н не активен) и «Я…» (не используется) +EXTRA_ON_BALANCE_ROOTS = {"000", "53", "Я75", "Я80", "Я81", "Я96"} +CHART_SIZE = 488 +# Субсчета реальных ОСВ, которых не было в seed из 122 строк (OQ-113: 19 кодов с account_id = NULL) +OSV_SUBACCOUNTS_FORMERLY_MISSING = {"01.01", "66.01", "76.01", "76.ОТ"} +# «60.АВ» есть только в синтетическом снимке s09 (fixtures/golden), в плане 1С его нет: account_id = NULL +ORPHANS_1C = {"Я68.01", "Я68.21", "Я68.32", "Я68.42", "Я01.К", "Я69.06.5"} # без родителя в выгрузке +NOT_IN_1C_PLAN = {"60.АВ"} def _write_chart(tmp_path: Path, lines: list[str]) -> Path: @@ -73,32 +83,64 @@ def test_repository_chart_is_valid() -> None: for code, account in accounts.items(): assert account.code == code assert account.parent_code is None or account.parent_code in accounts - if account.row_type is AccountRowType.account: - assert account.kind is not None, f"у синтетического счёта {code} не задан kind" - else: - parent = accounts[str(account.parent_code)] - assert account.kind is parent.kind, f"субсчёт {code} должен наследовать kind родителя" - assert "." not in code or code == f"{account.parent_code}.{code.rsplit('.', 1)[1]}" + # kind берётся из «Вида» 1С и у субсчёта может отличаться от родителя (60.01 — П при 60 — АП) + assert account.kind is not None, f"у счёта {code} не задан kind" + if account.parent_code is not None: + assert code == f"{account.parent_code}.{code.rsplit('.', 1)[1]}" + assert accounts[account.parent_code].is_off_balance == account.is_off_balance + assert len(accounts) == CHART_SIZE assert all(code.count(".") <= MAX_CODE_DOTS for code in accounts) assert "60.01" in accounts assert "60.1" not in accounts -def test_repository_chart_off_balance_flag_only_for_001_011() -> None: +def test_repository_chart_has_no_parent_cycles_and_orphans_are_only_unused_copies() -> None: accounts = load_seed(SEED_DIR).accounts - assert {c for c, a in accounts.items() if a.is_off_balance} == OFF_BALANCE + for code in accounts: + seen, current = {code}, accounts[code].parent_code + while current is not None: + assert current not in seen, f"цикл в иерархии через {current}" + seen.add(current) + current = accounts[current].parent_code + orphans = {c for c, a in accounts.items() if a.parent_code is None and a.row_type is not AccountRowType.account} + # в выгрузке 1С нет родителей «Я68», «Я01», «Я69.06»: родителей не выдумываем + assert orphans == {"Я68.01", "Я68.21", "Я68.32", "Я68.42", "Я01.К", "Я69.06.5"} + + +def test_repository_chart_keeps_letter_and_off_balance_accounts_of_1c() -> None: + accounts = load_seed(SEED_DIR).accounts + assert {"01.К", "004.К", "62.ОТ", "МЦ.04", "ГТД", "Я68.01", "Я96", "99.02.И", "НЕ.01.1", "РВ.1"} <= set(accounts) + assert accounts["01.К"].parent_code == "01" + assert accounts["62.ОТ.1"].parent_code == "62.ОТ" + assert accounts["003.01"].is_off_balance and accounts["МЦ.02"].is_off_balance + assert not accounts["000"].is_off_balance and not accounts["Я68.01"].is_off_balance + assert accounts["60.01"].kind is AccountKind.P and accounts["60.02"].kind is AccountKind.A + + +def test_repository_chart_resolves_subaccounts_formerly_missing() -> None: + codes = set(load_seed(SEED_DIR).accounts) + assert OSV_SUBACCOUNTS_FORMERLY_MISSING <= codes + assert not NOT_IN_1C_PLAN & codes + + +def test_repository_chart_off_balance_flag_only_for_001_012_and_letter_roots() -> None: + accounts = load_seed(SEED_DIR).accounts + roots = OFF_BALANCE | OFF_BALANCE_LETTER + assert {c for c, a in accounts.items() if a.is_off_balance and a.parent_code is None} == roots + assert {c for c, a in accounts.items() if a.is_off_balance} == {c for c in accounts if c.split(".")[0] in roots} assert all( accounts[c].row_type is AccountRowType.account and accounts[c].kind is AccountKind.A for c in OFF_BALANCE ) -def test_repository_chart_has_exactly_the_94n_synthetic_accounts() -> None: +def test_repository_chart_has_the_94n_synthetic_accounts_and_1c_extras() -> None: accounts = load_seed(SEED_DIR).accounts synthetic_on_balance = { c for c, a in accounts.items() if a.row_type is AccountRowType.account and not a.is_off_balance } - assert synthetic_on_balance == SYNTHETIC_94N - assert len(synthetic_on_balance) == SYNTHETIC_94N_COUNT + assert synthetic_on_balance == SYNTHETIC_94N | EXTRA_ON_BALANCE_ROOTS + assert SYNTHETIC_94N_COUNT == len(SYNTHETIC_94N) == 62 # noqa: PLR2004 + assert SYNTHETIC_94N <= synthetic_on_balance def test_repository_chart_contains_accounts_of_rules_s4_s6_and_checklist() -> None: @@ -140,7 +182,8 @@ def test_validator_rejects_not_normalized_code(tmp_path: Path) -> None: ["60,,Расчеты,AP,account,false", "60.1,60,Расчеты (руб),AP,subaccount,false"], ) assert message == ( - "core/chart_of_accounts.csv, строка 3 (60.1): код не нормализован, ожидается вид 60, 001, 60.01 или 76.07.1" + "core/chart_of_accounts.csv, строка 3 (60.1): " + "код не нормализован, ожидается вид 60, 001, 60.01, 76.07.1, 01.К или МЦ.04" ) @@ -181,14 +224,45 @@ def test_validator_rejects_off_balance_flag_missing_for_off_balance_account(tmp_ def test_validator_rejects_off_balance_flag_for_on_balance_account(tmp_path: Path) -> None: message = _chart_error(tmp_path, ["60,,Расчеты,AP,account,true"]) - assert ( - message == "core/chart_of_accounts.csv, строка 2 (60): is_off_balance=true допустим только для счетов 001–011" + assert message == ( + "core/chart_of_accounts.csv, строка 2 (60): " + "is_off_balance=true допустим только для счетов 001–012 и буквенных (МЦ, НЕ, ГТД…)" ) def test_validator_rejects_three_digit_code_outside_off_balance_range(tmp_path: Path) -> None: - message = _chart_error(tmp_path, ["012,,Неизвестный,A,account,true"]) - assert message == "core/chart_of_accounts.csv, строка 2 (012): трёхзначные коды допустимы только для 001–011" + message = _chart_error(tmp_path, ["013,,Неизвестный,A,account,true"]) + assert message == "core/chart_of_accounts.csv, строка 2 (013): трёхзначные коды допустимы только для 000–012" + + +def test_validator_accepts_letter_codes_orphans_and_auxiliary_000(tmp_path: Path) -> None: + core = _write_chart( + tmp_path, + [ + "000,,Вспомогательный счет,AP,account,false", + "01,,Основные средства,A,account,false", + "01.К,01,Корректировка,A,subaccount,false", + "МЦ,,Материальные ценности,A,account,true", + "МЦ.04,МЦ,Инвентарь,A,subaccount,true", + "РВ,,Розничная выручка,A,account,true", + "РВ.1,РВ,Наличная выручка,A,subaccount,true", + "Я68.01,,(Не используется) НДС,P,subaccount,false", + ], + ) + accounts = load_chart_of_accounts(core, tmp_path) + assert accounts["Я68.01"].parent_code is None + assert accounts["01.К"].parent_code == "01" + assert accounts["МЦ.04"].is_off_balance is True + + +def test_validator_rejects_empty_parent_when_ancestor_exists(tmp_path: Path) -> None: + message = _chart_error(tmp_path, ["60,,Расчеты,AP,account,false", "60.01,,Расчеты (руб),AP,subaccount,false"]) + assert message == "core/chart_of_accounts.csv, строка 3 (60.01): родитель должен быть «60», указан «»" + + +def test_validator_rejects_letter_root_without_off_balance_flag(tmp_path: Path) -> None: + message = _chart_error(tmp_path, ["МЦ,,Материальные ценности,A,account,false"]) + assert message == "core/chart_of_accounts.csv, строка 2 (МЦ): забалансовый счёт должен иметь is_off_balance=true" def test_validator_rejects_account_without_kind(tmp_path: Path) -> None: @@ -262,18 +336,20 @@ async def test_run_seed_inserts_chart_with_hierarchy(db_session: AsyncSession) - root_codes = set( (await db_session.scalars(select(ChartOfAccount.code).where(ChartOfAccount.parent_id.is_(None)))).all() ) - assert root_codes == SYNTHETIC_94N | OFF_BALANCE + assert root_codes == SYNTHETIC_94N | EXTRA_ON_BALANCE_ROOTS | OFF_BALANCE | OFF_BALANCE_LETTER | ORPHANS_1C @pytest.mark.integration async def test_chart_columns_stored_as_in_file(db_session: AsyncSession) -> None: await run_seed(db_session) rows = {c.code: c for c in (await db_session.scalars(select(ChartOfAccount))).all()} - assert rows["60"].kind is AccountKind.AP + assert rows["60"].kind is AccountKind.AP and rows["60.01"].kind is AccountKind.P assert rows["01"].kind is AccountKind.A and rows["02"].kind is AccountKind.P assert rows["76.07.1"].row_type is AccountRowType.analytic assert rows["60.01"].row_type is AccountRowType.subaccount - assert {c for c, r in rows.items() if r.is_off_balance} == OFF_BALANCE + assert {c for c, r in rows.items() if r.is_off_balance} == { + c for c in rows if c.split(".")[0] in OFF_BALANCE | OFF_BALANCE_LETTER + } @pytest.mark.integration diff --git a/openspec/specs/reference-data-seed/spec.md b/openspec/specs/reference-data-seed/spec.md index 7699fbd..a764ec2 100644 --- a/openspec/specs/reference-data-seed/spec.md +++ b/openspec/specs/reference-data-seed/spec.md @@ -51,8 +51,11 @@ dev-данные загружаются из файлов репозитория ### Requirement: Счета правил и чек-листа существуют в плане счетов Все коды счетов, на которые ссылаются `elimination_rules_v1.yaml` и `required_document_rules.yaml`, SHALL резолвиться в `chart_of_account.code` после seed; `elimination_rule_account.is_excluded = true` SHALL быть у исключений вида -«76 кроме 76.07.5, 76.07.9»; `chart_of_account.kind` SHALL быть задан для всех синтетических счетов, `is_off_balance = true` -для 001–011. +«76 кроме 76.07.5, 76.07.9»; `chart_of_account.kind` SHALL быть задан для всех счетов, `is_off_balance = true` +для забалансовых счетов 001–012 и буквенных корней плана 1С (МЦ, НЕ, ГТД, ИНВ, КВ, ОТ, РВ, УСН) со всеми их субсчетами. +`chart_of_accounts.csv` SHALL содержать полный план счетов 1С заказчика (`fixtures/directories/chart-of-accounts-1c.xlsx`, +488 строк, включая буквенные субсчета `01.К`, `62.ОТ`, `76.АВ`; ASSUMPTION(OQ-113): выгрузка полна); `kind` строки — «Вид» +1С (у субсчёта может отличаться от родителя); субсчёт без родителя в выгрузке (`Я68.01`) загружается с пустым `parent_code`. #### Scenario: Правило № 6 (основная пара) - **WHEN** seed завершён @@ -60,6 +63,11 @@ dev-данные загружаются из файлов репозитория 76.07.5, 76.07.9; сторона 2 — 60.01, 60.03, 60.21, 60.31, 62.02, 62.22, 62.32, 76 и исключение 76.07.1; `elimination_mode = min`, `measure = closing`, `side_1 = D` +#### Scenario: Субсчета реальных ОСВ в плане счетов +- **WHEN** seed завершён +- **THEN** в `chart_of_account` есть `01.01`, `66.01`, `76.01`, `76.ОТ`, `01.К` и `МЦ.04` (строки ОСВ с этими кодами получают + `account_id`); `60.АВ` в плане 1С нет, `account_id` таких строк остаётся `NULL` + #### Scenario: Ссылка на несуществующий счёт - **WHEN** в файл правил добавлен счёт, которого нет в `chart_of_accounts.csv` - **THEN** seed падает до записи в БД с сообщением, какой счёт и в каком правиле не найден