Andrey Epifancev 6e5ab834ec spec(slice-4): OpenSpec change консолидации — версии, периметр, блокировка, привязка документов, сводная ОСВ, экспорт
Proposal, design (D-1…D-16, решения без обсуждения), tasks и дельты спек: новые capability consolidations-api и
consolidated-osv; изменения data-model (DBML v5.16, counterparty_match_kind), documents-api (привязка при
подтверждении), primary-files (consolidation_version_id, отвязка при автозамене), osv-result-mapping (match_kind,
NEEDS_CHECK → DATA_CORRECTION), directory-policy (редактируемость версии), audit-trail (события консолидации).
Решения владельца 06.10.2026: OQ-03 пробел, OQ-19 блокировка, статусы по событиям, явная привязка, экспорт одним листом.

Refs RSHB/arm-core#18

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012vJkmBGKKqMoEMzvsXG3y2
2026-10-06 02:52:23 +04:00

4.0 KiB
Raw Blame History

Spec Delta: data-model

RENAMED Requirements

  • FROM: ### Requirement: Схема БД равна DBML v5.15
  • TO: ### Requirement: Схема БД равна DBML v5.16

MODIFIED Requirements

Requirement: Схема БД равна DBML v5.16

ORM-метаданные SHALL содержать ровно 43 таблицы и 28 enum'ов из ../docs/model/data-model-v5.16.dbml в схеме dkb; имена таблиц, колонок, enum'ов и их значений SHALL совпадать с DBML буквально; nullability, PK, UNIQUE, FK, значения по умолчанию и индексы SHALL соответствовать DBML, включая частичные уникальные индексы (related_group_member (related_group_id, legal_entity_id) и (legal_entity_id, kind) WHERE is_current, consolidation_lock WHERE released_at IS NULL) и NULLS NOT DISTINCT на document (stored_file_id, document_type, osv_account_code). related_group_member.kind SHALL быть NOT NULL и равняться related_group.kind группы (проверяет ядро при вставке). audit_action SHALL содержать LEGAL_ENTITY_CHANGE и USER_CHANGE; osv_data_type SHALL содержать NU (после BU). Enum counterparty_match_kind SHALL содержать INN, NAME, ALIAS, MANUAL, PROPAGATED; колонка osv_entry.counterparty_match_kind (nullable) SHALL быть NULL тогда и только тогда, когда counterparty_id NULL (проверяет ядро при записи). app_user.email SHALL храниться в нижнем регистре. Миграция 0004_dbml_v5_16 SHALL создавать enum и колонку и заполнять её по уже смапленным строкам (ИНН строки без пробелов = legal_entity.inn → INN; trim(counterparty_name) = legal_entity.name → NAME; остальные с counterparty_id → ALIAS); откат SHALL удалять колонку и enum. Поля, отсутствующие в DBML, MUST NOT существовать.

Scenario: Сверка ORM с DBML

  • WHEN выполняется python scripts/check_dbml_vs_orm.py ../../docs/model/data-model-v5.16.dbml
  • THEN вывод пуст и код возврата 0

Scenario: Лишняя колонка в ORM

  • WHEN в ORM добавлена колонка, которой нет в DBML (или удалена существующая)
  • THEN скрипт печатает таблица.колонка: отсутствует в DBML (или отсутствует в ORM) и возвращает код 1

Scenario: Расхождение типа или nullability

  • WHEN колонка osv_entry.opening_debit объявлена в ORM как Numeric(18, 4) или NOT NULL
  • THEN скрипт сообщает ожидалось numeric(18,2) NULL / фактически numeric(18,4) NOT NULL и возвращает код 1

Scenario: ЮЛ одновременно в ГСК и ГСЗ

  • WHEN для одного legal_entity_id вставлены две текущие строки related_group_member с kind = gsk и kind = gsz
  • THEN обе вставки проходят; третья текущая строка с kind = gsk нарушает уникальный индекс

Scenario: Строка налогового учёта

  • WHEN в osv_entry вставляется строка с data_type = 'NU'
  • THEN вставка проходит

Scenario: Backfill при миграции

  • WHEN до миграции 0004 есть строки с counterparty_id, найденным по ИНН, по имени и по алиасу, и строка без counterparty_id
  • THEN после alembic upgrade head у них counterparty_match_kind = INN, NAME, ALIAS и NULL соответственно; alembic downgrade 0003 удаляет колонку и enum