Initial SFERA platform baseline
This commit is contained in:
@@ -0,0 +1,11 @@
|
||||
# sfera-one-c-normalizer
|
||||
|
||||
Нормализация исходников и метаданных 1С для SFERA.
|
||||
|
||||
Текущий пакет содержит:
|
||||
|
||||
- нормализацию BSL-файлов;
|
||||
- первичный парсер XML-выгрузок метаданных;
|
||||
- каталог типов метаданных 1С для построения дерева SFERA IDE.
|
||||
|
||||
Опорная модель дерева описана в `docs/1c-metadata-structure.md`.
|
||||
@@ -0,0 +1,10 @@
|
||||
[project]
|
||||
name = "sfera-one-c-normalizer"
|
||||
version = "0.1.0"
|
||||
requires-python = ">=3.12"
|
||||
dependencies = [
|
||||
"pydantic>=2.0",
|
||||
]
|
||||
|
||||
[tool.uv]
|
||||
package = true
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,415 @@
|
||||
from __future__ import annotations
|
||||
|
||||
from dataclasses import dataclass
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class MetadataTypeSpec:
|
||||
code: str
|
||||
russian_name: str
|
||||
tree_branch: str
|
||||
icon: str
|
||||
child_groups: tuple[str, ...] = ()
|
||||
module_kinds: tuple[str, ...] = ()
|
||||
properties: tuple[str, ...] = ()
|
||||
context_actions: tuple[str, ...] = ()
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class MetadataChildObjectSpec:
|
||||
code: str
|
||||
russian_name: str
|
||||
parent_groups: tuple[str, ...]
|
||||
description: str
|
||||
documentation_url: str = "https://edt.1c.ru/dev/edt/2024.2/apidocs/com/_1c/g5/v8/dt/metadata/mdclass/package-summary.html"
|
||||
|
||||
|
||||
COMMON_BRANCH_CHILDREN = (
|
||||
"Подсистемы",
|
||||
"Общие модули",
|
||||
"Параметры сеанса",
|
||||
"Роли",
|
||||
"Общие реквизиты",
|
||||
"Планы обмена",
|
||||
"Подписки на события",
|
||||
"Критерии отбора",
|
||||
"Регламентные задания",
|
||||
"Функциональные опции",
|
||||
"Параметры функциональных опций",
|
||||
"Определяемые типы",
|
||||
"Хранилища настроек",
|
||||
"Общие команды",
|
||||
"Группы команд",
|
||||
"Общие формы",
|
||||
"Общие макеты",
|
||||
"Общие картинки",
|
||||
"XDTO-пакеты",
|
||||
"Web-сервисы",
|
||||
"HTTP-сервисы",
|
||||
"WS-ссылки",
|
||||
"WebSocket-клиенты",
|
||||
"Сервисы интеграции",
|
||||
"Боты",
|
||||
"Интерфейсы",
|
||||
"Словари полнотекстового поиска",
|
||||
"Цвета палитры",
|
||||
"Элементы стиля",
|
||||
"Стили",
|
||||
"Языки",
|
||||
)
|
||||
|
||||
OBJECT_MODULES = ("Модуль объекта", "Модуль менеджера")
|
||||
RECORD_SET_MODULES = ("Модуль набора записей", "Модуль менеджера")
|
||||
MANAGER_MODULE = ("Модуль менеджера",)
|
||||
HANDLER_METHOD = ("Обработчик",)
|
||||
STANDARD_PROPERTIES = (
|
||||
"Имя",
|
||||
"Синоним",
|
||||
"Комментарий",
|
||||
"Подсистемы",
|
||||
"Функциональные опции",
|
||||
)
|
||||
DATA_OBJECT_PROPERTIES = STANDARD_PROPERTIES + (
|
||||
"Основная форма",
|
||||
"Форма списка",
|
||||
"Форма выбора",
|
||||
"Представление объекта",
|
||||
"Представление списка",
|
||||
)
|
||||
REFERENCE_OBJECT_PROPERTIES = DATA_OBJECT_PROPERTIES + (
|
||||
"Иерархический",
|
||||
"Владельцы",
|
||||
"Длина кода",
|
||||
"Длина наименования",
|
||||
"Уникальность кода",
|
||||
)
|
||||
DOCUMENT_PROPERTIES = DATA_OBJECT_PROPERTIES + (
|
||||
"Нумерация",
|
||||
"Проведение",
|
||||
"Оперативное проведение",
|
||||
"Запись движений",
|
||||
"Журналирование",
|
||||
)
|
||||
REGISTER_PROPERTIES = STANDARD_PROPERTIES + (
|
||||
"Периодичность",
|
||||
"Режим записи",
|
||||
"Основной отбор",
|
||||
"Итоги",
|
||||
)
|
||||
MODULE_CONTEXT_ACTIONS = (
|
||||
"Открыть модуль",
|
||||
"Открыть менеджер",
|
||||
"Найти вызовы",
|
||||
"Найти использование",
|
||||
"Показать влияние",
|
||||
)
|
||||
OBJECT_CONTEXT_ACTIONS = (
|
||||
"Открыть объект",
|
||||
"Открыть модуль объекта",
|
||||
"Открыть модуль менеджера",
|
||||
"Показать связи",
|
||||
"Найти ссылки",
|
||||
"Показать права",
|
||||
)
|
||||
RECORD_SET_CONTEXT_ACTIONS = (
|
||||
"Открыть набор записей",
|
||||
"Открыть модуль набора записей",
|
||||
"Открыть модуль менеджера",
|
||||
"Показать чтение/запись",
|
||||
"Найти ссылки",
|
||||
)
|
||||
STRUCTURED_OBJECT_CHILDREN = (
|
||||
"Реквизиты",
|
||||
"Табличные части",
|
||||
"Формы",
|
||||
"Команды",
|
||||
"Макеты",
|
||||
"Права",
|
||||
)
|
||||
REGISTER_CHILDREN = ("Измерения", "Ресурсы", "Реквизиты", "Формы", "Команды", "Макеты", "Права")
|
||||
REPORT_CHILDREN = (
|
||||
"Реквизиты",
|
||||
"Табличные части",
|
||||
"Формы",
|
||||
"Команды",
|
||||
"Макеты",
|
||||
"Табличные документы",
|
||||
"СКД",
|
||||
"Варианты отчета",
|
||||
"Настройки",
|
||||
"Хранилище вариантов",
|
||||
"Хранилище настроек",
|
||||
"Справка",
|
||||
"Права",
|
||||
)
|
||||
|
||||
METADATA_TYPE_SPECS: tuple[MetadataTypeSpec, ...] = (
|
||||
MetadataTypeSpec("COMMON", "Общие", "Общие", "common", COMMON_BRANCH_CHILDREN),
|
||||
MetadataTypeSpec(
|
||||
"COMMON_MODULE",
|
||||
"Общий модуль",
|
||||
"Общие модули",
|
||||
"module",
|
||||
("Процедуры", "Функции", "Экспортные методы", "Вызовы", "Кто вызывает", "Запросы", "Записи", "Проверки", "Версии", "Знания"),
|
||||
("Модуль",),
|
||||
),
|
||||
MetadataTypeSpec("CONSTANT", "Константа", "Константы", "constant", ("Формы", "Команды", "Права"), MANAGER_MODULE),
|
||||
MetadataTypeSpec(
|
||||
"CATALOG",
|
||||
"Справочник",
|
||||
"Справочники",
|
||||
"catalog",
|
||||
STRUCTURED_OBJECT_CHILDREN + ("Предопределенные данные",),
|
||||
OBJECT_MODULES,
|
||||
),
|
||||
MetadataTypeSpec(
|
||||
"DOCUMENT",
|
||||
"Документ",
|
||||
"Документы",
|
||||
"document",
|
||||
STRUCTURED_OBJECT_CHILDREN + ("Движения", "Последовательности", "Нумераторы"),
|
||||
OBJECT_MODULES,
|
||||
),
|
||||
MetadataTypeSpec("DOCUMENT_JOURNAL", "Журнал документов", "Журналы документов", "journal", ("Графы", "Формы", "Команды", "Макеты", "Права"), ("Модуль менеджера",)),
|
||||
MetadataTypeSpec("ENUM", "Перечисление", "Перечисления", "enum", ("Значения", "Формы", "Команды", "Макеты", "Права"), ("Модуль менеджера",)),
|
||||
MetadataTypeSpec("REPORT", "Отчет", "Отчеты", "report", REPORT_CHILDREN, OBJECT_MODULES),
|
||||
MetadataTypeSpec("DATA_PROCESSOR", "Обработка", "Обработки", "processing", STRUCTURED_OBJECT_CHILDREN, OBJECT_MODULES),
|
||||
MetadataTypeSpec("CHART_OF_CHARACTERISTIC_TYPES", "План видов характеристик", "Планы видов характеристик", "plan", STRUCTURED_OBJECT_CHILDREN + ("Предопределенные данные",), OBJECT_MODULES),
|
||||
MetadataTypeSpec("CHART_OF_ACCOUNTS", "План счетов", "Планы счетов", "plan", ("Признаки учета", "Признаки учета субконто", "Реквизиты", "Табличные части", "Формы", "Команды", "Макеты", "Права", "Предопределенные данные"), OBJECT_MODULES),
|
||||
MetadataTypeSpec("CHART_OF_CALCULATION_TYPES", "План видов расчета", "Планы видов расчета", "plan", STRUCTURED_OBJECT_CHILDREN + ("Вытесняющие виды расчета", "Ведущие виды расчета", "Базовые виды расчета"), OBJECT_MODULES),
|
||||
MetadataTypeSpec("INFORMATION_REGISTER", "Регистр сведений", "Регистры сведений", "register", REGISTER_CHILDREN, RECORD_SET_MODULES),
|
||||
MetadataTypeSpec("ACCUMULATION_REGISTER", "Регистр накопления", "Регистры накопления", "register", REGISTER_CHILDREN, RECORD_SET_MODULES),
|
||||
MetadataTypeSpec("ACCOUNTING_REGISTER", "Регистр бухгалтерии", "Регистры бухгалтерии", "register", REGISTER_CHILDREN + ("Признаки учета", "Признаки учета субконто",), RECORD_SET_MODULES),
|
||||
MetadataTypeSpec("CALCULATION_REGISTER", "Регистр расчета", "Регистры расчета", "register", REGISTER_CHILDREN + ("Перерасчеты",), RECORD_SET_MODULES),
|
||||
MetadataTypeSpec("BUSINESS_PROCESS", "Бизнес-процесс", "Бизнес-процессы", "business-process", STRUCTURED_OBJECT_CHILDREN + ("Карта маршрута", "Точки маршрута"), OBJECT_MODULES),
|
||||
MetadataTypeSpec("TASK", "Задача 1С", "Задачи", "task", STRUCTURED_OBJECT_CHILDREN + ("Адресация",), OBJECT_MODULES),
|
||||
MetadataTypeSpec("EXTERNAL_DATA_SOURCE", "Внешний источник данных", "Внешние источники данных", "external-source", ("Таблицы", "Кубы", "Функции", "Формы", "Команды", "Макеты")),
|
||||
MetadataTypeSpec("EXCHANGE_PLAN", "План обмена", "Планы обмена", "exchange-plan", STRUCTURED_OBJECT_CHILDREN + ("Состав",), OBJECT_MODULES),
|
||||
MetadataTypeSpec("EVENT_SUBSCRIPTION", "Подписка на событие", "Подписки на события", "event", ("События",), HANDLER_METHOD),
|
||||
MetadataTypeSpec("EXTENSION", "Расширение конфигурации", "Расширения конфигурации", "extension", ("Объекты расширения", "Заимствованные объекты", "Добавленные реквизиты", "Формы", "Команды", "Проверки совместимости")),
|
||||
MetadataTypeSpec("SCHEDULED_JOB", "Регламентное задание", "Регламентные задания", "scheduled-job", ("Расписание", "Параметры"), ("Метод",)),
|
||||
MetadataTypeSpec("SESSION_PARAMETER", "Параметр сеанса", "Параметры сеанса", "parameter"),
|
||||
MetadataTypeSpec("COMMON_ATTRIBUTE", "Общий реквизит", "Общие реквизиты", "attribute"),
|
||||
MetadataTypeSpec("FILTER_CRITERION", "Критерий отбора", "Критерии отбора", "filter"),
|
||||
MetadataTypeSpec("FUNCTIONAL_OPTION", "Функциональная опция", "Функциональные опции", "option"),
|
||||
MetadataTypeSpec("FUNCTIONAL_OPTION_PARAMETER", "Параметр функциональной опции", "Параметры функциональных опций", "parameter"),
|
||||
MetadataTypeSpec("DEFINED_TYPE", "Определяемый тип", "Определяемые типы", "type"),
|
||||
MetadataTypeSpec("SETTINGS_STORAGE", "Хранилище настроек", "Хранилища настроек", "storage"),
|
||||
MetadataTypeSpec("COMMON_COMMAND", "Общая команда", "Общие команды", "command"),
|
||||
MetadataTypeSpec("COMMAND_GROUP", "Группа команд", "Группы команд", "command-group"),
|
||||
MetadataTypeSpec("COMMON_FORM", "Общая форма", "Общие формы", "form", ("Реквизиты", "Элементы", "Команды", "События", "Модуль формы")),
|
||||
MetadataTypeSpec("COMMON_LAYOUT", "Общий макет", "Общие макеты", "layout"),
|
||||
MetadataTypeSpec("COMMON_PICTURE", "Общая картинка", "Общие картинки", "picture"),
|
||||
MetadataTypeSpec("XDTO_PACKAGE", "XDTO-пакет", "XDTO-пакеты", "xdto"),
|
||||
MetadataTypeSpec("WEB_SERVICE", "Web-сервис", "Web-сервисы", "service", ("Операции", "Параметры", "Модуль")),
|
||||
MetadataTypeSpec("HTTP_SERVICE", "HTTP-сервис", "HTTP-сервисы", "service", ("Шаблоны URL", "Методы", "Модуль")),
|
||||
MetadataTypeSpec("WS_REFERENCE", "WS-ссылка", "WS-ссылки", "service", ("Операции", "Параметры")),
|
||||
MetadataTypeSpec("WEBSOCKET_CLIENT", "WebSocket-клиент", "WebSocket-клиенты", "service", ("Модуль",)),
|
||||
MetadataTypeSpec("INTEGRATION_SERVICE", "Сервис интеграции", "Сервисы интеграции", "service", ("Каналы", "Сообщения", "Модуль")),
|
||||
MetadataTypeSpec("BOT", "Бот", "Боты", "service", ("Команды", "Модуль")),
|
||||
MetadataTypeSpec("INTERFACE", "Интерфейс", "Интерфейсы", "interface"),
|
||||
MetadataTypeSpec("FULL_TEXT_SEARCH_DICTIONARY", "Словарь полнотекстового поиска", "Словари полнотекстового поиска", "search"),
|
||||
MetadataTypeSpec("PALETTE_COLOR", "Цвет палитры", "Цвета палитры", "style"),
|
||||
MetadataTypeSpec("STYLE_ITEM", "Элемент стиля", "Элементы стиля", "style"),
|
||||
MetadataTypeSpec("STYLE", "Стиль", "Стили", "style"),
|
||||
MetadataTypeSpec("LANGUAGE", "Язык", "Языки", "language"),
|
||||
)
|
||||
|
||||
METADATA_TYPE_DESCRIPTIONS = {
|
||||
"COMMON": "Служебная ветка дерева конфигурации, объединяющая общие объекты метаданных.",
|
||||
"COMMON_MODULE": "Общий модуль содержит процедуры и функции, доступные из разных областей выполнения конфигурации.",
|
||||
"CONSTANT": "Константа хранит единичное значение конфигурации и может иметь формы, команды, права и модуль менеджера.",
|
||||
"CATALOG": "Справочник описывает прикладной список объектов с реквизитами, табличными частями, формами, командами, макетами, правами и предопределенными данными.",
|
||||
"DOCUMENT": "Документ фиксирует событие учета, имеет реквизиты, табличные части, формы, команды, макеты, права и движения по регистрам.",
|
||||
"DOCUMENT_JOURNAL": "Журнал документов объединяет документы для совместного просмотра и может содержать графы, формы, команды, макеты и права.",
|
||||
"ENUM": "Перечисление задает фиксированный набор значений, используемых в типах реквизитов и логике.",
|
||||
"REPORT": "Отчет описывает формирование аналитических данных: реквизиты, табличные части, формы, команды, макеты и табличные документы, СКД, варианты, настройки, хранилища, справку, права и модули.",
|
||||
"DATA_PROCESSOR": "Обработка реализует прикладный сценарий или сервисную операцию с формами, командами, макетами и модулями.",
|
||||
"CHART_OF_CHARACTERISTIC_TYPES": "План видов характеристик описывает расширяемый набор характеристик объектов учета.",
|
||||
"CHART_OF_ACCOUNTS": "План счетов описывает счета бухгалтерского учета, признаки учета, реквизиты, табличные части и предопределенные данные.",
|
||||
"CHART_OF_CALCULATION_TYPES": "План видов расчета описывает виды расчетов, их вытеснение, ведущие и базовые виды.",
|
||||
"INFORMATION_REGISTER": "Регистр сведений хранит независимые или подчиненные записи с измерениями, ресурсами и реквизитами.",
|
||||
"ACCUMULATION_REGISTER": "Регистр накопления хранит движения ресурсов по измерениям для остатков и оборотов.",
|
||||
"ACCOUNTING_REGISTER": "Регистр бухгалтерии хранит бухгалтерские движения по счетам и субконто.",
|
||||
"CALCULATION_REGISTER": "Регистр расчета хранит записи расчетов, перерасчеты, измерения, ресурсы и реквизиты.",
|
||||
"BUSINESS_PROCESS": "Бизнес-процесс описывает маршрут выполнения, точки маршрута, реквизиты, формы, команды и права.",
|
||||
"TASK": "Задача описывает поручение пользователю или роли, включая адресацию, формы, команды и права.",
|
||||
"EXTERNAL_DATA_SOURCE": "Внешний источник данных описывает подключение к внешним таблицам, кубам и функциям.",
|
||||
"EXCHANGE_PLAN": "План обмена описывает узлы и состав данных для распределенного обмена.",
|
||||
"EVENT_SUBSCRIPTION": "Подписка на событие связывает событие платформы или объекта с обработчиком.",
|
||||
"EXTENSION": "Расширение конфигурации содержит добавленные и заимствованные объекты, а также проверки совместимости.",
|
||||
"SCHEDULED_JOB": "Регламентное задание описывает метод, параметры и расписание фонового выполнения.",
|
||||
"SESSION_PARAMETER": "Параметр сеанса задает значение, доступное в течение пользовательского сеанса.",
|
||||
"COMMON_ATTRIBUTE": "Общий реквизит добавляет реквизит сразу к выбранному набору объектов конфигурации.",
|
||||
"FILTER_CRITERION": "Критерий отбора задает состав реквизитов для универсального отбора ссылочных данных.",
|
||||
"FUNCTIONAL_OPTION": "Функциональная опция управляет доступностью функциональности конфигурации.",
|
||||
"FUNCTIONAL_OPTION_PARAMETER": "Параметр функциональной опции задает измерение, от которого зависит значение опции.",
|
||||
"DEFINED_TYPE": "Определяемый тип задает именованный набор типов для повторного использования.",
|
||||
"SETTINGS_STORAGE": "Хранилище настроек описывает место хранения пользовательских или системных настроек.",
|
||||
"COMMON_COMMAND": "Общая команда описывает команду, доступную в нескольких формах или разделах интерфейса.",
|
||||
"COMMAND_GROUP": "Группа команд объединяет команды для отображения в интерфейсе.",
|
||||
"COMMON_FORM": "Общая форма описывает переиспользуемую форму с реквизитами, элементами, командами, событиями и модулем.",
|
||||
"COMMON_LAYOUT": "Общий макет хранит общий шаблон, печатную форму, текстовый или двоичный ресурс.",
|
||||
"COMMON_PICTURE": "Общая картинка хранит изображение, используемое в интерфейсе и макетах.",
|
||||
"XDTO_PACKAGE": "XDTO-пакет описывает XML-типы и пространства имен для обмена данными.",
|
||||
"WEB_SERVICE": "Web-сервис публикует SOAP-операции, параметры и обработчики в модуле.",
|
||||
"HTTP_SERVICE": "HTTP-сервис публикует REST-подобные URL-шаблоны и HTTP-методы с обработчиками в модуле.",
|
||||
"WS_REFERENCE": "WS-ссылка описывает внешний SOAP-сервис и его операции.",
|
||||
"WEBSOCKET_CLIENT": "WebSocket-клиент описывает клиентское подключение и модуль обработки WebSocket-событий.",
|
||||
"INTEGRATION_SERVICE": "Сервис интеграции описывает каналы, сообщения и код обработки интеграционного взаимодействия.",
|
||||
"BOT": "Бот описывает команды и обработчики взаимодействия через поддерживаемые платформой каналы.",
|
||||
"INTERFACE": "Интерфейс описывает устаревшую структуру командного интерфейса для совместимости.",
|
||||
"FULL_TEXT_SEARCH_DICTIONARY": "Словарь полнотекстового поиска задает словарные данные для полнотекстового поиска.",
|
||||
"PALETTE_COLOR": "Цвет палитры описывает общий цвет, используемый стилями и интерфейсом.",
|
||||
"STYLE_ITEM": "Элемент стиля описывает отдельный параметр оформления.",
|
||||
"STYLE": "Стиль объединяет элементы оформления прикладного интерфейса.",
|
||||
"LANGUAGE": "Язык описывает язык интерфейса и локализованных представлений конфигурации.",
|
||||
}
|
||||
|
||||
METADATA_TYPE_DOCUMENTATION_URLS = {
|
||||
code: f"https://edt.1c.ru/dev/edt/2024.2/apidocs/com/_1c/g5/v8/dt/metadata/mdclass/{code.title().replace('_', '')}.html"
|
||||
for code in METADATA_TYPE_DESCRIPTIONS
|
||||
}
|
||||
METADATA_TYPE_DOCUMENTATION_URLS.update(
|
||||
{
|
||||
"HTTP_SERVICE": "https://edt.1c.ru/dev/edt/2024.2/apidocs/com/_1c/g5/v8/dt/metadata/mdclass/HTTPService.html",
|
||||
"WEB_SERVICE": "https://edt.1c.ru/dev/edt/2024.2/apidocs/com/_1c/g5/v8/dt/metadata/mdclass/WebService.html",
|
||||
"INTEGRATION_SERVICE": "https://edt.1c.ru/dev/edt/2024.2/apidocs/com/_1c/g5/v8/dt/metadata/mdclass/IntegrationService.html",
|
||||
"COMMON_LAYOUT": "https://edt.1c.ru/dev/edt/2024.2/apidocs/com/_1c/g5/v8/dt/metadata/mdclass/CommonTemplate.html",
|
||||
"REPORT": "https://edt.1c.ru/dev/edt/2024.2/apidocs/com/_1c/g5/v8/dt/metadata/mdclass/Report.html",
|
||||
}
|
||||
)
|
||||
|
||||
METADATA_TYPE_PROPERTIES: dict[str, tuple[str, ...]] = {
|
||||
"COMMON": ("Состав общих объектов",),
|
||||
"COMMON_MODULE": STANDARD_PROPERTIES + ("Клиент", "Сервер", "Внешнее соединение", "Глобальный", "Вызов сервера", "Повторное использование возвращаемых значений"),
|
||||
"CONSTANT": STANDARD_PROPERTIES + ("Тип значения", "Основная форма", "Форма выбора"),
|
||||
"CATALOG": REFERENCE_OBJECT_PROPERTIES,
|
||||
"DOCUMENT": DOCUMENT_PROPERTIES,
|
||||
"DOCUMENT_JOURNAL": STANDARD_PROPERTIES + ("Регистрируемые документы", "Графы", "Основная форма", "Форма списка"),
|
||||
"ENUM": STANDARD_PROPERTIES + ("Значения", "Основная форма", "Форма выбора"),
|
||||
"REPORT": DATA_OBJECT_PROPERTIES + ("Основная схема компоновки данных", "Варианты", "Хранилище вариантов", "Хранилище настроек"),
|
||||
"DATA_PROCESSOR": DATA_OBJECT_PROPERTIES + ("Основная форма", "Основная команда"),
|
||||
"CHART_OF_CHARACTERISTIC_TYPES": REFERENCE_OBJECT_PROPERTIES + ("Тип значения характеристик",),
|
||||
"CHART_OF_ACCOUNTS": REFERENCE_OBJECT_PROPERTIES + ("Длина кода счета", "Признаки учета", "Субконто"),
|
||||
"CHART_OF_CALCULATION_TYPES": REFERENCE_OBJECT_PROPERTIES + ("Использует период действия", "Зависимость от базы", "Вытеснение"),
|
||||
"INFORMATION_REGISTER": REGISTER_PROPERTIES + ("Периодический", "Подчинение регистратору", "Измерения", "Ресурсы"),
|
||||
"ACCUMULATION_REGISTER": REGISTER_PROPERTIES + ("Вид регистра", "Измерения", "Ресурсы", "Использование итогов"),
|
||||
"ACCOUNTING_REGISTER": REGISTER_PROPERTIES + ("План счетов", "Корреспонденция", "Субконто", "Разделение итогов"),
|
||||
"CALCULATION_REGISTER": REGISTER_PROPERTIES + ("План видов расчета", "График", "Перерасчеты", "Базовый период"),
|
||||
"BUSINESS_PROCESS": DATA_OBJECT_PROPERTIES + ("Карта маршрута", "Точки маршрута", "Задачи"),
|
||||
"TASK": DATA_OBJECT_PROPERTIES + ("Адресация", "Исполнитель", "Бизнес-процесс"),
|
||||
"EXTERNAL_DATA_SOURCE": STANDARD_PROPERTIES + ("Соединение", "Таблицы", "Кубы", "Функции"),
|
||||
"EXCHANGE_PLAN": DATA_OBJECT_PROPERTIES + ("Состав обмена", "Распределенная ИБ", "Авторегистрация изменений"),
|
||||
"EVENT_SUBSCRIPTION": STANDARD_PROPERTIES + ("Источник", "Событие", "Обработчик", "Перед/после события"),
|
||||
"EXTENSION": ("Имя", "Назначение", "Версия", "Режим совместимости", "Заимствованные объекты", "Проверки совместимости"),
|
||||
"SCHEDULED_JOB": STANDARD_PROPERTIES + ("Метод", "Расписание", "Использование", "Параметры", "Предопределенное"),
|
||||
"SESSION_PARAMETER": STANDARD_PROPERTIES + ("Тип значения",),
|
||||
"COMMON_ATTRIBUTE": STANDARD_PROPERTIES + ("Тип значения", "Состав", "Разделение данных", "Автоиспользование"),
|
||||
"FILTER_CRITERION": STANDARD_PROPERTIES + ("Тип значения", "Состав реквизитов"),
|
||||
"FUNCTIONAL_OPTION": STANDARD_PROPERTIES + ("Тип значения", "Хранение", "Состав объектов"),
|
||||
"FUNCTIONAL_OPTION_PARAMETER": STANDARD_PROPERTIES + ("Тип значения", "Состав"),
|
||||
"DEFINED_TYPE": STANDARD_PROPERTIES + ("Типы",),
|
||||
"SETTINGS_STORAGE": STANDARD_PROPERTIES + ("Тип хранилища", "Модуль менеджера"),
|
||||
"COMMON_COMMAND": STANDARD_PROPERTIES + ("Тип параметра команды", "Группа", "Представление", "Модуль команды"),
|
||||
"COMMAND_GROUP": STANDARD_PROPERTIES + ("Категория", "Представление"),
|
||||
"COMMON_FORM": STANDARD_PROPERTIES + ("Реквизиты", "Команды", "Элементы", "События", "Модуль формы"),
|
||||
"COMMON_LAYOUT": STANDARD_PROPERTIES + ("Тип макета", "Файл/данные", "Назначение"),
|
||||
"COMMON_PICTURE": STANDARD_PROPERTIES + ("Картинка", "Варианты", "Масштабирование"),
|
||||
"XDTO_PACKAGE": STANDARD_PROPERTIES + ("URI пространства имен", "Типы", "Схемы"),
|
||||
"WEB_SERVICE": STANDARD_PROPERTIES + ("URI пространства имен", "Операции", "Параметры", "Модуль"),
|
||||
"HTTP_SERVICE": STANDARD_PROPERTIES + ("Корневой URL", "Шаблоны URL", "HTTP-методы", "Модуль"),
|
||||
"WS_REFERENCE": STANDARD_PROPERTIES + ("WSDL", "Операции", "Параметры"),
|
||||
"WEBSOCKET_CLIENT": STANDARD_PROPERTIES + ("URL", "Модуль", "События подключения"),
|
||||
"INTEGRATION_SERVICE": STANDARD_PROPERTIES + ("Каналы", "Сообщения", "Форматы", "Модуль"),
|
||||
"BOT": STANDARD_PROPERTIES + ("Команды", "Каналы", "Модуль"),
|
||||
"INTERFACE": STANDARD_PROPERTIES + ("Командный интерфейс",),
|
||||
"FULL_TEXT_SEARCH_DICTIONARY": STANDARD_PROPERTIES + ("Состав словаря",),
|
||||
"PALETTE_COLOR": STANDARD_PROPERTIES + ("Цвет",),
|
||||
"STYLE_ITEM": STANDARD_PROPERTIES + ("Значение стиля",),
|
||||
"STYLE": STANDARD_PROPERTIES + ("Элементы стиля",),
|
||||
"LANGUAGE": STANDARD_PROPERTIES + ("Код языка", "Локализованные строки"),
|
||||
}
|
||||
|
||||
METADATA_TYPE_CONTEXT_ACTIONS: dict[str, tuple[str, ...]] = {
|
||||
code: ("Открыть", "Показать свойства", "Показать связи", "Найти ссылки")
|
||||
for code in METADATA_TYPE_DESCRIPTIONS
|
||||
}
|
||||
for code in {
|
||||
"CATALOG",
|
||||
"DOCUMENT",
|
||||
"REPORT",
|
||||
"DATA_PROCESSOR",
|
||||
"CHART_OF_CHARACTERISTIC_TYPES",
|
||||
"CHART_OF_ACCOUNTS",
|
||||
"CHART_OF_CALCULATION_TYPES",
|
||||
"BUSINESS_PROCESS",
|
||||
"TASK",
|
||||
"EXCHANGE_PLAN",
|
||||
}:
|
||||
METADATA_TYPE_CONTEXT_ACTIONS[code] = OBJECT_CONTEXT_ACTIONS
|
||||
for code in {"INFORMATION_REGISTER", "ACCUMULATION_REGISTER", "ACCOUNTING_REGISTER", "CALCULATION_REGISTER"}:
|
||||
METADATA_TYPE_CONTEXT_ACTIONS[code] = RECORD_SET_CONTEXT_ACTIONS
|
||||
METADATA_TYPE_CONTEXT_ACTIONS.update(
|
||||
{
|
||||
"COMMON_MODULE": MODULE_CONTEXT_ACTIONS,
|
||||
"COMMON_FORM": ("Открыть форму", "Открыть модуль формы", "Показать команды", "Показать реквизиты", "Найти ссылки"),
|
||||
"COMMON_COMMAND": ("Открыть команду", "Открыть модуль команды", "Показать использование", "Найти ссылки"),
|
||||
"HTTP_SERVICE": ("Открыть сервис", "Открыть модуль", "Показать URL-шаблоны", "Показать методы", "Показать интеграции"),
|
||||
"WEB_SERVICE": ("Открыть сервис", "Открыть модуль", "Показать операции", "Показать параметры", "Показать интеграции"),
|
||||
"SCHEDULED_JOB": ("Открыть задание", "Открыть метод", "Показать расписание", "Показать влияние"),
|
||||
"EVENT_SUBSCRIPTION": ("Открыть подписку", "Открыть обработчик", "Показать источник события", "Показать влияние"),
|
||||
"ROLE": ("Открыть роль", "Показать права", "Показать объекты доступа"),
|
||||
}
|
||||
)
|
||||
|
||||
METADATA_CHILD_OBJECT_SPECS: tuple[MetadataChildObjectSpec, ...] = (
|
||||
MetadataChildObjectSpec("ATTRIBUTE", "Реквизит", ("Реквизиты",), "Хранит дополнительное поле объекта метаданных."),
|
||||
MetadataChildObjectSpec("DIMENSION", "Измерение", ("Измерения",), "Задает аналитический разрез регистра."),
|
||||
MetadataChildObjectSpec("RESOURCE", "Ресурс", ("Ресурсы",), "Задает накапливаемое или хранимое значение регистра."),
|
||||
MetadataChildObjectSpec("TABULAR_SECTION", "Табличная часть", ("Табличные части",), "Описывает коллекцию строк внутри объекта."),
|
||||
MetadataChildObjectSpec("FORM", "Форма", ("Формы", "Общие формы"), "Описывает пользовательскую форму объекта или общую форму."),
|
||||
MetadataChildObjectSpec("COMMAND", "Команда", ("Команды", "Общие команды"), "Описывает действие интерфейса или объекта."),
|
||||
MetadataChildObjectSpec("LAYOUT", "Макет", ("Макеты", "Общие макеты"), "Описывает печатный, текстовый или двоичный шаблон."),
|
||||
MetadataChildObjectSpec("TABULAR_DOCUMENT", "Табличный документ", ("Табличные документы",), "Описывает табличный документ отчета или печатную форму."),
|
||||
MetadataChildObjectSpec("DATA_COMPOSITION_SCHEMA", "Схема компоновки данных", ("СКД",), "Описывает основную или дополнительную схему компоновки данных отчета."),
|
||||
MetadataChildObjectSpec("REPORT_VARIANT", "Вариант отчета", ("Варианты отчета",), "Описывает вариант настроек и представления отчета."),
|
||||
MetadataChildObjectSpec("REPORT_SETTING", "Настройка отчета", ("Настройки",), "Описывает настройки отчета, включая формы и параметры компоновки."),
|
||||
MetadataChildObjectSpec("REPORT_STORAGE", "Хранилище отчета", ("Хранилище вариантов", "Хранилище настроек"), "Описывает хранилище вариантов или настроек отчета."),
|
||||
MetadataChildObjectSpec("HELP", "Справка", ("Справка",), "Описывает справочную информацию объекта метаданных."),
|
||||
MetadataChildObjectSpec("MODULE", "Модуль", ("Модуль", "Модуль объекта", "Модуль менеджера", "Модуль формы", "Модуль набора записей", "Метод", "Обработчик"), "Содержит BSL-код обработчиков и прикладной логики."),
|
||||
MetadataChildObjectSpec("RIGHT", "Право", ("Права",), "Описывает доступ роли к объекту или действию."),
|
||||
MetadataChildObjectSpec("EVENT", "Событие", ("События",), "Описывает событие формы, объекта или подписки."),
|
||||
MetadataChildObjectSpec("MOVEMENT", "Движение", ("Движения",), "Описывает движение документа по регистру."),
|
||||
MetadataChildObjectSpec("ENUM_VALUE", "Значение перечисления", ("Значения",), "Описывает элемент фиксированного перечисления."),
|
||||
MetadataChildObjectSpec("PREDEFINED", "Предопределенные данные", ("Предопределенные данные",), "Описывает предопределенный элемент справочника, плана или другого объекта."),
|
||||
MetadataChildObjectSpec("URL_TEMPLATE", "Шаблон URL", ("Шаблоны URL",), "Описывает URL-шаблон HTTP-сервиса."),
|
||||
MetadataChildObjectSpec("METHOD", "Метод", ("Методы", "Метод", "Функции"), "Описывает HTTP-метод, функцию внешнего источника или исполняемый метод."),
|
||||
MetadataChildObjectSpec("OPERATION", "Операция", ("Операции",), "Описывает операцию Web-сервиса или WS-ссылки."),
|
||||
MetadataChildObjectSpec("PARAMETER", "Параметр", ("Параметры",), "Описывает параметр метода, операции или регламентного задания."),
|
||||
MetadataChildObjectSpec("CHANNEL", "Канал", ("Каналы",), "Описывает канал сервиса интеграции."),
|
||||
MetadataChildObjectSpec("MESSAGE", "Сообщение", ("Сообщения",), "Описывает сообщение сервиса интеграции."),
|
||||
MetadataChildObjectSpec("TABLE", "Таблица", ("Таблицы",), "Описывает таблицу внешнего источника данных."),
|
||||
MetadataChildObjectSpec("CUBE", "Куб", ("Кубы",), "Описывает куб внешнего источника данных."),
|
||||
MetadataChildObjectSpec("FIELD", "Поле", ("Графы", "Элементы", "Поля"), "Описывает графу журнала, поле таблицы или элемент формы."),
|
||||
)
|
||||
|
||||
METADATA_TYPE_BY_CODE = {spec.code: spec for spec in METADATA_TYPE_SPECS}
|
||||
METADATA_TYPE_BY_BRANCH = {spec.tree_branch: spec for spec in METADATA_TYPE_SPECS}
|
||||
METADATA_CHILD_OBJECT_BY_CODE = {spec.code: spec for spec in METADATA_CHILD_OBJECT_SPECS}
|
||||
|
||||
|
||||
__all__ = [
|
||||
"COMMON_BRANCH_CHILDREN",
|
||||
"METADATA_CHILD_OBJECT_BY_CODE",
|
||||
"METADATA_CHILD_OBJECT_SPECS",
|
||||
"METADATA_TYPE_BY_BRANCH",
|
||||
"METADATA_TYPE_BY_CODE",
|
||||
"METADATA_TYPE_DESCRIPTIONS",
|
||||
"METADATA_TYPE_DOCUMENTATION_URLS",
|
||||
"METADATA_TYPE_CONTEXT_ACTIONS",
|
||||
"METADATA_TYPE_PROPERTIES",
|
||||
"METADATA_TYPE_SPECS",
|
||||
"MetadataChildObjectSpec",
|
||||
"MetadataTypeSpec",
|
||||
]
|
||||
@@ -0,0 +1,658 @@
|
||||
from pathlib import Path
|
||||
|
||||
from one_c_normalizer import (
|
||||
COMMON_BRANCH_CHILDREN,
|
||||
METADATA_TYPE_BY_BRANCH,
|
||||
METADATA_TYPE_BY_CODE,
|
||||
build_normalized_project,
|
||||
normalize_bsl_source,
|
||||
normalize_one_c_project,
|
||||
normalize_source_path,
|
||||
parse_one_c_xml_file,
|
||||
)
|
||||
|
||||
|
||||
def test_normalize_bsl_source_removes_bom_and_normalizes_newlines():
|
||||
assert normalize_bsl_source("\ufeffПроцедура X()\r\n A = 1; \r\n\r\n") == (
|
||||
"Процедура X()\n A = 1;\n"
|
||||
)
|
||||
|
||||
|
||||
def test_normalize_source_path_uses_forward_slashes():
|
||||
assert normalize_source_path("src\\module.bsl") == "src/module.bsl"
|
||||
|
||||
|
||||
def test_parse_one_c_xml_file_extracts_ui_objects(tmp_path: Path):
|
||||
xml = tmp_path / "form.xml"
|
||||
xml.write_text(
|
||||
"""
|
||||
<Form name="ФормаДокумента" qualifiedName="Документ.Заказ.ФормаДокумента">
|
||||
<Command name="Провести" />
|
||||
<Attribute name="Контрагент" />
|
||||
</Form>
|
||||
""",
|
||||
encoding="utf-8",
|
||||
)
|
||||
|
||||
objects = parse_one_c_xml_file(xml)
|
||||
|
||||
assert [item.object_kind for item in objects] == ["FORM", "COMMAND", "ATTRIBUTE"]
|
||||
assert objects[0].qualified_name == "Документ.Заказ.ФормаДокумента"
|
||||
|
||||
|
||||
def test_parse_one_c_xml_file_extracts_metadata_objects(tmp_path: Path):
|
||||
xml = tmp_path / "metadata.xml"
|
||||
xml.write_text(
|
||||
"""
|
||||
<Configuration>
|
||||
<Catalog name="Номенклатура" qualifiedName="Справочник.Номенклатура">
|
||||
<Attribute name="Артикул" qualifiedName="Справочник.Номенклатура.Артикул" />
|
||||
</Catalog>
|
||||
<Document>
|
||||
<Name>ЗаказПокупателя</Name>
|
||||
<QualifiedName>Документ.ЗаказПокупателя</QualifiedName>
|
||||
<TabularSection name="Товары" qualifiedName="Документ.ЗаказПокупателя.Товары" />
|
||||
<Form name="ФормаДокумента" qualifiedName="Документ.ЗаказПокупателя.ФормаДокумента" />
|
||||
</Document>
|
||||
<MetadataObject type="AccumulationRegister">
|
||||
<Name>ОстаткиТоваров</Name>
|
||||
<QualifiedName>РегистрНакопления.ОстаткиТоваров</QualifiedName>
|
||||
</MetadataObject>
|
||||
</Configuration>
|
||||
""",
|
||||
encoding="utf-8",
|
||||
)
|
||||
|
||||
objects = parse_one_c_xml_file(xml)
|
||||
|
||||
assert [item.object_kind for item in objects] == [
|
||||
"CATALOG",
|
||||
"ATTRIBUTE",
|
||||
"DOCUMENT",
|
||||
"TABULAR_SECTION",
|
||||
"FORM",
|
||||
"ACCUMULATION_REGISTER",
|
||||
]
|
||||
assert objects[2].qualified_name == "Документ.ЗаказПокупателя"
|
||||
assert objects[5].name == "ОстаткиТоваров"
|
||||
|
||||
|
||||
def test_normalize_one_c_project_preserves_configuration_root_metadata(tmp_path: Path):
|
||||
xml = tmp_path / "configuration.xml"
|
||||
xml.write_text(
|
||||
"""
|
||||
<Configuration name="УправлениеТорговлей" synonym="Управление торговлей" platformVersion="8.3.24" compatibilityMode="8.3.20">
|
||||
<Catalog name="Контрагенты" qualifiedName="Справочник.Контрагенты" />
|
||||
</Configuration>
|
||||
""",
|
||||
encoding="utf-8",
|
||||
)
|
||||
|
||||
normalized = normalize_one_c_project(tmp_path, project_id="configuration-root")
|
||||
|
||||
assert normalized.configuration.name == "УправлениеТорговлей"
|
||||
assert normalized.configuration.metadata["synonym"] == "Управление торговлей"
|
||||
assert normalized.configuration.metadata["platformVersion"] == "8.3.24"
|
||||
assert normalized.configuration.metadata["compatibilityMode"] == "8.3.20"
|
||||
assert normalized.configuration.metadata["source_path"].endswith("configuration.xml")
|
||||
assert [group.name for group in normalized.configuration.groups] == ["Справочники"]
|
||||
|
||||
|
||||
def test_parse_edt_mdo_derives_qualified_names(tmp_path: Path):
|
||||
mdo = tmp_path / "Товары.mdo"
|
||||
mdo.write_text(
|
||||
"""
|
||||
<mdclass:Catalog xmlns:mdclass="http://g5.1c.ru/v8/dt/metadata/mdclass">
|
||||
<name>Товары</name>
|
||||
<attributes>
|
||||
<name>Артикул</name>
|
||||
</attributes>
|
||||
<tabularSections>
|
||||
<name>Цены</name>
|
||||
<attributes>
|
||||
<name>ВидЦены</name>
|
||||
</attributes>
|
||||
</tabularSections>
|
||||
<forms>
|
||||
<name>ФормаЭлемента</name>
|
||||
</forms>
|
||||
</mdclass:Catalog>
|
||||
""",
|
||||
encoding="utf-8",
|
||||
)
|
||||
|
||||
objects = parse_one_c_xml_file(mdo)
|
||||
by_name = {item.name: item for item in objects}
|
||||
|
||||
assert by_name["Товары"].qualified_name == "Справочник.Товары"
|
||||
assert by_name["Артикул"].qualified_name == "Справочник.Товары.Артикул"
|
||||
assert by_name["Цены"].qualified_name == "Справочник.Товары.Цены"
|
||||
assert by_name["ВидЦены"].qualified_name == "Справочник.Товары.Цены.ВидЦены"
|
||||
assert by_name["ФормаЭлемента"].qualified_name == "Справочник.Товары.ФормаЭлемента"
|
||||
|
||||
|
||||
def test_normalize_http_service_keeps_url_templates_and_methods(tmp_path: Path):
|
||||
mdo = tmp_path / "ПубличныйAPI.mdo"
|
||||
mdo.write_text(
|
||||
"""
|
||||
<mdclass:HTTPService xmlns:mdclass="http://g5.1c.ru/v8/dt/metadata/mdclass">
|
||||
<name>ПубличныйAPI</name>
|
||||
<rootURL>api</rootURL>
|
||||
<urlTemplates>
|
||||
<name>Orders</name>
|
||||
<template>/orders/{id}</template>
|
||||
<methods>
|
||||
<httpMethod>GET</httpMethod>
|
||||
<handler>ПолучитьЗаказ</handler>
|
||||
</methods>
|
||||
</urlTemplates>
|
||||
</mdclass:HTTPService>
|
||||
""",
|
||||
encoding="utf-8",
|
||||
)
|
||||
|
||||
normalized = normalize_one_c_project(tmp_path, project_id="http-service")
|
||||
http_group = next(group for group in normalized.configuration.groups if group.name == "HTTP-сервисы")
|
||||
service = http_group.objects[0]
|
||||
|
||||
assert service.qualified_name == "HTTPСервис.ПубличныйAPI"
|
||||
assert service.metadata["rootURL"] == "api"
|
||||
assert service.url_templates[0].name == "Orders"
|
||||
assert service.url_templates[0].attributes["template"] == "/orders/{id}"
|
||||
assert service.url_templates[0].children[0].kind == "METHOD"
|
||||
assert service.url_templates[0].children[0].name == "ПолучитьЗаказ"
|
||||
|
||||
|
||||
def test_normalize_edt_project_keeps_tabular_section_columns_nested(tmp_path: Path):
|
||||
mdo = tmp_path / "ЗаказПокупателя.mdo"
|
||||
mdo.write_text(
|
||||
"""
|
||||
<mdclass:Document xmlns:mdclass="http://g5.1c.ru/v8/dt/metadata/mdclass">
|
||||
<name>ЗаказПокупателя</name>
|
||||
<tabularSections>
|
||||
<name>Товары</name>
|
||||
<attributes>
|
||||
<name>Номенклатура</name>
|
||||
</attributes>
|
||||
<attributes>
|
||||
<name>Количество</name>
|
||||
</attributes>
|
||||
</tabularSections>
|
||||
</mdclass:Document>
|
||||
""",
|
||||
encoding="utf-8",
|
||||
)
|
||||
|
||||
normalized = normalize_one_c_project(tmp_path, project_id="edt-tabular")
|
||||
documents = next(group for group in normalized.configuration.groups if group.name == "Документы")
|
||||
document = documents.objects[0]
|
||||
|
||||
assert document.attributes == []
|
||||
assert document.tabular_sections[0].qualified_name == "Документ.ЗаказПокупателя.Товары"
|
||||
assert [child.name for child in document.tabular_sections[0].children] == ["Номенклатура", "Количество"]
|
||||
assert [child.qualified_name for child in document.tabular_sections[0].children] == [
|
||||
"Документ.ЗаказПокупателя.Товары.Номенклатура",
|
||||
"Документ.ЗаказПокупателя.Товары.Количество",
|
||||
]
|
||||
|
||||
|
||||
def test_normalize_edt_project_preserves_source_path_and_common_object_descriptions(tmp_path: Path):
|
||||
common_form = tmp_path / "ФормаПодбора.mdo"
|
||||
common_form.write_text(
|
||||
"""
|
||||
<mdclass:CommonForm xmlns:mdclass="http://g5.1c.ru/v8/dt/metadata/mdclass">
|
||||
<name>ФормаПодбора</name>
|
||||
<synonym>Форма подбора</synonym>
|
||||
<comment>Используется в подборе товаров</comment>
|
||||
</mdclass:CommonForm>
|
||||
""",
|
||||
encoding="utf-8",
|
||||
)
|
||||
|
||||
normalized = normalize_one_c_project(tmp_path, project_id="edt-common")
|
||||
groups = {group.name: group for group in normalized.configuration.groups}
|
||||
common_forms = groups["Общие формы"].objects
|
||||
|
||||
assert common_forms[0].qualified_name == "ОбщаяФорма.ФормаПодбора"
|
||||
assert common_forms[0].source_path.endswith("ФормаПодбора.mdo")
|
||||
assert common_forms[0].metadata["synonym"] == "Форма подбора"
|
||||
assert common_forms[0].metadata["comment"] == "Используется в подборе товаров"
|
||||
|
||||
|
||||
def test_normalize_edt_project_preserves_localized_descriptions(tmp_path: Path):
|
||||
catalog = tmp_path / "Контрагенты.mdo"
|
||||
catalog.write_text(
|
||||
"""
|
||||
<mdclass:Catalog xmlns:mdclass="http://g5.1c.ru/v8/dt/metadata/mdclass">
|
||||
<name>Контрагенты</name>
|
||||
<synonym>
|
||||
<key>ru</key>
|
||||
<value>Контрагенты</value>
|
||||
</synonym>
|
||||
<comment>
|
||||
<key>ru</key>
|
||||
<value>Описание справочника контрагентов</value>
|
||||
</comment>
|
||||
<attributes>
|
||||
<name>ИНН</name>
|
||||
<synonym>
|
||||
<key>ru</key>
|
||||
<value>ИНН</value>
|
||||
</synonym>
|
||||
<comment>
|
||||
<key>ru</key>
|
||||
<value>Идентификационный номер налогоплательщика</value>
|
||||
</comment>
|
||||
</attributes>
|
||||
</mdclass:Catalog>
|
||||
""",
|
||||
encoding="utf-8",
|
||||
)
|
||||
|
||||
normalized = normalize_one_c_project(tmp_path, project_id="edt-localized")
|
||||
catalogs = next(group for group in normalized.configuration.groups if group.name == "Справочники")
|
||||
metadata_object = catalogs.objects[0]
|
||||
attribute = metadata_object.attributes[0]
|
||||
|
||||
assert metadata_object.metadata["synonym"] == "Контрагенты"
|
||||
assert metadata_object.metadata["synonym_localized"] == {"ru": "Контрагенты"}
|
||||
assert metadata_object.metadata["comment"] == "Описание справочника контрагентов"
|
||||
assert metadata_object.metadata["comment_localized"] == {"ru": "Описание справочника контрагентов"}
|
||||
assert attribute.attributes["synonym"] == "ИНН"
|
||||
assert attribute.attributes["comment"] == "Идентификационный номер налогоплательщика"
|
||||
|
||||
|
||||
def test_normalize_edt_project_attaches_bsl_modules_to_metadata_objects(tmp_path: Path):
|
||||
catalog_dir = tmp_path / "Catalogs" / "Контрагенты"
|
||||
module_dir = catalog_dir / "Ext"
|
||||
module_dir.mkdir(parents=True)
|
||||
(catalog_dir / "Контрагенты.mdo").write_text(
|
||||
"""
|
||||
<mdclass:Catalog xmlns:mdclass="http://g5.1c.ru/v8/dt/metadata/mdclass">
|
||||
<name>Контрагенты</name>
|
||||
</mdclass:Catalog>
|
||||
""",
|
||||
encoding="utf-8",
|
||||
)
|
||||
(module_dir / "ObjectModule.bsl").write_text(
|
||||
"""
|
||||
Процедура ПроверитьКонтрагента() Экспорт
|
||||
КонецПроцедуры
|
||||
""",
|
||||
encoding="utf-8",
|
||||
)
|
||||
(module_dir / "ManagerModule.bsl").write_text(
|
||||
"""
|
||||
Процедура Создать() Экспорт
|
||||
КонецПроцедуры
|
||||
""",
|
||||
encoding="utf-8",
|
||||
)
|
||||
|
||||
normalized = normalize_one_c_project(tmp_path, project_id="edt-modules")
|
||||
catalogs = next(group for group in normalized.configuration.groups if group.name == "Справочники")
|
||||
catalog = catalogs.objects[0]
|
||||
|
||||
assert [module.module_kind for module in catalog.modules] == ["MANAGER_MODULE", "OBJECT_MODULE"]
|
||||
assert all(module.source_path.endswith(".bsl") for module in catalog.modules)
|
||||
assert all(module.attributes["source_hash"] for module in catalog.modules)
|
||||
|
||||
|
||||
def test_normalize_edt_project_attaches_form_modules_to_owner_with_form_name(tmp_path: Path):
|
||||
catalog_dir = tmp_path / "Catalogs" / "Контрагенты"
|
||||
form_dir = catalog_dir / "Forms" / "ФормаЭлемента" / "Ext"
|
||||
form_dir.mkdir(parents=True)
|
||||
(catalog_dir / "Контрагенты.mdo").write_text(
|
||||
"""
|
||||
<mdclass:Catalog xmlns:mdclass="http://g5.1c.ru/v8/dt/metadata/mdclass">
|
||||
<name>Контрагенты</name>
|
||||
<forms>
|
||||
<name>ФормаЭлемента</name>
|
||||
</forms>
|
||||
</mdclass:Catalog>
|
||||
""",
|
||||
encoding="utf-8",
|
||||
)
|
||||
(form_dir / "Module.bsl").write_text(
|
||||
"""
|
||||
Процедура ПриОткрытии()
|
||||
КонецПроцедуры
|
||||
""",
|
||||
encoding="utf-8",
|
||||
)
|
||||
|
||||
normalized = normalize_one_c_project(tmp_path, project_id="edt-form-module")
|
||||
catalog = next(group for group in normalized.configuration.groups if group.name == "Справочники").objects[0]
|
||||
|
||||
assert catalog.modules[0].module_kind == "FORM_MODULE"
|
||||
assert catalog.modules[0].attributes["form_name"] == "ФормаЭлемента"
|
||||
assert catalog.modules[0].qualified_name == "Справочник.Контрагенты.Форма.ФормаЭлемента.Модуль"
|
||||
|
||||
|
||||
def test_normalize_edt_project_attaches_common_form_modules(tmp_path: Path):
|
||||
common_form_dir = tmp_path / "CommonForms" / "ФормаПодбора"
|
||||
module_dir = common_form_dir / "Ext"
|
||||
module_dir.mkdir(parents=True)
|
||||
(common_form_dir / "ФормаПодбора.mdo").write_text(
|
||||
"""
|
||||
<mdclass:CommonForm xmlns:mdclass="http://g5.1c.ru/v8/dt/metadata/mdclass">
|
||||
<name>ФормаПодбора</name>
|
||||
</mdclass:CommonForm>
|
||||
""",
|
||||
encoding="utf-8",
|
||||
)
|
||||
(module_dir / "Module.bsl").write_text(
|
||||
"""
|
||||
Процедура ПриСозданииНаСервере() Экспорт
|
||||
КонецПроцедуры
|
||||
""",
|
||||
encoding="utf-8",
|
||||
)
|
||||
|
||||
normalized = normalize_one_c_project(tmp_path, project_id="edt-common-form-module")
|
||||
common_forms = next(group for group in normalized.configuration.groups if group.name == "Общие формы")
|
||||
common_form = common_forms.objects[0]
|
||||
|
||||
assert common_form.qualified_name == "ОбщаяФорма.ФормаПодбора"
|
||||
assert len(common_form.modules) == 1
|
||||
assert common_form.modules[0].module_kind == "MODULE"
|
||||
assert common_form.modules[0].source_path.endswith("Module.bsl")
|
||||
|
||||
|
||||
def test_parse_register_dimensions_and_resources_preserves_attribute_roles(tmp_path: Path):
|
||||
mdo = tmp_path / "ОстаткиТоваров.mdo"
|
||||
mdo.write_text(
|
||||
"""
|
||||
<mdclass:AccumulationRegister xmlns:mdclass="http://g5.1c.ru/v8/dt/metadata/mdclass">
|
||||
<name>ОстаткиТоваров</name>
|
||||
<dimensions>
|
||||
<name>Номенклатура</name>
|
||||
</dimensions>
|
||||
<resources>
|
||||
<name>Количество</name>
|
||||
</resources>
|
||||
<attributes>
|
||||
<name>Комментарий</name>
|
||||
</attributes>
|
||||
</mdclass:AccumulationRegister>
|
||||
""",
|
||||
encoding="utf-8",
|
||||
)
|
||||
|
||||
objects = parse_one_c_xml_file(mdo)
|
||||
by_name = {item.name: item for item in objects}
|
||||
|
||||
assert by_name["ОстаткиТоваров"].object_kind == "ACCUMULATION_REGISTER"
|
||||
assert by_name["ОстаткиТоваров"].qualified_name == "РегистрНакопления.ОстаткиТоваров"
|
||||
assert by_name["Номенклатура"].attributes["attribute_role"] == "DIMENSION"
|
||||
assert by_name["Количество"].attributes["attribute_role"] == "RESOURCE"
|
||||
assert by_name["Комментарий"].attributes["attribute_role"] == "REQUISITE"
|
||||
|
||||
|
||||
def test_normalize_edt_project_preserves_specific_register_kinds(tmp_path: Path):
|
||||
for file_name, tag, name in (
|
||||
("Цены.mdo", "InformationRegister", "Цены"),
|
||||
("ОстаткиТоваров.mdo", "AccumulationRegister", "ОстаткиТоваров"),
|
||||
("Хозрасчетный.mdo", "AccountingRegister", "Хозрасчетный"),
|
||||
("Начисления.mdo", "CalculationRegister", "Начисления"),
|
||||
):
|
||||
(tmp_path / file_name).write_text(
|
||||
f"""
|
||||
<mdclass:{tag} xmlns:mdclass="http://g5.1c.ru/v8/dt/metadata/mdclass">
|
||||
<name>{name}</name>
|
||||
</mdclass:{tag}>
|
||||
""",
|
||||
encoding="utf-8",
|
||||
)
|
||||
|
||||
normalized = normalize_one_c_project(tmp_path, project_id="edt-register-kinds")
|
||||
groups = {group.name: group for group in normalized.configuration.groups}
|
||||
|
||||
assert groups["Регистры сведений"].objects[0].object_kind == "INFORMATION_REGISTER"
|
||||
assert groups["Регистры накопления"].objects[0].qualified_name == "РегистрНакопления.ОстаткиТоваров"
|
||||
assert groups["Регистры бухгалтерии"].objects[0].object_kind == "ACCOUNTING_REGISTER"
|
||||
assert groups["Регистры расчета"].objects[0].object_kind == "CALCULATION_REGISTER"
|
||||
|
||||
|
||||
def test_parse_one_c_xml_file_extracts_role_rights(tmp_path: Path):
|
||||
xml = tmp_path / "roles.xml"
|
||||
xml.write_text(
|
||||
"""
|
||||
<Configuration>
|
||||
<Role name="Менеджер" qualifiedName="Роль.Менеджер">
|
||||
<Right object="Документ.ЗаказПокупателя" read="true" write="true" post="true" />
|
||||
</Role>
|
||||
</Configuration>
|
||||
""",
|
||||
encoding="utf-8",
|
||||
)
|
||||
|
||||
objects = parse_one_c_xml_file(xml)
|
||||
|
||||
assert [item.object_kind for item in objects] == ["ROLE", "RIGHT"]
|
||||
assert objects[1].name == "Документ.ЗаказПокупателя"
|
||||
assert objects[1].attributes["role"] == "Роль.Менеджер"
|
||||
assert objects[1].attributes["post"] == "true"
|
||||
|
||||
|
||||
def test_normalized_project_attaches_role_rights(tmp_path: Path):
|
||||
xml = tmp_path / "roles.xml"
|
||||
xml.write_text(
|
||||
"""
|
||||
<Configuration>
|
||||
<Role name="Менеджер" qualifiedName="Роль.Менеджер">
|
||||
<Right object="Документ.ЗаказПокупателя" read="true" write="true" />
|
||||
</Role>
|
||||
</Configuration>
|
||||
""",
|
||||
encoding="utf-8",
|
||||
)
|
||||
|
||||
normalized = build_normalized_project(parse_one_c_xml_file(xml), project_id="roles", source_path=str(tmp_path))
|
||||
roles_group = next(group for group in normalized.configuration.groups if group.name == "Роли")
|
||||
role = roles_group.objects[0]
|
||||
|
||||
assert role.name == "Менеджер"
|
||||
assert role.rights[0].target == "Документ.ЗаказПокупателя"
|
||||
assert role.rights[0].permissions["write"] == "true"
|
||||
|
||||
|
||||
def test_parse_one_c_xml_file_extracts_child_element_command_action_and_role_right(tmp_path: Path):
|
||||
xml = tmp_path / "metadata.xml"
|
||||
xml.write_text(
|
||||
"""
|
||||
<Configuration>
|
||||
<Document>
|
||||
<Name>ЗаказПокупателя</Name>
|
||||
<QualifiedName>Документ.ЗаказПокупателя</QualifiedName>
|
||||
<Form>
|
||||
<Name>ФормаДокумента</Name>
|
||||
<Command>
|
||||
<Name>Провести</Name>
|
||||
<Action>ПровестиКоманда</Action>
|
||||
</Command>
|
||||
</Form>
|
||||
</Document>
|
||||
<Role>
|
||||
<Name>Менеджер</Name>
|
||||
<Right read="true">
|
||||
<Object>Документ.ЗаказПокупателя</Object>
|
||||
</Right>
|
||||
</Role>
|
||||
</Configuration>
|
||||
""",
|
||||
encoding="utf-8",
|
||||
)
|
||||
|
||||
objects = parse_one_c_xml_file(xml)
|
||||
by_kind = {item.object_kind: item for item in objects}
|
||||
command = next(item for item in objects if item.object_kind == "COMMAND")
|
||||
right = next(item for item in objects if item.object_kind == "RIGHT")
|
||||
|
||||
assert by_kind["FORM"].qualified_name == "Документ.ЗаказПокупателя.ФормаДокумента"
|
||||
assert command.attributes["Action"] == "ПровестиКоманда"
|
||||
assert right.name == "Документ.ЗаказПокупателя"
|
||||
assert right.attributes["role"] == "Роль.Менеджер"
|
||||
|
||||
|
||||
def test_normalized_project_groups_extended_1c_objects(tmp_path: Path):
|
||||
xml = tmp_path / "extended.xml"
|
||||
xml.write_text(
|
||||
"""
|
||||
<Configuration>
|
||||
<Subsystem name="Продажи" qualifiedName="Подсистема.Продажи" />
|
||||
<HTTPService name="ПубличныйAPI" qualifiedName="HTTPСервис.ПубличныйAPI" />
|
||||
<XDTOPackage name="ИнтеграцияCRM" qualifiedName="XDTO.ИнтеграцияCRM" />
|
||||
<Document name="ЗаказПокупателя" qualifiedName="Документ.ЗаказПокупателя">
|
||||
<Layout name="ПечатнаяФорма" qualifiedName="Документ.ЗаказПокупателя.ПечатнаяФорма" />
|
||||
<Movement name="Остатки" qualifiedName="Документ.ЗаказПокупателя.Движения.Остатки" />
|
||||
</Document>
|
||||
<Extension name="CRM" version="1.0" />
|
||||
</Configuration>
|
||||
""",
|
||||
encoding="utf-8",
|
||||
)
|
||||
|
||||
objects = parse_one_c_xml_file(xml)
|
||||
normalized = build_normalized_project(objects, project_id="extended", source_path=str(tmp_path))
|
||||
groups = {group.name: group for group in normalized.configuration.groups}
|
||||
document = next(item for item in groups["Документы"].objects if item.name == "ЗаказПокупателя")
|
||||
|
||||
assert "Подсистемы" in groups
|
||||
assert "HTTP-сервисы" in groups
|
||||
assert "XDTO-пакеты" in groups
|
||||
assert document.layouts[0].name == "ПечатнаяФорма"
|
||||
assert document.movements[0].name == "Остатки"
|
||||
assert normalized.configuration.extensions[0].name == "CRM"
|
||||
|
||||
|
||||
def test_normalize_one_c_project_skips_unreadable_or_invalid_metadata(tmp_path: Path):
|
||||
(tmp_path / "valid.xml").write_text(
|
||||
"""
|
||||
<Configuration>
|
||||
<Catalog name="Контрагенты" qualifiedName="Справочник.Контрагенты" />
|
||||
</Configuration>
|
||||
""",
|
||||
encoding="utf-8",
|
||||
)
|
||||
(tmp_path / "broken.xml").write_text("<Configuration><Catalog>", encoding="utf-8")
|
||||
|
||||
normalized = normalize_one_c_project(tmp_path, project_id="skip-invalid")
|
||||
catalogs = next(group for group in normalized.configuration.groups if group.name == "Справочники")
|
||||
|
||||
assert catalogs.objects[0].qualified_name == "Справочник.Контрагенты"
|
||||
|
||||
|
||||
def test_configuration_extension_has_own_metadata_tree_structure(tmp_path: Path):
|
||||
xml = tmp_path / "extension.mdo"
|
||||
xml.write_text(
|
||||
"""
|
||||
<mdclass:ConfigurationExtension xmlns:mdclass="http://g5.1c.ru/v8/dt/metadata/mdclass/extension">
|
||||
<name>CRM</name>
|
||||
<version>1.0</version>
|
||||
<catalogs>
|
||||
<name>КонтрагентыCRM</name>
|
||||
<attributes>
|
||||
<name>ВнешнийКод</name>
|
||||
</attributes>
|
||||
</catalogs>
|
||||
<commonModules>
|
||||
<name>CRMСервер</name>
|
||||
</commonModules>
|
||||
</mdclass:ConfigurationExtension>
|
||||
""",
|
||||
encoding="utf-8",
|
||||
)
|
||||
|
||||
objects = parse_one_c_xml_file(xml)
|
||||
normalized = build_normalized_project(objects, project_id="extension-structure", source_path=str(tmp_path))
|
||||
|
||||
assert normalized.configuration.groups == []
|
||||
extension = normalized.configuration.extensions[0]
|
||||
assert extension.name == "CRM"
|
||||
assert extension.version == "1.0"
|
||||
extension_groups = {group.name: group for group in extension.groups}
|
||||
assert extension_groups["Справочники"].objects[0].name == "КонтрагентыCRM"
|
||||
assert extension_groups["Справочники"].objects[0].attributes[0].name == "ВнешнийКод"
|
||||
assert extension_groups["Общие модули"].objects[0].name == "CRMСервер"
|
||||
|
||||
|
||||
def test_report_metadata_parts_include_dcs_variants_settings_and_tabular_documents(tmp_path: Path):
|
||||
xml = tmp_path / "report.mdo"
|
||||
xml.write_text(
|
||||
"""
|
||||
<mdclass:Report xmlns:mdclass="http://g5.1c.ru/v8/dt/metadata/mdclass">
|
||||
<name>АнализПродаж</name>
|
||||
<attributes>
|
||||
<name>Период</name>
|
||||
</attributes>
|
||||
<tabularSections>
|
||||
<name>Показатели</name>
|
||||
</tabularSections>
|
||||
<forms>
|
||||
<name>ФормаОтчета</name>
|
||||
</forms>
|
||||
<templates>
|
||||
<name>ПечатнаяФорма</name>
|
||||
</templates>
|
||||
<tabularDocuments>
|
||||
<name>ТабличныйДокумент</name>
|
||||
</tabularDocuments>
|
||||
<mainDataCompositionSchema>
|
||||
<name>ОсновнаяСхемаКомпоновкиДанных</name>
|
||||
</mainDataCompositionSchema>
|
||||
<reportVariants>
|
||||
<name>Основной</name>
|
||||
</reportVariants>
|
||||
<settings>
|
||||
<name>НастройкиПоУмолчанию</name>
|
||||
</settings>
|
||||
</mdclass:Report>
|
||||
""",
|
||||
encoding="utf-8",
|
||||
)
|
||||
|
||||
objects = parse_one_c_xml_file(xml)
|
||||
normalized = build_normalized_project(objects, project_id="report-parts", source_path=str(tmp_path))
|
||||
reports = next(group for group in normalized.configuration.groups if group.name == "Отчеты")
|
||||
report = reports.objects[0]
|
||||
|
||||
assert report.qualified_name == "Отчет.АнализПродаж"
|
||||
assert report.attributes[0].name == "Период"
|
||||
assert report.tabular_sections[0].name == "Показатели"
|
||||
assert report.forms[0].name == "ФормаОтчета"
|
||||
assert report.layouts[0].name == "ПечатнаяФорма"
|
||||
assert report.tabular_documents[0].name == "ТабличныйДокумент"
|
||||
assert report.data_composition_schemas[0].name == "ОсновнаяСхемаКомпоновкиДанных"
|
||||
assert report.report_variants[0].name == "Основной"
|
||||
assert report.report_settings[0].name == "НастройкиПоУмолчанию"
|
||||
|
||||
|
||||
def test_metadata_catalog_describes_core_1c_tree_branches():
|
||||
assert "Общие модули" in COMMON_BRANCH_CHILDREN
|
||||
assert "HTTP-сервисы" in COMMON_BRANCH_CHILDREN
|
||||
|
||||
document = METADATA_TYPE_BY_CODE["DOCUMENT"]
|
||||
assert document.tree_branch == "Документы"
|
||||
assert "Реквизиты" in document.child_groups
|
||||
assert "Табличные части" in document.child_groups
|
||||
assert "Движения" in document.child_groups
|
||||
assert document.module_kinds == ("Модуль объекта", "Модуль менеджера")
|
||||
|
||||
register = METADATA_TYPE_BY_CODE["ACCUMULATION_REGISTER"]
|
||||
assert register.tree_branch == "Регистры накопления"
|
||||
assert "Измерения" in register.child_groups
|
||||
assert "Ресурсы" in register.child_groups
|
||||
|
||||
common_form = METADATA_TYPE_BY_CODE["COMMON_FORM"]
|
||||
assert common_form.tree_branch == "Общие формы"
|
||||
assert "Модуль формы" in common_form.child_groups
|
||||
|
||||
report = METADATA_TYPE_BY_CODE["REPORT"]
|
||||
assert "СКД" in report.child_groups
|
||||
assert "Табличные документы" in report.child_groups
|
||||
assert "Варианты отчета" in report.child_groups
|
||||
assert "Настройки" in report.child_groups
|
||||
|
||||
assert METADATA_TYPE_BY_BRANCH["XDTO-пакеты"].code == "XDTO_PACKAGE"
|
||||
assert METADATA_TYPE_BY_BRANCH["Сервисы интеграции"].code == "INTEGRATION_SERVICE"
|
||||
Reference in New Issue
Block a user